KITAQ SERIES • 參考版
KITAQGB 函式庫
建立遊戲的工具
原始碼快照:2026 年 9 月 14 日 · 繁體中文版:2026 年 9 月 14 日
使用原生編譯器呼叫程式庫
lib/ 包含編入遊戲機 ROM 的 C 標頭與原始碼。PC 編譯器與輔助工具使用 Rust;遊戲原始碼、目標平台程式庫與 API 仍使用 C。提供的 SOURCE_MANIFEST.json 與 LIBRARY_MERGE.json 記錄程式庫原始碼的選擇。
kitaqgb · Rust 原生編譯器與輔助工具 · GitHub Actions
Windows、Linux、macOS ARM 和 macOS Intel 的原生建置及執行驗證均成功。KITAQGB 在每個環境通過 48 項測試與 395 項輔助工具檢查;KITAQFC 通過 55 項測試與 401 項檢查,也驗證了 Rust 1.85。PUBLIC_DISTRIBUTION.json 記錄已配置程式的雜湊與驗證來源。公開 GitHub Actions 會獨立建置及驗證這些原始碼。
保存的參考輸出用於檢查 ROM 位元組、診斷與輔助工具格式。先前的 C# 模擬器驗證保留為對應原始碼指紋的歷史紀錄,並不自動證明所有 Rust API、實體硬體或完整的 FDS BIOS 遊戲啟動。原始 PNG 轉換腳本無法取得,因此依規格重新實作,不能宣稱與原腳本位元組一致。
完整範例程式
程式、共用標頭、提供的 ascii.c 與轉換素材均已附上。m_ 開頭的名稱是本手冊的輔助函式。請搭配預期結果和驗證紀錄閱讀建置命令,並從各並列儲存庫的上層目錄執行。
顯示提供的字元集 gb_font.c
目的: 了解提供的原創字型包含哪些字母、數字與標點符號,以及如何繪製。
運作方式: m_init 準備顯示與字型。m_text 繪製各列,m_put 則以字元碼 34 繪製雙引號。
操作方式與預期結果: 請確認有 26 個大寫字母、26 個小寫字母、10 個數字及 30 個標點符號,並檢查每個字形是否清晰可辨。無須輸入操作。

.\kitaqgb\kitaqgb.exe kitaq-docs/samples/gb_font.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_font.gb --profile=dev --rst-disable --stack-bank=fixed// Display the letters, digits and punctuation from the supplied ascii.c font.
// Expected: Uppercase, lowercase, numbers and all 30 supplied punctuation glyphs
#include "gb_common.h"
// Lay out every supplied character category, yielding between rows. The final
// m_put uses character code 34 to display the double quote separately.
void main() {
m_init();
m_text(2,3,"FONT");
m_text(2,5,"ABCDEFGHIJKLMNOP"); m_wait();
m_text(2,6,"QRSTUVWXYZ"); m_wait();
m_text(2,8,"0123456789"); m_wait();
m_text(2,10,"abcdefghijklmnop"); m_wait();
m_text(2,11,"qrstuvwxyz"); m_wait();
m_text(2,13,"!#$%&'()*+,-./"); m_wait();
m_text(2,14,":;<=>?@[]^_`{}~"); m_wait();
m_put(16,13,34); m_wait();
while (1) { m_wait(); }
}第一次顯示文字 gb_hello.c
目的: 學習啟動 ROM 並在背景繪製文字與數字的基本步驟。
運作方式: m_init 後,m_text 繪製問候文字,m_number 格式化 42。最後的迴圈等待影格並保持畫面顯示。
操作方式與預期結果: 畫面顯示 HELLO WORLD 與 042。前面的零來自三位數十進位格式。

.\kitaqgb\kitaqgb.exe kitaq-docs/samples/gb_hello.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_hello.gb --profile=dev --rst-disable --stack-bank=fixed// Display a first message on screen.
// Expected: HELLO WORLD and 042
#include "gb_common.h"
// Initialize the display/font, write HELLO WORLD and a three-digit 042,
// then wait for frames so the result remains visible.
void main() {
m_init();
m_text(2,3,"HELLO");
m_text(2,5,"HELLO WORLD");
m_number(42);
while (1) { m_wait(); }
}使用較寬型別的中間值運算 gb_arithmetic.c
目的: 學習如何保留超出八位元範圍的中間結果。
運作方式: (u16)200 + 100 的結果為 300。程式先除以 10,再轉為 u8 顯示。請注意,擴大型別的轉型發生在加法之前。
操作方式與預期結果: 030 表示計算結果 30。

.\kitaqgb\kitaqgb.exe kitaq-docs/samples/gb_arithmetic.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_arithmetic.gb --profile=dev --rst-disable --stack-bank=fixed// Variables, arithmetic and type conversion.
// Expected: 030
#include "gb_common.h"
// Widen before adding 200 + 100, divide the 16-bit sum, and display 30.
// The cast demonstrates avoiding an 8-bit intermediate result.
void main() {
m_init();
m_text(2,3,"ARITHMETIC");
u16 sum;
sum = (u16)200 + 100;
m_number((u8)(sum / 10));
while (1) { m_wait(); }
}分支與迴圈 gb_control.c
目的: 在簡單計算中試用 for、continue、while、do/while 與 switch。
運作方式: 將 0 到 7 相加但略過 3,得到 25。while 迴圈推進至 30,do/while 推進至 32,switch 再選擇 case 32 並指定 42。
操作方式與預期結果: 042 是這些迴圈與分支的最終結果。

.\kitaqgb\kitaqgb.exe kitaq-docs/samples/gb_control.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_control.gb --profile=dev --rst-disable --stack-bank=fixed// Conditional branches and loops.
// Expected: 042
#include "gb_common.h"
// Exercise loop control and a final branch, then display the selected value 42.
void main() {
m_init();
m_text(2,3,"CONTROL");
u8 i; u8 sum; sum=0;
for (i=0;i<8;i++) { if (i==3) continue; sum=(u8)(sum+i); }
while (sum<30) { sum++; }
do { sum++; } while (sum<32);
switch (sum) { case 32: sum=42; break; default: sum=0; break; }
m_number(sum);
while (1) { m_wait(); }
}函式、陣列、結構與指標 gb_aggregate.c
目的: 學習如何將值分組,並透過函式與指標存取。
運作方式: 程式複製包含 (10,20) 的 Point,再透過指標將 1 至 4 寫入陣列。它將函式結果 30 加上陣列值 1、2、4 與常數 5。
操作方式與預期結果: 總和顯示為 042。請追蹤結構複製、ptr[i] 寫入與函式傳回值。
![函式、陣列、結構與指標:總和顯示為 042。請追蹤結構複製、ptr[i] 寫入與函式傳回值。](../verification/gb_aggregate.png)
.\kitaqgb\kitaqgb.exe kitaq-docs/samples/gb_aggregate.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_aggregate.gb --profile=dev --rst-disable --stack-bank=fixed// Functions, arrays, structures and pointers.
// Expected: 042
#include "gb_common.h"
typedef struct { u8 x; u8 y; } Point;
// Add two byte values and explicitly narrow the returned result to u8.
u8 add(u8 a,u8 b) { return (u8)(a+b); }
// Copy a structure, fill an array through a pointer, and combine selected values
// through add() to produce 42. Keep the final screen visible in the idle loop.
void main() {
m_init();
m_text(2,3,"AGGREGATE");
Point a; Point b; u8 i; u8 data[4]; u8* ptr;
a.x=10; a.y=20; b=a; ptr=data;
for(i=0;i<4;i++) ptr[i]=(u8)(i+1);
m_number((u8)(add(b.x,b.y)+ptr[0]+ptr[1]+ptr[3]+5));
while (1) { m_wait(); }
}位元旗標與緩衝區複製 gb_bits_memory.c
目的: 將旗標打包成一個位元組,並將緩衝區複製至另一個儲存區。
運作方式: __memset 清除四個位元組。程式設定位元 3、切換位元 1,再以 __memcpy 複製全部四個位元組。
操作方式與預期結果: 目的緩衝區的第一個位元組顯示為 010,其中位元 3 貢獻 8,位元 1 貢獻 2。

.\kitaqgb\kitaqgb.exe kitaq-docs/samples/gb_bits_memory.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_bits_memory.gb --profile=dev --rst-disable --stack-bank=fixed// Bit operations and memory copying.
// Expected: 010
#include "gb_common.h"
void __memset(void* dst,u8 value,u16 len);
void __memcpy(void* dst,const void* src,u16 len);
void __bit_set(u8* base,u16 bit);
void __bit_toggle(u8* base,u16 bit);
// Clear the source bytes, set bits 3 and 1, copy the buffer, and display 8 + 2 = 10.
void main() {
m_init();
m_text(2,3,"BITS MEMORY");
u8 data[4]; u8 copy[4];
__memset(data,0,4); __bit_set(data,3); __bit_toggle(data,1);
__memcpy(copy,data,4); m_number(copy[0]);
while (1) { m_wait(); }
}計算按鈕新按下的次數 gb_input.c
目的: 區分按鈕剛按下與持續按住的狀態。
運作方式: 每個影格都會呼叫 input_update。只有 input_pressed(BTN_A) 為真時,計數器才會增加。
操作方式與預期結果: 初始值為 000。按 A 後變成 001,持續按住不會累加。放開後再按一次便變成 002。此位元組計數器會從 255 回繞至 000。

.\kitaqgb\kitaqgb.exe kitaqgb/lib/input.c kitaq-docs/samples/gb_input.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_input.gb --profile=dev --rst-disable --stack-bank=fixed// Distinguish a new button press from a held button.
// Expected: 000 initially; A increments once per press
#include "gb_common.h"
#include "input.h"
u8 manual_count;
// Sample buttons once per frame and increment only on a new A press.
// Holding A does not repeatedly increment; the byte-sized counter wraps after 255.
void main() {
m_init();
m_text(2,3,"INPUT");
input_init();
m_number(0);
while (1) { m_wait(); input_update(); if(input_pressed(BTN_A)) { manual_count++; m_number(manual_count); } }
}Q8.8 定點數相乘 gb_fixed.c
目的: 學習將整數轉為 Q8.8、相乘,再轉回整數。
運作方式: fix_from_int 將 3、4 轉成 Q8.8,fix_mul 將兩者相乘,fix_to_int 再將乘積轉回整數。
操作方式與預期結果: 012 表示 3 × 4 = 12,是轉換後的整數,不是內部放大 256 倍的值。

.\kitaqgb\kitaqgb.exe kitaqgb/lib/fixed.c kitaq-docs/samples/gb_fixed.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_fixed.gb --profile=dev --rst-disable --stack-bank=fixed// Calculate with signed Q8.8 fixed-point values.
// Expected: 012
#include "gb_common.h"
#include "fixed.h"
// Convert 3 and 4 to Q8.8, multiply them, convert the result back to an
// integer, and display 12.
void main() {
m_init();
m_text(2,3,"FIXED");
fix8 a; fix8 b; a=fix_from_int(3); b=fix_from_int(4);
m_number((u8)fix_to_int(fix_mul(a,b)));
while (1) { m_wait(); }
}從固定物件池配置 gb_entity.c
目的: 從固定的一組槽位建立物件,無須動態配置記憶體。
運作方式: entity_init 重設物件池。entity_create 在 (20,30) 建立型別 1;程式先檢查失敗 ID 0xFF,再將 vx 設為 2。
操作方式與預期結果: 001 是啟用中的物件數,不是 ID 或座標。此範例不更新或繪製物件,因此不會出現移動角色。

.\kitaqgb\kitaqgb.exe kitaqgb/lib/entity.c kitaq-docs/samples/gb_entity.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_entity.gb --profile=dev --rst-disable --stack-bank=fixed// Allocate an entity from a fixed-capacity object pool.
// Expected: 001
#include "gb_common.h"
#include "entity.h"
// Create one entity and check the 0xFF allocation-failure sentinel before
// accessing its velocity. Display the pool occupancy, not the entity ID.
void main() {
m_init();
m_text(2,3,"ENTITY");
u8 id; entity_init(); id=entity_create(1,20,30);
if(id!=0xFF) entity_get(id)->vx=2; m_number(entity_count_active());
while (1) { m_wait(); }
}將診斷值記錄至 RAM gb_debug.c
目的: 將具名遊戲值保存在診斷緩衝區,與畫面顯示分開處理。
運作方式: 程式初始化除錯功能,將影格標記設為 1,並以 HP 為名稱記錄值 42。
操作方式與預期結果: 001 是追蹤項目數。HP=42 存於診斷緩衝區,僅靠畫面無法顯示或驗證該內容。

.\kitaqgb\kitaqgb.exe kitaqgb/lib/debug.c kitaq-docs/samples/gb_debug.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_debug.gb --profile=dev --rst-disable --stack-bank=fixed// Record diagnostic values in the debug trace.
// Expected: 001; trace log contains HP=42
#include "gb_common.h"
#include "debug.h"
// Record HP = 42 with frame tag 1 and display the number of trace entries.
// The trace buffer contains the value; the screen displays the count, not HP.
void main() {
m_init();
m_text(2,3,"DEBUG");
debug_init(); debug_set_frame(1); debug_trace_u8("HP",42);
m_number(debug_get_trace_count());
while (1) { m_wait(); }
}儲存位置歷程 gb_chain.c
目的: 學習如何將位置軌跡儲存在環形緩衝區中。
運作方式: chain_init 掛接可容納四個點的陣列,接著 chain_push_head 記錄 (20,30)。
操作方式與預期結果: 042 是固定完成標記,不是座標或數量。請檢查 trail 與 points 以確認儲存的歷史。此程式不繪製跟隨的身體。

.\kitaqgb\kitaqgb.exe kitaqgb/lib/chain.c kitaq-docs/samples/gb_chain.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_chain.gb --profile=dev --rst-disable --stack-bank=fixed// Store a position history in a ring buffer.
// Expected: 042; history contains (20,30)
#include "gb_common.h"
#include "chain.h"
Chain trail; ChainPoint points[4];
// Attach four history slots and record one point. The displayed 42 is a fixed
// completion marker; inspect the chain to verify the stored (20,30) point.
void main() {
m_init();
m_text(2,3,"CHAIN");
chain_init(&trail,points,4); chain_push_head(&trail,20,30);
m_number(42);
while (1) { m_wait(); }
}讀取函式庫影格計數器 gb_system.c
目的: 觀察以影格計數的等待如何影響函式庫影格計數器。
運作方式: system_init 後,程式呼叫兩次 system_wait_vblank,再顯示 system_get_frame8。
操作方式與預期結果: 結果為 002。閒置迴圈使用手冊輔助函式 m_wait,因此顯示值不會持續增加。

.\kitaqgb\kitaqgb.exe kitaqgb/lib/system.c kitaq-docs/samples/gb_system.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_system.gb --profile=dev --rst-disable --stack-bank=fixed// Count completed frame waits.
// Expected: 002
#include "gb_common.h"
#include "system.h"
// Reset the library frame count, perform two counted waits, and display 2.
// Subsequent m_wait calls leave that library counter unchanged.
void main() {
m_init();
m_text(2,3,"SYSTEM");
system_init(); system_wait_vblank(); system_wait_vblank();
m_number(system_get_frame8());
while (1) { m_wait(); }
}選取目前場景 ID gb_scene.c
目的: 學習如何選取 ID,以區分標題畫面、遊戲進行等場景。
運作方式: 程式登錄兩個以零初始化的 SceneDef 項目,再以 scene_change 選取 ID 1。
操作方式與預期結果: 001 是 scene_get_current 傳回的目前 ID。此範例未註冊場景回呼或轉場繪製。

.\kitaqgb\kitaqgb.exe kitaqgb/lib/scene.c kitaq-docs/samples/gb_scene.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_scene.gb --profile=dev --rst-disable --stack-bank=fixed// Switch the current scene ID.
// Expected: 001; no callbacks registered
#include "gb_common.h"
#include "scene.h"
SceneDef manual_scenes[2];
// Register two zero-initialized scene entries, select ID 1 and display it.
// No callbacks are registered in this example.
void main() {
m_init();
m_text(2,3,"SCENE");
scene_init(manual_scenes,2); scene_change(1);
m_number(scene_get_current());
while (1) { m_wait(); }
}將世界座標轉換為畫面座標 gb_camera.c
目的: 從世界位置減去攝影機位置,求得畫面位置。
運作方式: Camera_Set 接收 Q8.8 值 2560,也就是 X=10 像素。接著 Camera_WorldToScreenX 轉換世界座標 X=52。
操作方式與預期結果: 052 減去 010 得到畫面上的 042。這是座標計算,不會捲動背景。

.\kitaqgb\kitaqgb.exe kitaqgb/lib/scroll.c kitaqgb/lib/camera.c kitaq-docs/samples/gb_camera.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_camera.gb --profile=dev --rst-disable --stack-bank=fixed// Convert world coordinates to screen coordinates.
// Expected: 042: world x=52 minus camera x=10
#include "gb_common.h"
#include "camera.h"
Camera8_8 cam;
// Set the camera X coordinate to 10 pixels in Q8.8 (10 * 256), then subtract
// it from world X = 52 to display screen X = 42.
void main() {
m_init();
m_text(2,3,"CAMERA");
Camera_Init(&cam); Camera_Set(&cam,2560,0);
m_number((u8)Camera_WorldToScreenX(&cam,52));
while (1) { m_wait(); }
}將 RLE 資料解壓縮至 RAM gb_rle.c
目的: 嘗試以次數與數值,精簡表示重複的位元組。
運作方式: 壓縮位元組 {3,42,0} 代表重複三次 42,再以零次數結束標記收尾。rle_decode 寫入三位元組目的緩衝區。
操作方式與預期結果: 最後一個位元組 out[2] 顯示為 042。解壓縮後的三個位元組應全部為 42。
![將 RLE 資料解壓縮至 RAM:最後一個位元組 out[2] 顯示為 042。解壓縮後的三個位元組應全部為 42。](../verification/gb_rle.png)
.\kitaqgb\kitaqgb.exe kitaqgb/lib/rle.c kitaq-docs/samples/gb_rle.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_rle.gb --profile=dev --rst-disable --stack-bank=fixed// Decode run-length encoded data.
// Expected: 042; three bytes each equal to 42
#include "gb_common.h"
#include "rpg.h"
__prg_rom u8 packed[] = {3,42,0};
// Decode count/value pair (3,42), terminated by a zero count, into a
// three-byte buffer and display the final decoded byte.
void main() {
m_init();
m_text(2,3,"RLE");
u8 out[3]; rle_decode(out,packed); m_number(out[2]);
while (1) { m_wait(); }
}讀寫棋盤格子 gb_board.c
目的: 了解棋盤遊戲的格子座標如何對應到儲存位置。
運作方式: 以 16 位元組陣列儲存 4×4 棋盤。程式清空棋盤、在格子 (2,1) 寫入 42,再讀回同一格。
操作方式與預期結果: 042 是讀回的值。程式不繪製 4×4 棋盤本身。

.\kitaqgb\kitaqgb.exe kitaqgb/lib/slg_board.c kitaq-docs/samples/gb_board.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_board.gb --profile=dev --rst-disable --stack-bank=fixed// Read and write cells in a game board.
// Expected: 042
#include "gb_common.h"
#include "slg.h"
SLGBoard board; u8 cells[16];
// Create a cleared 4-by-4 board in caller-owned storage, write 42 at (2,1),
// and display the value read back from the same cell.
void main() {
m_init();
m_text(2,3,"BOARD");
slg_board_init(&board,4,4,cells); slg_board_clear(&board,0);
slg_board_set(&board,2,1,42); m_number(slg_board_get(&board,2,1));
while (1) { m_wait(); }
}將方盒推進一個物理步驟 gb_physics.c
目的: 初始化世界與方盒剛體,再根據速度更新位置。
運作方式: 剛體從位置 (40,40)、速度 (2,0)、零重力開始。程式呼叫 kq2d_step 一次。
操作方式與預期結果: 042 是算出的 X 座標,此範例以整數像素為單位。不繪製方盒或連續動畫。

.\kitaqgb\kitaqgb.exe kitaqgb/lib/fixed.c kitaqgb/lib/physics2d.c kitaq-docs/samples/gb_physics.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_physics.gb --profile=dev --rst-disable --stack-bank=fixed// Advance a rectangular body through one physics step.
// Expected: 042: integer pixel coordinates
#include "gb_common.h"
#include "physics2d.h"
KQWorld2D world; KQBody2D boxes[1];
// Create one box at X = 40, set horizontal velocity 2 and zero gravity,
// then display its X coordinate after a single physics step.
void main() {
m_init();
m_text(2,3,"PHYSICS");
kq2d_world_init(&world,boxes,1);
kq2d_body_init(&boxes[0],40,40,4,4);
kq2d_body_set_velocity(&boxes[0],2,0);
world.gravity_x=0; world.gravity_y=0;
kq2d_step(&world); m_number((u8)boxes[0].x);
while (1) { m_wait(); }
}處理序列傳輸完成與逾時 gb_link.c
目的: 區分已完成的傳輸與未在等待上限內完成的傳輸。
運作方式: 主端送出 42 並以 Link_WaitByte 等待。完成時顯示收到的位元組;逾時則取消傳輸並顯示零。
操作方式與預期結果: 未連線時若傳輸完成,可能傳回 255。逾時顯示 000;連接對端時顯示收到的位元組。結果不一定是 042。

.\kitaqgb\kitaqgb.exe kitaqgb/lib/link_hwregs_gb.c kitaqgb/lib/link.c kitaq-docs/samples/gb_link.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_link.gb --profile=dev --rst-disable --stack-bank=fixed// Handle serial transfers that do not deliver a byte in time.
// Expected: 255 for disconnected link; 000 if timeout; peer value when connected
#include "gb_common.h"
#include "link.h"
// Start a master transfer of byte 42 and wait with a bounded timeout.
// Display the received byte on completion; cancel and display zero on timeout.
void main() {
m_init();
m_text(2,3,"LINK");
u8 value; Link_InitMaster(); Link_BeginTransfer(42);
if(Link_WaitByte(4,&value)) m_number(value);
else { Link_Cancel(); m_number(0); }
while (1) { m_wait(); }
}指定記憶體庫引數讀取 ROM 資料 gb_bank.c
目的: 學習將 ROM 資料複製到 RAM 所需的引數。
運作方式: far_data_read 使用記憶體庫引數 0 與長度 2,將位元組 7、42 複製到 copied。
操作方式與預期結果: 目的緩衝區的第二個位元組顯示為 042。此範例讀取固定 ROM,不示範不同可切換記憶體庫之間的傳輸。

.\kitaqgb\kitaqgb.exe kitaqgb/lib/bank.c kitaq-docs/samples/gb_bank.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_bank.gb --profile=dev --rst-disable --stack-bank=fixed// Read data using an explicit ROM bank.
// Expected: 042; explicit bank argument 0
#include "gb_common.h"
#include "bank.h"
__prg_rom u8 values[] = {7,42}; u8 copied[2];
// Copy two ROM bytes using bank argument zero and display the second byte.
// This introduces the API; it does not test switching between distinct payload banks.
void main() {
m_init();
m_text(2,3,"BANK");
far_data_read(0,values,copied,2); m_number(copied[1]);
while (1) { m_wait(); }
}依素材 ID 載入資料 gb_asset.c
目的: 登錄素材的位置與長度,再依 ID 取得位元組資料。
運作方式: 素材 0 的型別為 RAW、記憶體庫為 0,包含指向 {7,42} 的指標及長度 2。asset_load_raw 將其複製到兩位元組 RAM 緩衝區。
操作方式與預期結果: 第二個位元組顯示為 042。這示範素材查找與複製,不是影像繪製。

.\kitaqgb\kitaqgb.exe kitaqgb/lib/asset.c kitaq-docs/samples/gb_asset.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_asset.gb --profile=dev --rst-disable --stack-bank=fixed// Load asset bytes into RAM by asset ID.
// Expected: 042
#include "gb_common.h"
#include "asset.h"
AssetDesc table[1]; __prg_rom u8 values[] = {7,42}; u8 copied[2];
// Register a two-byte raw asset, copy it into RAM and display its second byte.
// This example uses bank zero and a destination sized for the complete payload.
void main() {
m_init();
m_text(2,3,"ASSET");
table[0].type=ASSET_TYPE_RAW; table[0].bank=0;
table[0].ptr=values; table[0].len=2;
asset_set_table(0,table,1); asset_load_raw(0,copied,2);
m_number(copied[1]);
while (1) { m_wait(); }
}配置一顆子彈 gb_danmaku.c
目的: 初始化子彈池,並在生成子彈後檢查使用狀況。
運作方式: danmaku_reset 後,程式呼叫 danmaku_spawn(40,40,16,0) 並顯示 dm_count。
操作方式與預期結果: 001 是已配置的子彈數。此處沒有子彈更新迴圈或背景合成器,因此不繪製移動子彈。

.\kitaqgb\kitaqgb.exe kitaqgb/lib/danmaku.c kitaq-docs/samples/gb_danmaku.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_danmaku.gb --profile=dev --rst-disable --stack-bank=fixed// Allocate a bullet and inspect the pool count.
// Expected: 001; numeric pool example, no bullet BG compositor
#include "gb_common.h"
#include "danmaku.h"
// Reset the bullet pool, spawn one bullet and display the active count.
// This numeric example does not install the background bullet compositor.
void main() {
m_init();
m_text(2,3,"DANMAKU");
danmaku_reset(); danmaku_spawn(40,40,16,0);
m_number(dm_count);
while (1) { m_wait(); }
}設定 CGB 背景調色盤 gb_cgb_palette.c
目的: 使用 Game Boy Color 的 RGB 分量選擇背景與文字顏色。
運作方式: 程式在 VBlank 期間關閉 LCD,將調色盤 0 的顏色 0 設為白色 (31,31,31)、顏色 3 設為紫色 (12,0,22),再啟用顯示。
操作方式與預期結果: 以 CGB 模式執行,可看到白底上的紫色文字與 042。DMG 單色輸出無法呈現這些顏色。

.\kitaqgb\kitaqgb.exe kitaqgb/lib/cgb_palette.c kitaq-docs/samples/gb_cgb_palette.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_cgb_palette.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb// Set Game Boy Color palette entries.
// Expected: 042 in purple on white; CGB mode
#include "gb_common.h"
#include "cgb_palette.h"
// Set palette-zero background colors to white and purple, then display 42.
// Run the ROM in CGB mode to observe the color result.
void main() {
m_init();
m_text(2,3,"CGB PALETTE");
// Disable the LCD during VBlank so both palette bytes remain accessible.
m_wait(); M_LCDC = 0;
cgb_bg_rgb(0,0,31,31,31); cgb_bg_rgb(0,3,12,0,22);
M_LCDC = 0x91;
m_number(42);
while (1) { m_wait(); }
}水平捲動背景 gb_scroll.c
目的: 移動觀景位置,無須重新繪製背景內容。
運作方式: 每個影格都會遞增 phase,並將其傳給 Scroll_SetBg。八位元位置值超過 255 後會回繞至 0。
操作方式與預期結果: SCROLL 字樣會向左移動。請觀察它隨時間改變的位置;單張螢幕擷取畫面無法呈現動作。

.\kitaqgb\kitaqgb.exe kitaqgb/lib/scroll.c kitaq-docs/samples/gb_scroll.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_scroll.gb --profile=dev --rst-disable --stack-bank=fixed// Scroll the background horizontally.
// Expected: title moves left as SCX increases
#include "gb_common.h"
#include "scroll.h"
u8 phase;
// Advance an 8-bit horizontal scroll position once per frame, wrapping naturally
// after 255. Background motion demonstrates the changing scroll register.
void main() {
m_init();
m_text(2,3,"SCROLL");
Scroll_SetBg(0,0);
while (1) { m_wait(); phase++; Scroll_SetBg(phase,0); }
}將圖塊更新加入佇列 gb_vram_queue.c
目的: 將繪圖請求與套用該請求的 VRAM 傳輸分開。
運作方式: vram_queue_bg_tile 將圖塊 52 排入圖塊座標 (3,8),vram_flush 再執行傳輸。提供的字型中,圖塊 52 是數字 4。
操作方式與預期結果: 請確認背景圖塊座標 (3,8) 出現一個 4。這是圖塊更新,不是數字計數器。

.\kitaqgb\kitaqgb.exe kitaqgb/lib/vram.c kitaq-docs/samples/gb_vram_queue.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_vram_queue.gb --profile=dev --rst-disable --stack-bank=fixed// Queue a VRAM update and flush it at VBlank.
// Expected: 4 at (3,8)
#include "gb_common.h"
#include "vram.h"
// Queue font tile 52 (the digit 4) at tile coordinate (3,8), then wait for
// VBlank and execute the queued transfer.
void main() {
m_init();
m_text(2,3,"VRAM QUEUE");
vram_init();
vram_queue_bg_tile(3,8,52); vram_flush();
while (1) { m_wait(); }
}透過 OAM DMA 顯示精靈 gb_sprite.c
目的: 獨立於背景配置並顯示精靈。
運作方式: 新初始化的池提供槽位 0。程式選取圖塊 65、設定位置 (70,80)、啟用 OBJ 顯示,並在每個影格傳輸影子 OAM。
操作方式與預期結果: 指定的精靈位置出現靜止字母 A。遊戲中須先檢查配置是否失敗,再使用傳回的 ID。

.\kitaqgb\kitaqgb.exe kitaqgb/lib/sprite.c kitaq-docs/samples/gb_sprite.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_sprite.gb --profile=dev --rst-disable --stack-bank=fixed// Display a sprite through the OAM DMA path.
// Expected: letter A at sprite position
#include "gb_common.h"
#include "sprite.h"
// Allocate the first sprite, choose font tile 65 (A), set its position and
// enable sprite display. Flush shadow OAM after each frame wait.
void main() {
m_init();
m_text(2,3,"SPRITE");
// The freshly reset pool guarantees slot zero for this first allocation.
// In a running game, check the allocation-failure sentinel before using the returned ID.
sprite_init(); sprite_set_tile(sprite_alloc(),65);
sprite_set_pos(0,70,80); M_LCDC=(u8)(M_LCDC|2);
while (1) { m_wait(); sprite_flush_oam_now(); }
}產生可重現的亂數 gb_rng.c
目的: 使用種子重現偽亂數序列。
運作方式: rng_seed(1234) 初始化產生器後,呼叫 rng_range(10) 一次。上限 10 不包含在結果中。
操作方式與預期結果: 畫面顯示 000 至 009 之間的一個值。以相同種子重新啟動同一程式,會重現相同結果;此值不會每個影格改變。

.\kitaqgb\kitaqgb.exe kitaqgb/lib/rng.c kitaq-docs/samples/gb_rng.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_rng.gb --profile=dev --rst-disable --stack-bank=fixed// Generate a repeatable pseudorandom value from a seed.
// Expected: value 000 through 009; same seed repeats
#include "gb_common.h"
#include "rpg.h"
// Seed the generator with 1234 and display one value in [0,10).
// Restarting with the same seed reproduces the sequence.
void main() {
m_init();
m_text(2,3,"RNG");
rng_seed(1234); m_number(rng_range(10));
while (1) { m_wait(); }
}儲存遊戲狀態旗標 gb_flags.c
目的: 使用旗標編號表示布林狀態,例如事件是否完成。
運作方式: 程式先清除旗標 12、再設定它,最後以 flag_get 讀回。
操作方式與預期結果: 001 表示旗標 12 為真。此範例操作 RAM 旗標,關機再開機後不會保留。

.\kitaqgb\kitaqgb.exe kitaqgb/lib/flags.c kitaq-docs/samples/gb_flags.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_flags.gb --profile=dev --rst-disable --stack-bank=fixed// Read and write RAM-backed game-state flags.
// Expected: 001
#include "gb_common.h"
#include "rpg.h"
// Clear and set flag 12, then display its Boolean value. This does not write
// a save file or demonstrate persistence across power cycles.
void main() {
m_init();
m_text(2,3,"FLAGS");
flag_clear(12); flag_set(12); m_number(flag_get(12));
while (1) { m_wait(); }
}將圓形推進一個物理步驟 gb_circle.c
目的: 設定圓形剛體,並根據速度更新位置。
運作方式: 啟用中的圓形半徑為 4、位置為 (40,40)、速度為 (2,0)。重力為零,linear_damping_q8 為 255;kq2dc_step 執行一次。
操作方式與預期結果: 042 是算出的整數 X 座標。此範例不繪製圓形外框或碰撞動畫。

.\kitaqgb\kitaqgb.exe kitaqgb/lib/physics2d_circle.c kitaq-docs/samples/gb_circle.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_circle.gb --profile=dev --rst-disable --stack-bank=fixed// Advance a circular body through one physics step.
// Expected: 042 after one step; this example uses integer pixels
#include "gb_common.h"
#include "physics2d_circle.h"
KQCircleBody2D balls[1]; KQCircleWorld2D world;
// Activate one circle at X = 40 with horizontal velocity 2 and zero gravity.
// Advance one step and display its resulting integer-pixel X coordinate.
void main() {
m_init();
m_text(2,3,"CIRCLE");
kq2dc_world_init(&world,balls,1);
balls[0].active=1; balls[0].x=40; balls[0].y=40;
balls[0].radius=4; balls[0].inv_mass_q8=256;
balls[0].vx=2; balls[0].vy=0;
world.gravity_x=0; world.gravity_y=0; world.linear_damping_q8=255;
kq2dc_step(&world); m_number((u8)balls[0].x);
while (1) { m_wait(); }
}每個影格處理音效 gb_sound.c
目的: 啟動音效串流,並透過規律的影格更新推進播放。
運作方式: Audio_Init 後,Audio_PlaySFX 在通道 ID 1 啟動 tone。主迴圈每影格呼叫一次 Audio_Update。
操作方式與預期結果: 顯示 042 的同時播放短促脈波音效。數字是固定標記,不是音量或播放位置。請透過音訊輸出或錄音判斷聲音。

.\kitaqgb\kitaqgb.exe kitaqgb/lib/audio_hwregs_gb.c kitaqgb/lib/audio.c kitaq-docs/samples/gb_sound.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_sound.gb --profile=dev --rst-disable --stack-bank=fixed// Play a Game Boy pulse-channel sound effect.
// Expected: 042 and a short pulse tone
#include "gb_common.h"
#include "audio.h"
__prg_rom u8 tone[] = { 24,0xF0,24,0xE0,24,0xC0,24,0xA0,24,0x80,24,0x60,0 };
// Start a pulse-channel effect and service Audio_Update once per frame
// so the effect stream advances while 42 remains on screen.
void main() {
m_init();
m_text(2,3,"SOUND");
Audio_Init(); Audio_PlaySFX(tone,1); m_number(42);
while (1) { m_wait(); Audio_Update(); }
}函式庫 API 辭典
共 554 個項目。展開可查看語法、引數、原始碼說明與範例。呼叫片段依賴周邊初始化,不能單獨建置 ROM。引數傳遞範例只說明如何將備妥的值交給 API,不代表已完成裝置層級驗證。
zx0
將 ZX0 相容素材解碼至 RAM 或 VRAM。先在 PC 上用 kitaqgb-zx0.exe 準備素材,執行時只解碼所需資料。--format=auto 比較 raw、RLE 與 ZX0 酬載並選擇最小者;相同大小時依 raw、RLE、ZX0 順序優先。含九位元組標頭的完整容器須不超過 65535 位元組,並依實際 CPU 記憶體庫與 RAM 容量拆分素材。
ZX0 格式與原始壓縮演算法由 Einar Saukas 設計。此處提供的壓縮器與解壓縮器為 KITAQ 的獨立實作,著作權屬於 DAISUKE OBA,以 MIT 授權條款發布。
請在儲存庫根目錄執行下列主機端命令,並使用 tools/zx0/build.ps1 建置工具。
.\kitaqgb-zx0.exe tiles.bin tiles.zx0
.\kitaqgb-zx0.exe tiles.bin tiles.h --header=tiles
.\kitaqgb-zx0.exe map.bin map.kqa --format=auto
.\kitaqgb-zx0.exe tiles.zx0 restored.bin --decompresszx0_decompress
將 ZX0 v2 串流解碼至有界 RAM 區域。相符片段會參照先前已解碼的位元組,因此目的地須可讀寫。適用於 CPU 使用前還要處理的圖塊地圖或關卡表。
語法
u16 zx0_decompress(void* dst, u16 capacity, const void* src, u16 packed_size);參數
dst可寫入目的 RAM 的起點,不可為 null。容量須以位元組表示,不是陣列元素數。
capacity目的地可寫入的位元組數。一般 ZX0 串流至少需要一位元組。空的 raw KQA1 素材可在容量零時成功。
src透過目前記憶體庫映射可讀的壓縮資料起點,不可為 null。
packed_size完整輸入的位元組數。ZX0 串流須包含結束標記,且後面不得有額外位元組。KQA1 容器須包含其九位元組標頭。最大 65535 位元組。
回傳值
成功時傳回解碼位元組數,錯誤時為零。務必同時檢查 zx0_error。
使用條件與限制
引入 zx0.h 並編譯 lib/zx0.c。這些常式使用共用暫存區,不可從中斷重入。輸入與輸出不可重疊、繞回 CPU 位址空間,或跨越目前映射的記憶體庫視窗。函式庫不切換素材記憶體庫。
每次呼叫均更新 zx0_error:0 成功、1 無效引數、2 輸入截斷、3 格式錯誤的串流、4 輸出空間不足、5 顯示啟用。失敗可能留下部分輸出,請勿使用。若多項條件無效,以最先偵測到的條件決定錯誤碼。
接受正向 ZX0 v2 串流。ZX0 v1、反向串流與外部字典不在此介面支援範圍。須掌握主機產生素材的解碼大小,並提供足夠儲存空間。
使用範例
count=zx0_decompress(decoded_map,16,packed_map,packed_map_SIZE);
if(count!=16||zx0_error!=ZX0_OK)failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
RAM MAP 列重複正方形、菱形與棋盤格圖塊。AUTO RLE MAP 以十六個正方形圖塊形成水平條。VRAM TILES 將像素解碼至 VRAM 後,重複相同三種圖塊。CGB 與 FC 上正方形為白色、菱形為紅色、棋盤格為藍色;DMG 使用灰階。CHECKS OK 表示三次呼叫均無錯誤,且傳回預期解碼大小。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\zx0_decode.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\zx0_decode.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/zx0.h:15
Return decoded bytes, or zero on error (possibly after partial writes). Source and output must not overlap or cross their current CPU bank windows. Capacity and packed_size are byte counts. No prefix/backward/v1 streams.
kitaqgb/lib/zx0.c:52
u16 zx0_decompress(void* dst,u16 capacity,const void* src,u16 packed_size) {
u8 phase; u8 low; u8* out; u8* match;
u16 count; u16 distance; u16 used; u16 upper;
zx0_error=ZX0_OK;
if(!kq_zx_arguments(dst,capacity,src,packed_size)) { zx0_error=ZX0_BAD_ARGUMENT; return 0; }
kq_zx_input=(const u8*)src; kq_zx_left=packed_size;
kq_zx_mask=0; kq_zx_borrowed=0;
out=(u8*)dst; used=0; distance=1; phase=0;
// Phase 0 is literal, 1 reuses the last distance, 2 carries a new distance.
while(1) {
if(phase==2) {
upper=kq_zx_number(1);
if(zx0_error) return 0;
if(upper==256) {
if(kq_zx_left!=0) { zx0_error=ZX0_BAD_STREAM; return 0; }
return used;
}
if(upper>255) { zx0_error=ZX0_BAD_STREAM; return 0; }
low=kq_zx_byte();
distance=(u16)((upper<<7)-(low>>1));
kq_zx_borrowed=1; kq_zx_borrow_value=(u8)(low&1);
count=kq_zx_number(0);
if(count==65535) { zx0_error=ZX0_BAD_STREAM; return 0; }
count++;
} else count=kq_zx_number(0);
if(zx0_error) return 0;
if(count>capacity-used) { zx0_error=ZX0_OUTPUT_FULL; return 0; }
if(phase==0) {
if(count>kq_zx_left) { zx0_error=ZX0_TRUNCATED; return 0; }
kq_zx_left-=count; used+=count;
while(count!=0) { *out++=*kq_zx_input++; count--; }
phase=kq_zx_bit()?2:1;
} else {
if(distance>used) { zx0_error=ZX0_BAD_STREAM; return 0; }
match=out-distance; used+=count;
// Forward byte copying deliberately supports overlapping matches.
while(count!=0) { *out++=*match++; count--; }
phase=kq_zx_bit()?2:0;
}
if(zx0_error) return 0;
}
}asset_decompress
從 --format=auto 產生的 KQA1 標頭讀取編碼方式與大小,再複製 raw 位元組或將 RLE/ZX0 解碼至 RAM。呼叫端不必為各編碼方式另外分支。
語法
u16 asset_decompress(void* dst, u16 capacity, const void* src, u16 packed_size);參數
dst可寫入目的 RAM 的起點,不可為 null。容量須以位元組表示,不是陣列元素數。
capacity目的地可寫入的位元組數。一般 ZX0 串流至少需要一位元組。空的 raw KQA1 素材可在容量零時成功。
src透過目前記憶體庫映射可讀的壓縮資料起點,不可為 null。
packed_size完整輸入的位元組數。ZX0 串流須包含結束標記,且後面不得有額外位元組。KQA1 容器須包含其九位元組標頭。最大 65535 位元組。
回傳值
成功時傳回解碼位元組數,錯誤時為零。務必同時檢查 zx0_error。
使用條件與限制
引入 zx0.h 並編譯 lib/zx0.c。這些常式使用共用暫存區,不可從中斷重入。輸入與輸出不可重疊、繞回 CPU 位址空間,或跨越目前映射的記憶體庫視窗。函式庫不切換素材記憶體庫。
每次呼叫均更新 zx0_error:0 成功、1 無效引數、2 輸入截斷、3 格式錯誤的串流、4 輸出空間不足、5 顯示啟用。失敗可能留下部分輸出,請勿使用。若多項條件無效,以最先偵測到的條件決定錯誤碼。
KQA1 是 KITAQ 素材容器:四位元組識別碼、一位元組編碼方式(0 raw、1 RLE、2 ZX0)、解碼大小 u16、酬載大小 u16,接著是酬載。u16 欄位採小端序。RLE 重複 count/value 配對,count 為 1..255,以 count 零結束。空的 raw 素材成功時傳回零且錯誤為零。
使用範例
count=asset_decompress(decoded_auto,16,packed_auto,packed_auto_SIZE);
if(count!=16||zx0_error!=ZX0_OK)failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
RAM MAP 列重複正方形、菱形與棋盤格圖塊。AUTO RLE MAP 以十六個正方形圖塊形成水平條。VRAM TILES 將像素解碼至 VRAM 後,重複相同三種圖塊。CGB 與 FC 上正方形為白色、菱形為紅色、棋盤格為藍色;DMG 使用灰階。CHECKS OK 表示三次呼叫均無錯誤,且傳回預期解碼大小。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\zx0_decode.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\zx0_decode.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/zx0.h:18
Decode a KQA1 raw/RLE/ZX0 asset produced with --format=auto. Empty raw assets return zero with zx0_error==ZX0_OK.
kitaqgb/lib/zx0.c:95
u16 asset_decompress(void* dst,u16 capacity,const void* src,u16 packed_size) {
const u8* in; u8* out; u16 raw; u16 packed; u16 used;
u8 codec; u8 count; u8 value;
zx0_error=ZX0_OK;
if(packed_size<9||!kq_zx_arguments(dst,capacity,src,packed_size)) { zx0_error=ZX0_BAD_ARGUMENT; return 0; }
in=(const u8*)src; out=(u8*)dst;
if(in[0]!=75||in[1]!=81||in[2]!=65||in[3]!=49) { zx0_error=ZX0_BAD_STREAM; return 0; }
codec=in[4]; raw=(u16)((u16)in[5]|((u16)in[6]<<8));
packed=(u16)((u16)in[7]|((u16)in[8]<<8));
if(packed!=packed_size-9||codec>2) { zx0_error=ZX0_BAD_STREAM; return 0; }
if(raw>capacity) { zx0_error=ZX0_OUTPUT_FULL; return 0; }
in+=9;
if(codec==2) {
used=zx0_decompress(dst,raw,in,packed);
if(zx0_error==0&&used!=raw) zx0_error=ZX0_BAD_STREAM;
return zx0_error?0:used;
}
if(codec==0) {
if(raw!=packed) { zx0_error=ZX0_BAD_STREAM; return 0; }
used=raw; while(raw!=0) { *out++=*in++; raw--; } return used;
}
used=0;
while(packed!=0) {
count=*in++; packed--;
if(count==0) {
if(packed!=0||used!=raw) { zx0_error=ZX0_BAD_STREAM; return 0; }
return used;
}
if(packed==0) { zx0_error=ZX0_TRUNCATED; return 0; }
value=*in++; packed--;
if((u16)count>raw-used) { zx0_error=ZX0_OUTPUT_FULL; return 0; }
used+=count; while(count!=0) { *out++=value; count--; }
}
zx0_error=ZX0_TRUNCATED; return 0;
}zx0_decompress_vram
LCD 停止時,將 ZX0 圖塊像素或地圖資料直接解碼至所選 VRAM 記憶體庫。VRAM 本身提供相符片段歷史,因此不需要中間 RAM 緩衝區。
語法
u16 zx0_decompress_vram(u16 vram_addr, const void* src, u16 packed_size);參數
vram_addrVRAM 起始位址,0x8000..0x9FFF。輸出受 VRAM 結尾 0xA000 限制。CGB 上須先選擇 VBK 再呼叫。
src透過目前記憶體庫映射可讀的壓縮資料起點,不可為 null。
packed_size完整輸入的位元組數。ZX0 串流須包含結束標記,且後面不得有額外位元組。KQA1 容器須包含其九位元組標頭。最大 65535 位元組。
回傳值
成功時傳回解碼位元組數,錯誤時為零。務必同時檢查 zx0_error。
使用條件與限制
引入 zx0.h 並編譯 lib/zx0.c。這些常式使用共用暫存區,不可從中斷重入。輸入與輸出不可重疊、繞回 CPU 位址空間,或跨越目前映射的記憶體庫視窗。函式庫不切換素材記憶體庫。
每次呼叫均更新 zx0_error:0 成功、1 無效引數、2 輸入截斷、3 格式錯誤的串流、4 輸出空間不足、5 顯示啟用。失敗可能留下部分輸出,請勿使用。若多項條件無效,以最先偵測到的條件決定錯誤碼。
接受正向 ZX0 v2 串流。ZX0 v1、反向串流與外部字典不在此介面支援範圍。須掌握主機產生素材的解碼大小,並提供足夠儲存空間。
LCD 啟用時傳回錯誤 5;僅處於 VBlank 並不足夠。顯示、VBK 與中斷設定保持不變。由呼叫端停止並重新啟動 LCD。
使用範例
count=zx0_decompress_vram(0x8800,packed_tiles,packed_tiles_SIZE);
if(count!=48||zx0_error!=ZX0_OK)failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
RAM MAP 列重複正方形、菱形與棋盤格圖塊。AUTO RLE MAP 以十六個正方形圖塊形成水平條。VRAM TILES 將像素解碼至 VRAM 後,重複相同三種圖塊。CGB 與 FC 上正方形為白色、菱形為紅色、棋盤格為藍色;DMG 使用灰階。CHECKS OK 表示三次呼叫均無錯誤,且傳回預期解碼大小。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\zx0_decode.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\zx0_decode.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/zx0.h:21
Decode directly into the selected GB VRAM bank ($8000..$9FFF), with LCD off. Preserve LCDC, VBK and interrupt state. Output must fit before $A000.
kitaqgb/lib/zx0.c:132
u16 zx0_decompress_vram(u16 vram_addr,const void* src,u16 packed_size) {
zx0_error=ZX0_OK;
if(vram_addr<0x8000||vram_addr>=0xA000) { zx0_error=ZX0_BAD_ARGUMENT; return 0; }
if(kq_zx_lcdc&0x80) { zx0_error=ZX0_DISPLAY_ACTIVE; return 0; }
return zx0_decompress((void*)vram_addr,(u16)(0xA000-vram_addr),src,packed_size);
}asset.h — 素材 ID 與資料描述
素材函式庫透過8位元ID查找ROM記憶體區塊中的素材。請包含asset.c;FC版還需要bank.c。緊密排列的AssetDesc占6位元組,依序儲存1位元組類型、1位元組素材區塊編號、16位元位址,以及以位元組計算的長度。描述符表與素材資料可以放在不同區塊。
查找前請先登記表格。登記資訊是共用全域狀態,不要在查找過程中同時修改。函式庫會檢查ID與asset_get的輸出指標,但不會驗證已登記的表格、素材位址或卡匣內容是否正確。
查找RAW或TILES素材,使用__vram_copy傳送全部desc.len位元組。呼叫前必須選取素材資料所在的ROM區塊;GB版直接使用desc.ptr,傳送時不會選取desc.bank。
asset_get
從已登記表格所在的ROM區塊讀取一筆AssetDesc,複製到呼叫端提供的空間。取得的是素材資訊,而非素材資料本身。
語法
u8 asset_get(u8 asset_id, AssetDesc* out_desc);參數
asset_id從0開始的素材索引;只有小於已登記表格的
count的asset_id才有效。out_desc可寫入一筆6位元組描述符的空間。若為null,會在存取表格之前傳回失敗。
回傳值
複製描述符後傳回1;輸出指標為null或ID超出範圍時傳回0,且不修改輸出空間。
使用條件與限制
查找前請先登記表格。登記資訊是共用全域狀態,不要在查找過程中同時修改。函式庫會檢查ID與asset_get的輸出指標,但不會驗證已登記的表格、素材位址或卡匣內容是否正確。
範例將呼叫端程式碼放在固定區塊0,避免切換來源區塊後,正在執行的程式碼變得不可見。傳送是同步操作。不要在傳送期間由中斷再次執行切換區塊的複製,也不要認為此輔助函式能確保整個程式的中斷安全。
使用範例
loaded=asset_get(0,&descriptor);
expect(loaded==1,1);
expect(descriptor.type==ASSET_TYPE_TILES && descriptor.bank==2,2);
expect(descriptor.ptr==asset_shapes && descriptor.len==144,3);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例讀取描述符0,檢查TILES類型、區塊2、素材指標與144位元組長度。超出範圍的ID與null輸出必須失敗;查找失敗時保留輸出空間中的原值。
預期圖像中,紅色一列從像素座標(16,32)開始,占72×8像素。依序重複8×8三角形、邊框厚1像素的8×8空心正方形、填滿左側4欄的圖塊,共三組。三角形從左上角1像素逐漸擴展到底列8像素。
GB中,(16,64)的藍色三角形與方框顯示__farmemcpy結果,(16,96)的綠色一對顯示__far_memcpy結果。每對占16×8像素。CGB顯示上述顏色,DMG則在白底上以黑色顯示相同形狀。
預期狀態為FAILED CHECKS 000與FIRST FAILURE 00。驗證會執行300影格,比較文字、圖形遮罩與顏色是否符合預期。這是模擬器驗證,並非實體硬體測試。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\asset_banks.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\asset_banks.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/asset.h:24
Copy one descriptor from its ROM bank into caller storage. Return zero for a null destination or an out-of-range ID; table validity is the caller's responsibility.
kitaqgb/lib/asset.c:18
u8 asset_get(u8 asset_id, AssetDesc* out_desc)
{
if (out_desc == 0) return 0;
if (asset_id >= asset_table_count) return 0;
__farmemcpy(out_desc, asset_table_bank, asset_table + asset_id, sizeof(AssetDesc));
return 1;
}asset_get_bank
從描述符讀取素材資料的區塊編號。這不是描述符表所在的區塊編號,函式返回後也不會保持選取素材區塊。
語法
u8 asset_get_bank(u8 asset_id);參數
asset_id從0開始的素材索引;只有小於已登記表格的
count的asset_id才有效。
回傳值
傳回描述符的8位元bank;查找失敗則為0。有效區塊也可能為0,需要區分成敗時請使用asset_get()。
使用條件與限制
查找前請先登記表格。登記資訊是共用全域狀態,不要在查找過程中同時修改。函式庫會檢查ID與asset_get的輸出指標,但不會驗證已登記的表格、素材位址或卡匣內容是否正確。
每個取得函式都會再次呼叫asset_get並複製描述符。若同時需要區塊、指標與長度,請只呼叫一次asset_get後讀取各欄位。
範例將呼叫端程式碼放在固定區塊0,避免切換來源區塊後,正在執行的程式碼變得不可見。傳送是同步操作。不要在傳送期間由中斷再次執行切換區塊的複製,也不要認為此輔助函式能確保整個程式的中斷安全。
使用範例
payload_bank=asset_get_bank(0);
expect(payload_bank==2,17); // Payload bank, not descriptor-table bank 3.
expect(asset_get_bank(4)==0,18); // Failure sentinel; a valid descriptor may also use bank 0.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例確認即使描述符表位於區塊3,傳回的仍是素材資料的區塊2,也檢查無效ID會傳回0。
預期圖像中,紅色一列從像素座標(16,32)開始,占72×8像素。依序重複8×8三角形、邊框厚1像素的8×8空心正方形、填滿左側4欄的圖塊,共三組。三角形從左上角1像素逐漸擴展到底列8像素。
GB中,(16,64)的藍色三角形與方框顯示__farmemcpy結果,(16,96)的綠色一對顯示__far_memcpy結果。每對占16×8像素。CGB顯示上述顏色,DMG則在白底上以黑色顯示相同形狀。
預期狀態為FAILED CHECKS 000與FIRST FAILURE 00。驗證會執行300影格,比較文字、圖形遮罩與顏色是否符合預期。這是模擬器驗證,並非實體硬體測試。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\asset_banks.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\asset_banks.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/asset.h:32
Return the descriptor bank, or zero on lookup failure; zero can also be a valid bank.
kitaqgb/lib/asset.c:51
u8 asset_get_bank(u8 asset_id)
{
AssetDesc desc;
if (asset_get(asset_id, &desc) == 0) return 0;
return desc.bank;
}asset_get_len
從描述符讀取以位元組計算的素材長度。傳回的是登記資訊;函式不檢查素材本身,也不換算為圖塊數、元素數或影格數。
語法
u16 asset_get_len(u8 asset_id);參數
asset_id從0開始的素材索引;只有小於已登記表格的
count的asset_id才有效。
回傳值
傳回以位元組計算的16位元len;查找失敗為0。空素材的長度也是0,區分兩者請使用asset_get()。
使用條件與限制
查找前請先登記表格。登記資訊是共用全域狀態,不要在查找過程中同時修改。函式庫會檢查ID與asset_get的輸出指標,但不會驗證已登記的表格、素材位址或卡匣內容是否正確。
每個取得函式都會再次呼叫asset_get並複製描述符。若同時需要區塊、指標與長度,請只呼叫一次asset_get後讀取各欄位。
範例將呼叫端程式碼放在固定區塊0,避免切換來源區塊後,正在執行的程式碼變得不可見。傳送是同步操作。不要在傳送期間由中斷再次執行切換區塊的複製,也不要認為此輔助函式能確保整個程式的中斷安全。
使用範例
expect(asset_get_len(0)==144,21); // Bytes, not tiles.
expect(asset_get_len(3)==0 && asset_get_len(4)==0,22); // Empty asset and invalid ID both yield zero.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
9個圖塊的素材應傳回144位元組,而非圖塊數9。空素材與無效ID皆應傳回0。
預期圖像中,紅色一列從像素座標(16,32)開始,占72×8像素。依序重複8×8三角形、邊框厚1像素的8×8空心正方形、填滿左側4欄的圖塊,共三組。三角形從左上角1像素逐漸擴展到底列8像素。
GB中,(16,64)的藍色三角形與方框顯示__farmemcpy結果,(16,96)的綠色一對顯示__far_memcpy結果。每對占16×8像素。CGB顯示上述顏色,DMG則在白底上以黑色顯示相同形狀。
預期狀態為FAILED CHECKS 000與FIRST FAILURE 00。驗證會執行300影格,比較文字、圖形遮罩與顏色是否符合預期。這是模擬器驗證,並非實體硬體測試。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\asset_banks.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\asset_banks.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/asset.h:37
Return the descriptor byte length, or zero if its ID cannot be resolved.
kitaqgb/lib/asset.c:68
u16 asset_get_len(u8 asset_id)
{
AssetDesc desc;
if (asset_get(asset_id, &desc) == 0) return 0;
return desc.len;
}asset_get_ptr
讀取描述符中保存的16位元的素材位址。傳回的近指標不含區塊編號。讀取其他ROM區塊中的素材時,應搭配asset_get_bank()的結果與跨區塊複製函式使用。
語法
const u8* asset_get_ptr(u8 asset_id);參數
asset_id從0開始的素材索引;只有小於已登記表格的
count的asset_id才有效。
回傳值
傳回保存的const u8*;查找失敗時為null。函式不檢查描述符中的素材指標是否為null,區分查找成敗請使用asset_get()。
使用條件與限制
查找前請先登記表格。登記資訊是共用全域狀態,不要在查找過程中同時修改。函式庫會檢查ID與asset_get的輸出指標,但不會驗證已登記的表格、素材位址或卡匣內容是否正確。
每個取得函式都會再次呼叫asset_get並複製描述符。若同時需要區塊、指標與長度,請只呼叫一次asset_get後讀取各欄位。
範例將呼叫端程式碼放在固定區塊0,避免切換來源區塊後,正在執行的程式碼變得不可見。傳送是同步操作。不要在傳送期間由中斷再次執行切換區塊的複製,也不要認為此輔助函式能確保整個程式的中斷安全。
使用範例
payload_pointer=asset_get_ptr(0);
expect(payload_pointer==asset_shapes,19);
expect(*asset_bank_marker==0xA1,20); // Getting the pointer leaves bank 1 selected.
// Use payload_bank together with payload_pointer for a far copy; do not dereference it here.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
傳回指標必須等於ROM配置完成後的素材位址,同時區塊1中的標記仍可讀取。隨後,範例將此指標與素材區塊2一起傳給跨區塊複製函式。
預期圖像中,紅色一列從像素座標(16,32)開始,占72×8像素。依序重複8×8三角形、邊框厚1像素的8×8空心正方形、填滿左側4欄的圖塊,共三組。三角形從左上角1像素逐漸擴展到底列8像素。
GB中,(16,64)的藍色三角形與方框顯示__farmemcpy結果,(16,96)的綠色一對顯示__far_memcpy結果。每對占16×8像素。CGB顯示上述顏色,DMG則在白底上以黑色顯示相同形狀。
預期狀態為FAILED CHECKS 000與FIRST FAILURE 00。驗證會執行300影格,比較文字、圖形遮罩與顏色是否符合預期。這是模擬器驗證,並非實體硬體測試。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\asset_banks.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\asset_banks.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/asset.h:35
Return the stored address without switching banks. Use the descriptor bank with far-data helpers before dereferencing banked assets; failure returns null.
kitaqgb/lib/asset.c:60
const u8* asset_get_ptr(u8 asset_id)
{
AssetDesc desc;
if (asset_get(asset_id, &desc) == 0) return 0;
return desc.ptr;
}asset_load_raw
查找素材,從其ROM區塊向可寫入記憶體複製min(desc.len, max_len)位元組。不檢查類型標記;圖塊、地圖與樂曲都依原始位元組複製,不解析格式,也不解壓縮。
語法
u8 asset_load_raw(u8 asset_id, void* dst, u16 max_len);參數
asset_id從0開始的素材索引;只有小於已登記表格的
count的asset_id才有效。dst目標可寫入記憶體,容量必須足以容納實際複製的全部位元組。除了零位元組傳送外,不會檢查null或無效目標位址。
max_len最多複製的位元組數,範圍0–65535。小於素材長度時只複製前面一部分;設為0時不複製素材位元組。
回傳值
查找失敗傳回0,否則傳回1,包含只複製部分資料、上限為0或空素材。傳回值不是位元組數,也不表示整份素材都已複製。
使用條件與限制
查找前請先登記表格。登記資訊是共用全域狀態,不要在查找過程中同時修改。函式庫會檢查ID與asset_get的輸出指標,但不會驗證已登記的表格、素材位址或卡匣內容是否正確。
整個來源範圍必須在預期ROM映射中可讀取,整個目標範圍必須可寫入。複製不會在區塊視窗邊界自動切換至下一區塊,不提供memmove式的重疊處理,也不控制VRAM安全寫入時機。寫入VRAM請使用圖形傳送API。
範例將呼叫端程式碼放在固定區塊0,避免切換來源區塊後,正在執行的程式碼變得不可見。傳送是同步操作。不要在傳送期間由中斷再次執行切換區塊的複製,也不要認為此輔助函式能確保整個程式的中斷安全。
使用範例
loaded=asset_load_raw(0,buffer,7); // Success with truncation: copy seven of 144 bytes.
expect(loaded==1 && buffer[7]==0x55,7);
for(i=0;i<7;i++) expect(buffer[(__safe_index u8)i]==expected_shape_byte(i),8);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
對144位元組素材設定7位元組上限,只複製前7位元組,下一位元組仍為0x55,但函式傳回成功。程式也檢查完整複製、上限0、空素材,以及MAP類型素材的原始複製。
預期圖像中,紅色一列從像素座標(16,32)開始,占72×8像素。依序重複8×8三角形、邊框厚1像素的8×8空心正方形、填滿左側4欄的圖塊,共三組。三角形從左上角1像素逐漸擴展到底列8像素。
GB中,(16,64)的藍色三角形與方框顯示__farmemcpy結果,(16,96)的綠色一對顯示__far_memcpy結果。每對占16×8像素。CGB顯示上述顏色,DMG則在白底上以黑色顯示相同形狀。
預期狀態為FAILED CHECKS 000與FIRST FAILURE 00。驗證會執行300影格,比較文字、圖形遮罩與顏色是否符合預期。這是模擬器驗證,並非實體硬體測試。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\asset_banks.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\asset_banks.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/asset.h:27
Copy at most max_len bytes using the asset's bank. Success means the ID was valid, even when the payload was truncated to fit the supplied limit.
kitaqgb/lib/asset.c:28
u8 asset_load_raw(u8 asset_id, void* dst, u16 max_len)
{
AssetDesc desc;
u16 len;
if (asset_get(asset_id, &desc) == 0) return 0;
len = desc.len;
if (len > max_len) len = max_len;
__farmemcpy(dst, desc.bank, desc.ptr, len);
return 1;
}asset_load_tiles
查找RAW或TILES素材,使用__vram_copy傳送全部desc.len位元組。呼叫前必須選取素材資料所在的ROM區塊;GB版直接使用desc.ptr,傳送時不會選取desc.bank。
語法
u8 asset_load_tiles(u8 asset_id, u16 vram_dst);參數
asset_id從0開始的素材索引;只有小於已登記表格的
count的asset_id才有效。vram_dst$8000–$9FFF範圍內的VRAM位元組位址,不是圖塊編號。圖塊圖案應使用16位元組對齊的位址,描述符長度應為16的倍數;函式庫不會檢查這些格式要求。
回傳值
ID無效或類型不是RAW/TILES時傳回0;接受並完成傳送後傳回1,長度為0也一樣。成功值不代表已驗證圖塊編碼或VRAM顯示正確。
使用條件與限制
查找前請先登記表格。登記資訊是共用全域狀態,不要在查找過程中同時修改。函式庫會檢查ID與asset_get的輸出指標,但不會驗證已登記的表格、素材位址或卡匣內容是否正確。
範例將呼叫端程式碼放在固定區塊0,避免切換來源區塊後,正在執行的程式碼變得不可見。傳送是同步操作。不要在傳送期間由中斷再次執行切換區塊的複製,也不要認為此輔助函式能確保整個程式的中斷安全。
上傳只寫入位元組,不會在地圖上放置圖塊、設定顏色或配置VRAM。圖塊地圖與調色盤需要另外設定。範例會關閉繪製後上傳,準備好圖像才啟用顯示。
GB輔助常式依編譯器保存的ROM區塊狀態恢復映射。請用__bankswitch維護此狀態;直接寫入映射器不會更新它。HRAM中的返回區塊儲存位置是共用的,巢狀傳送若覆寫此位置就不安全。
使用範例
__bankswitch(payload_bank); // GB tile upload expects the payload bank already visible.
loaded=asset_load_tiles(0,0x8010); // Nine tiles = 144 bytes, LCD off.
expect(loaded==1,24);
__bankswitch(1);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
圖塊上傳範例使用9個自製8×8圖案,共144位元組,並檢查MAP類型與無效ID會被拒絕。FC的144位元組傳送同時涵蓋128位元組區塊與剩餘16位元組。
預期圖像中,紅色一列從像素座標(16,32)開始,占72×8像素。依序重複8×8三角形、邊框厚1像素的8×8空心正方形、填滿左側4欄的圖塊,共三組。三角形從左上角1像素逐漸擴展到底列8像素。
GB中,(16,64)的藍色三角形與方框顯示__farmemcpy結果,(16,96)的綠色一對顯示__far_memcpy結果。每對占16×8像素。CGB顯示上述顏色,DMG則在白底上以黑色顯示相同形狀。
預期狀態為FAILED CHECKS 000與FIRST FAILURE 00。驗證會執行300影格,比較文字、圖形遮罩與顏色是否符合預期。這是模擬器驗證,並非實體硬體測試。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\asset_banks.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\asset_banks.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/asset.h:30
Accept tile/raw descriptors and transfer their bytes to VRAM. This path passes the descriptor pointer directly; callers must arrange the correct visible ROM bank.
kitaqgb/lib/asset.c:41
u8 asset_load_tiles(u8 asset_id, u16 vram_dst)
{
AssetDesc desc;
if (asset_get(asset_id, &desc) == 0) return 0;
if (desc.type != ASSET_TYPE_TILES && desc.type != ASSET_TYPE_RAW) return 0;
__vram_copy(vram_dst, desc.ptr, desc.len);
return 1;
}asset_set_table
登記目前描述符表的區塊編號、位址與項目數。同一時間只保留一張表。此函式只保存這三個值,不複製表格、不讀取素材,也不配置記憶體。
語法
void asset_set_table(u8 bank, const AssetDesc* table, u8 count);參數
bank描述符表所在的ROM區塊編號,使用8位元值;不是素材資料的編號。
table指向連續
count筆AssetDesc的近指標。登記有效期間,表格所在區塊中的count * 6位元組必須維持可讀取狀態。count項目數,範圍為0–255。設為0時所有ID皆無效;可用
asset_set_table(0, 0, 0)安全地登記空表。
回傳值
無(void)。
使用條件與限制
查找前請先登記表格。登記資訊是共用全域狀態,不要在查找過程中同時修改。函式庫會檢查ID與asset_get的輸出指標,但不會驗證已登記的表格、素材位址或卡匣內容是否正確。
使用範例
asset_set_table(3,asset_descriptors,4); // Four descriptors in bank 3, payloads in bank 2.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此例登記區塊3中的4筆描述符,非空素材資料位於區塊2。也會登記空表,確認查找失敗時不會讀取位址0。
預期圖像中,紅色一列從像素座標(16,32)開始,占72×8像素。依序重複8×8三角形、邊框厚1像素的8×8空心正方形、填滿左側4欄的圖塊,共三組。三角形從左上角1像素逐漸擴展到底列8像素。
GB中,(16,64)的藍色三角形與方框顯示__farmemcpy結果,(16,96)的綠色一對顯示__far_memcpy結果。每對占16×8像素。CGB顯示上述顏色,DMG則在白底上以黑色顯示相同形狀。
預期狀態為FAILED CHECKS 000與FIRST FAILURE 00。驗證會執行300影格,比較文字、圖形遮罩與顏色是否符合預期。這是模擬器驗證,並非實體硬體測試。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\asset_banks.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\asset_banks.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/asset.h:21
Retain the descriptor table address, bank and count; the table is not copied.
kitaqgb/lib/asset.c:9
void asset_set_table(u8 bank, const AssetDesc* table, u8 count)
{
asset_table_bank = bank;
asset_table = table;
asset_table_count = count;
}audio.h — 音樂、音效與音訊控制
提供四聲部直接控制、分庫音樂/效果、立體聲路由、音量淡入淡出與自訂波形。音樂串流及直接 API 的通道 ID 為 CH1=0、CH2=1、CH3=2、CH4=3。CH3 播放波形,CH4 產生雜訊。
請先引入 audio_hwregs_gb.c 再引入 audio.c,並在啟動時呼叫 Audio_Init。每影格恰好呼叫 Audio_Update 一次,約 59.7 Hz。讀取串流會暫時改變 ROM 映射,勿從中斷重入此驅動。
效果每次更新消耗一組 (note,value),遇到 note=0 結束。脈波效果的 value 為 NR12,CH3 則為 NR32。CH3 資料前須加上 0xFF,且儲存空間須保留至播放完成。優先權在同一槽內競爭,相同優先權也可取代目前效果。
Audio_CancelMasterVolumeFade
保留目前音量與暫存器,停止後續淡入淡出步進。
語法
void Audio_CancelMasterVolumeFade();回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用範例
// A sustained pulse moves left, right and center, then fades to a quieter level.
#include "gb_sound_example.h"
void main() {
sound_begin("PAN AND VOLUME");
Audio_SetMasterVolume(7,7);
Audio_Ch1NoteOn(33,0xC0,2);
Audio_SetPan(AUDIO_CHANNEL_CH1,AUDIO_PAN_LEFT);
sound_result[0]=NR51;
sound_wait(30);
// Packed low two bits are CH1: 2 means right. Other channels remain centered.
Audio_SetPanPacked(2);
sound_result[1]=NR51;
sound_wait(30);
Audio_SetPanPacked(0);
sound_result[2]=NR51;
Audio_FadeToMasterVolume(1,1,5);
sound_wait(30);
sound_result[3]=NR50;
sound_result[4]=Audio_FadeActive;
sound_wait(30);
// Cancel halfway through a rise: retain volume 4 instead of reaching 7.
Audio_FadeToMasterVolume(7,7,5);
sound_wait(15);
Audio_CancelMasterVolumeFade();
sound_result[5]=NR50;
sound_wait(30);
sound_result[6]=NR50;
// A zero fade interval sets the target immediately. Level zero is not mute.
Audio_FadeToMasterVolume(0,0,0);
sound_result[7]=NR50;
sound_wait(30);
Audio_StopChannel(AUDIO_CHANNEL_CH1);
sound_wait(15);
sound_end();
}預期結果
A4 依序移至左、右、中央。在中央從等級 7 淡出至 1,再升至 4 並保持。等級 0 仍可微弱聽見;停止通道才會靜音。改變路由後,可能留下逐漸衰減的濾波器暫態聲。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_mix.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-mix.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:125
Cancel further volume steps, retaining the current cached levels and hardware output.
kitaqgb/lib/audio.c:548
void Audio_CancelMasterVolumeFade() {
Audio_FadeTargetLeft = Audio_MasterLeft;
Audio_FadeTargetRight = Audio_MasterRight;
Audio_FadeStepFrames = 0;
Audio_FadeCounter = 0;
Audio_FadeActive = 0;
}Audio_Ch1NoteOn
設定 CH1 掃頻、工作週期、包絡與音高,再觸發脈波。
語法
void __stackcall Audio_Ch1NoteOn(u8 note, u8 vol_env, u8 duty2);參數
note音高表索引 0..67。範圍折返與 CH3 八度差異請參閱注意事項。
vol_envNR12/NR22/NR42 編碼:高半位元組為初始音量,位元 3 為遞增包絡,低三位元為包絡週期。0xC0 維持音量 12。
duty2脈波工作週期:0=12.5%、1=25%、3=75%;其他值皆選擇 50%。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
note 是 0..67 音高表索引:0 為 C2,33 為 A4。大於 67 會限制為 67;60..67 使用 48..55 的頻率。同索引下,CH3 比脈波通道低一個八度。發聲函式直接觸發硬體,不檢查啟用或暫停開關。
使用範例
// Four isolated voices, each lasting 30 frames, separated by 15 silent frames.
#include "gb_sound_example.h"
void main() {
sound_begin("FOUR SOUND CHANNELS");
Audio_SetMasterVolume(3,3);
// CH1: A4, 50% duty, fixed envelope volume 12.
Audio_SetCh1Duty(2);
sound_result[0]=Audio_Ch1Duty;
Audio_Ch1NoteOn(33,0xC0,Audio_Ch1Duty);
sound_result[1]=NR12;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH1); sound_wait(15);
// CH2: A4, 25% duty. Changing the cached duty takes effect on this trigger.
Audio_SetCh2Duty(1);
sound_result[2]=Audio_Ch2Duty;
Audio_Ch2NoteOn(33,0xC0,Audio_Ch2Duty);
sound_result[3]=NR22;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH2); sound_wait(15);
// CH3: the initialized triangle wave, at 50% digital output level.
Audio_SetCh3Level(AUDIO_CH3_LEVEL_50);
sound_result[4]=Audio_Ch3Level;
Audio_Ch3NoteOn(33,Audio_Ch3Level);
sound_result[5]=NR32;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
// CH4: a sustained noise burst; param is NR43, not a pitched note number.
Audio_SetCh4Param(0x35);
sound_result[6]=Audio_Ch4Param;
Audio_Ch4NoteOn(Audio_Ch4Param,0xC0);
sound_result[7]=NR43;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH4); sound_wait(15);
sound_end();
}預期結果
約半秒靜音後,依序聽到 CH1 A4、CH2 A4、CH3 A3 與雜訊。每個聲音持續 30 影格,中間間隔 15 影格。SEQUENCE COMPLETE 表示程式完成;請用錄音判斷聲音。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_channels.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-channels.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:151
Trigger CH1 with the cached sweep and the supplied raw envelope. Clamp the note index; duty values 0, 1 and 3 select their encodings, and all others use 2.
kitaqgb/lib/audio.c:132
void __stackcall Audio_Ch1NoteOn(u8 note, u8 vol_env, u8 duty2) {
u16 freq;
u8 duty_reg;
u8 hi;
if (note > AUDIO_NOTE_MAX) note = AUDIO_NOTE_MAX;
freq = GB_FREQ_TABLE[note];
duty_reg = 128;
if (duty2 == 0) duty_reg = 0;
else if (duty2 == 1) duty_reg = 64;
else if (duty2 == 3) duty_reg = 192;
NR10 = Audio_Ch1Sweep;
NR11 = duty_reg;
NR12 = vol_env;
NR13 = (u8)(freq & 0xFF);
hi = (u8)((u16)freq >> 8);
NR14 = (u8)(hi | 0x80);
}Audio_Ch2NoteOn
設定 CH2 工作週期、包絡與音高,再觸發脈波。
語法
void __stackcall Audio_Ch2NoteOn(u8 note, u8 vol_env, u8 duty2);參數
note音高表索引 0..67。範圍折返與 CH3 八度差異請參閱注意事項。
vol_envNR12/NR22/NR42 編碼:高半位元組為初始音量,位元 3 為遞增包絡,低三位元為包絡週期。0xC0 維持音量 12。
duty2脈波工作週期:0=12.5%、1=25%、3=75%;其他值皆選擇 50%。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
note 是 0..67 音高表索引:0 為 C2,33 為 A4。大於 67 會限制為 67;60..67 使用 48..55 的頻率。同索引下,CH3 比脈波通道低一個八度。發聲函式直接觸發硬體,不檢查啟用或暫停開關。
使用範例
// Four isolated voices, each lasting 30 frames, separated by 15 silent frames.
#include "gb_sound_example.h"
void main() {
sound_begin("FOUR SOUND CHANNELS");
Audio_SetMasterVolume(3,3);
// CH1: A4, 50% duty, fixed envelope volume 12.
Audio_SetCh1Duty(2);
sound_result[0]=Audio_Ch1Duty;
Audio_Ch1NoteOn(33,0xC0,Audio_Ch1Duty);
sound_result[1]=NR12;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH1); sound_wait(15);
// CH2: A4, 25% duty. Changing the cached duty takes effect on this trigger.
Audio_SetCh2Duty(1);
sound_result[2]=Audio_Ch2Duty;
Audio_Ch2NoteOn(33,0xC0,Audio_Ch2Duty);
sound_result[3]=NR22;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH2); sound_wait(15);
// CH3: the initialized triangle wave, at 50% digital output level.
Audio_SetCh3Level(AUDIO_CH3_LEVEL_50);
sound_result[4]=Audio_Ch3Level;
Audio_Ch3NoteOn(33,Audio_Ch3Level);
sound_result[5]=NR32;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
// CH4: a sustained noise burst; param is NR43, not a pitched note number.
Audio_SetCh4Param(0x35);
sound_result[6]=Audio_Ch4Param;
Audio_Ch4NoteOn(Audio_Ch4Param,0xC0);
sound_result[7]=NR43;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH4); sound_wait(15);
sound_end();
}預期結果
約半秒靜音後,依序聽到 CH1 A4、CH2 A4、CH3 A3 與雜訊。每個聲音持續 30 影格,中間間隔 15 影格。SEQUENCE COMPLETE 表示程式完成;請用錄音判斷聲音。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_channels.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-channels.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:154
Trigger CH2 with the supplied raw envelope and a clamped note index. Duty values 0, 1 and 3 select their encodings; all other values use duty 2.
kitaqgb/lib/audio.c:666
void __stackcall Audio_Ch2NoteOn(u8 note, u8 vol_env, u8 duty2) {
u16 freq;
u8 duty_reg;
u8 hi;
if (note > AUDIO_NOTE_MAX) note = AUDIO_NOTE_MAX;
freq = GB_FREQ_TABLE[note];
duty_reg = 128;
if (duty2 == 0) duty_reg = 0;
else if (duty2 == 1) duty_reg = 64;
else if (duty2 == 3) duty_reg = 192;
NR21 = duty_reg;
NR22 = vol_env;
NR23 = (u8)(freq & 0xFF);
hi = (u8)((u16)freq >> 8);
NR24 = (u8)(hi | 0x80);
}Audio_Ch3NoteOn
以指定音高與 NR32 音量觸發已載入的 CH3 波形。
語法
void __stackcall Audio_Ch3NoteOn(u8 note, u8 level);參數
note音高表索引 0..67。範圍折返與 CH3 八度差異請參閱注意事項。
levelNR32 編碼:0x00=靜音、0x20=100%、0x40=50%、0x60=25%。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
note 是 0..67 音高表索引:0 為 C2,33 為 A4。大於 67 會限制為 67;60..67 使用 48..55 的頻率。同索引下,CH3 比脈波通道低一個八度。發聲函式直接觸發硬體,不檢查啟用或暫停開關。
使用範例
// Four isolated voices, each lasting 30 frames, separated by 15 silent frames.
#include "gb_sound_example.h"
void main() {
sound_begin("FOUR SOUND CHANNELS");
Audio_SetMasterVolume(3,3);
// CH1: A4, 50% duty, fixed envelope volume 12.
Audio_SetCh1Duty(2);
sound_result[0]=Audio_Ch1Duty;
Audio_Ch1NoteOn(33,0xC0,Audio_Ch1Duty);
sound_result[1]=NR12;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH1); sound_wait(15);
// CH2: A4, 25% duty. Changing the cached duty takes effect on this trigger.
Audio_SetCh2Duty(1);
sound_result[2]=Audio_Ch2Duty;
Audio_Ch2NoteOn(33,0xC0,Audio_Ch2Duty);
sound_result[3]=NR22;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH2); sound_wait(15);
// CH3: the initialized triangle wave, at 50% digital output level.
Audio_SetCh3Level(AUDIO_CH3_LEVEL_50);
sound_result[4]=Audio_Ch3Level;
Audio_Ch3NoteOn(33,Audio_Ch3Level);
sound_result[5]=NR32;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
// CH4: a sustained noise burst; param is NR43, not a pitched note number.
Audio_SetCh4Param(0x35);
sound_result[6]=Audio_Ch4Param;
Audio_Ch4NoteOn(Audio_Ch4Param,0xC0);
sound_result[7]=NR43;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH4); sound_wait(15);
sound_end();
}預期結果
約半秒靜音後,依序聽到 CH1 A4、CH2 A4、CH3 A3 與雜訊。每個聲音持續 30 影格,中間間隔 15 影格。SEQUENCE COMPLETE 表示程式完成;請用錄音判斷聲音。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_channels.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-channels.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:157
Clamp the note index, program the raw NR32 output level, and trigger CH3. Wave RAM must already contain the desired waveform; this does not load one.
kitaqgb/lib/audio.c:115
void __stackcall Audio_Ch3NoteOn(u8 note, u8 level) {
u16 freq;
u8 hi;
if (note > AUDIO_NOTE_MAX) note = AUDIO_NOTE_MAX;
freq = GB_FREQ_TABLE[note];
NR30 = 128;
NR31 = 0;
NR32 = level;
NR33 = (u8)(freq & 255);
hi = (u8)((u16)freq >> 8);
NR34 = (u8)(hi | 128);
}Audio_Ch4NoteOn
快取雜訊參數,設定包絡/多項式計數器暫存器,再觸發 CH4。
語法
void __stackcall Audio_Ch4NoteOn(u8 param, u8 vol_env);參數
param原始 NR43:位元 7..4 為時脈移位,位元 3 為短 LFSR,位元 2..0 為除數代碼。
vol_envNR12/NR22/NR42 編碼:高半位元組為初始音量,位元 3 為遞增包絡,低三位元為包絡週期。0xC0 維持音量 12。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
不啟用依長度自動停止。請用包絡或明確停止操作結束聲音。
使用範例
// Four isolated voices, each lasting 30 frames, separated by 15 silent frames.
#include "gb_sound_example.h"
void main() {
sound_begin("FOUR SOUND CHANNELS");
Audio_SetMasterVolume(3,3);
// CH1: A4, 50% duty, fixed envelope volume 12.
Audio_SetCh1Duty(2);
sound_result[0]=Audio_Ch1Duty;
Audio_Ch1NoteOn(33,0xC0,Audio_Ch1Duty);
sound_result[1]=NR12;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH1); sound_wait(15);
// CH2: A4, 25% duty. Changing the cached duty takes effect on this trigger.
Audio_SetCh2Duty(1);
sound_result[2]=Audio_Ch2Duty;
Audio_Ch2NoteOn(33,0xC0,Audio_Ch2Duty);
sound_result[3]=NR22;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH2); sound_wait(15);
// CH3: the initialized triangle wave, at 50% digital output level.
Audio_SetCh3Level(AUDIO_CH3_LEVEL_50);
sound_result[4]=Audio_Ch3Level;
Audio_Ch3NoteOn(33,Audio_Ch3Level);
sound_result[5]=NR32;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
// CH4: a sustained noise burst; param is NR43, not a pitched note number.
Audio_SetCh4Param(0x35);
sound_result[6]=Audio_Ch4Param;
Audio_Ch4NoteOn(Audio_Ch4Param,0xC0);
sound_result[7]=NR43;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH4); sound_wait(15);
sound_end();
}預期結果
約半秒靜音後,依序聽到 CH1 A4、CH2 A4、CH3 A3 與雜訊。每個聲音持續 30 影格,中間間隔 15 影格。SEQUENCE COMPLETE 表示程式完成;請用錄音判斷聲音。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_channels.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-channels.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:160
Cache the supplied noise parameter, program the raw envelope and polynomial registers, then trigger CH4 with the length-enable bit clear.
kitaqgb/lib/audio.c:688
void __stackcall Audio_Ch4NoteOn(u8 param, u8 vol_env) {
Audio_SetCh4Param(param);
NR41 = 0x20;
NR42 = vol_env;
NR43 = Audio_Ch4Param;
NR44 = 0x80;
}Audio_FadeToMasterVolume
每到指定更新間隔,讓各輸出音量朝目標前進一級。
語法
void __stackcall Audio_FadeToMasterVolume(u8 left, u8 right, u8 step_frames);參數
left左側主音量 0..7,較大值限制為 7。零並非完全靜音。
right右側主音量 0..7,較大值限制為 7。
step_frames每改變一級所需的 Audio_Update 呼叫數。零會立即套用目標值。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
請先引入 audio_hwregs_gb.c 再引入 audio.c,並在啟動時呼叫 Audio_Init。每影格恰好呼叫 Audio_Update 一次,約 59.7 Hz。讀取串流會暫時改變 ROM 映射,勿從中斷重入此驅動。
使用範例
// A sustained pulse moves left, right and center, then fades to a quieter level.
#include "gb_sound_example.h"
void main() {
sound_begin("PAN AND VOLUME");
Audio_SetMasterVolume(7,7);
Audio_Ch1NoteOn(33,0xC0,2);
Audio_SetPan(AUDIO_CHANNEL_CH1,AUDIO_PAN_LEFT);
sound_result[0]=NR51;
sound_wait(30);
// Packed low two bits are CH1: 2 means right. Other channels remain centered.
Audio_SetPanPacked(2);
sound_result[1]=NR51;
sound_wait(30);
Audio_SetPanPacked(0);
sound_result[2]=NR51;
Audio_FadeToMasterVolume(1,1,5);
sound_wait(30);
sound_result[3]=NR50;
sound_result[4]=Audio_FadeActive;
sound_wait(30);
// Cancel halfway through a rise: retain volume 4 instead of reaching 7.
Audio_FadeToMasterVolume(7,7,5);
sound_wait(15);
Audio_CancelMasterVolumeFade();
sound_result[5]=NR50;
sound_wait(30);
sound_result[6]=NR50;
// A zero fade interval sets the target immediately. Level zero is not mute.
Audio_FadeToMasterVolume(0,0,0);
sound_result[7]=NR50;
sound_wait(30);
Audio_StopChannel(AUDIO_CHANNEL_CH1);
sound_wait(15);
sound_end();
}預期結果
A4 依序移至左、右、中央。在中央從等級 7 淡出至 1,再升至 4 並保持。等級 0 仍可微弱聽見;停止通道才會靜音。改變路由後,可能留下逐漸衰減的濾波器暫態聲。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_mix.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-mix.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:123
Move left/right volume toward clamped targets at the requested Audio_Update call interval. An interval of zero applies the levels immediately.
kitaqgb/lib/audio.c:528
void __stackcall Audio_FadeToMasterVolume(u8 left, u8 right, u8 step_frames) {
Audio_FadeTargetLeft = Audio_ClampVolume(left);
Audio_FadeTargetRight = Audio_ClampVolume(right);
if (step_frames == 0) {
Audio_SetMasterVolume(Audio_FadeTargetLeft, Audio_FadeTargetRight);
return;
}
Audio_FadeStepFrames = step_frames;
Audio_FadeCounter = step_frames;
if (Audio_MasterLeft == Audio_FadeTargetLeft && Audio_MasterRight == Audio_FadeTargetRight) {
Audio_FadeActive = 0;
Audio_FadeCounter = 0;
} else {
Audio_FadeActive = 1;
}
}Audio_Init
啟用 APU,初始化音樂、效果、暫停、混音與波形狀態,並讓所有通道保持靜音。
語法
void Audio_Init();回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
請先引入 audio_hwregs_gb.c 再引入 audio.c,並在啟動時呼叫 Audio_Init。每影格恰好呼叫 Audio_Update 一次,約 59.7 Hz。讀取串流會暫時改變 ROM 映射,勿從中斷重入此驅動。
使用範例
// Four isolated voices, each lasting 30 frames, separated by 15 silent frames.
#include "gb_sound_example.h"
void main() {
sound_begin("FOUR SOUND CHANNELS");
Audio_SetMasterVolume(3,3);
// CH1: A4, 50% duty, fixed envelope volume 12.
Audio_SetCh1Duty(2);
sound_result[0]=Audio_Ch1Duty;
Audio_Ch1NoteOn(33,0xC0,Audio_Ch1Duty);
sound_result[1]=NR12;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH1); sound_wait(15);
// CH2: A4, 25% duty. Changing the cached duty takes effect on this trigger.
Audio_SetCh2Duty(1);
sound_result[2]=Audio_Ch2Duty;
Audio_Ch2NoteOn(33,0xC0,Audio_Ch2Duty);
sound_result[3]=NR22;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH2); sound_wait(15);
// CH3: the initialized triangle wave, at 50% digital output level.
Audio_SetCh3Level(AUDIO_CH3_LEVEL_50);
sound_result[4]=Audio_Ch3Level;
Audio_Ch3NoteOn(33,Audio_Ch3Level);
sound_result[5]=NR32;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
// CH4: a sustained noise burst; param is NR43, not a pitched note number.
Audio_SetCh4Param(0x35);
sound_result[6]=Audio_Ch4Param;
Audio_Ch4NoteOn(Audio_Ch4Param,0xC0);
sound_result[7]=NR43;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH4); sound_wait(15);
sound_end();
}預期結果
約半秒靜音後,依序聽到 CH1 A4、CH2 A4、CH3 A3 與雜訊。每個聲音持續 30 影格,中間間隔 15 影格。SEQUENCE COMPLETE 表示程式完成;請用錄音判斷聲音。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_channels.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-channels.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:76
Enable the APU and reset software streams, instruments, mix and fade state. Load the initial triangle wave, then leave every channel silent. Call at startup before concurrent interrupt-driven audio service can access these shared fields.
kitaqgb/lib/audio.c:864
void Audio_Init() {
NR52 = 0x80;
NR51 = 0xFF;
Audio_Pan = 0xFF;
Audio_EffectPan = AUDIO_PAN_INHERIT;
Audio_EffectPan3 = AUDIO_PAN_INHERIT;
Audio_UpdateNR51();
Audio_SetMasterVolume(AUDIO_VOLUME_MAX, AUDIO_VOLUME_MAX);
Audio_SilenceAll();
Audio_PlayingMusic = 0;
Audio_Paused = 0;
Audio_MusicEnabled = 1;
Audio_SfxEnabled = 1;
Audio_Delay = 0;
Audio_MusicBank = 0;
Audio_MusicPointer = 0;
Audio_MusicLoopPoint = 0;
Audio_EffectPointer = 0;
Audio_EffectPriority = 0;
Audio_EffectBank = 0;
Audio_EffectPointer3 = 0;
Audio_EffectPriority3 = 0;
Audio_EffectBank3 = 0;
Audio_EffectUsesCh2 = 0;
Audio_EffectPan = AUDIO_PAN_INHERIT;
Audio_EffectPan3 = AUDIO_PAN_INHERIT;
Audio_LastChMask = 0;
Audio_LastCh1Note = 0;
Audio_LastCh2Note = 0;
Audio_LastCh3Note = 0;
Audio_LastCh4Param = 0;
Audio_Ch1Duty = 2;
Audio_Ch2Duty = 2;
Audio_Ch1Env = 0xF1;
Audio_Ch2Env = 0xF2;
Audio_Ch4Env = 0xF1;
Audio_Ch4Param = 0x00;
Audio_Ch3Level = AUDIO_CH3_LEVEL_100;
Audio_Ch3Wave = AUDIO_WAVE_TRIANGLE;
Audio_Ch1Sweep = 0x00;
Audio_SetCustomWaveTriangle();
#ifdef AUDIO_EXCLUDE_WAVE_LOAD_API
Audio_ApplyWaveBytes(Audio_CustomWave);
#else
Audio_LoadWave(Audio_Ch3Wave);
#endif
Audio_Ch3Off();
}Audio_LoadCustomWave
複製 16 位元組至自訂波形快取與 CH3 波形 RAM。
語法
void __stackcall Audio_LoadCustomWave(const u8 *wave16);參數
wave1616 個可讀位元組;高、低半位元組依序編碼連續取樣值。忽略 NULL。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
複製後呼叫端可重用來源。函式寫入時停用 DAC,須由呼叫端重新觸發音符。
使用範例
// Compare a triangle preset with an original packed 32-sample pulse waveform.
#include "gb_sound_example.h"
__prg_rom u8 custom_wave[16]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0,0,0,0,0,0,0,0};
void main() {
sound_begin("WAVE PRESET CUSTOM");
Audio_SetMasterVolume(3,3);
Audio_LoadWave(AUDIO_WAVE_TRIANGLE);
Audio_Ch3NoteOn(33,AUDIO_CH3_LEVEL_100);
sound_wait(45); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
// Loading copies all sixteen bytes and enables the DAC without triggering a note.
Audio_LoadCustomWave(custom_wave);
sound_result[0]=Audio_CustomWave[0]; sound_result[1]=Audio_CustomWave[8];
Audio_Ch3NoteOn(33,AUDIO_CH3_LEVEL_100);
sound_wait(45); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
// The cache survives another preset load; select CUSTOM to reuse it.
Audio_LoadWave(AUDIO_WAVE_SAW);
Audio_LoadWave(AUDIO_WAVE_CUSTOM);
sound_result[2]=WAVE0; sound_result[3]=WAVE8;
Audio_Ch3NoteOn(33,AUDIO_CH3_LEVEL_100);
sound_wait(45); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
sound_end();
}預期結果
依序聽到三角波預設、原創脈波,以及從快取重新載入的同一脈波。各持續 45 影格,間隔 15 影格。三者皆約 220 Hz,只有第一個音色不同。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_wave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-wave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:138
Copy 16 packed sample bytes into the persistent custom cache and wave RAM. A null pointer is ignored; the source is needed only for this call.
kitaqgb/lib/audio.c:614
void __stackcall Audio_LoadCustomWave(const u8 *wave16) {
if (wave16 == 0) return;
Audio_CustomWave[0] = wave16[0]; Audio_CustomWave[1] = wave16[1];
Audio_CustomWave[2] = wave16[2]; Audio_CustomWave[3] = wave16[3];
Audio_CustomWave[4] = wave16[4]; Audio_CustomWave[5] = wave16[5];
Audio_CustomWave[6] = wave16[6]; Audio_CustomWave[7] = wave16[7];
Audio_CustomWave[8] = wave16[8]; Audio_CustomWave[9] = wave16[9];
Audio_CustomWave[10] = wave16[10]; Audio_CustomWave[11] = wave16[11];
Audio_CustomWave[12] = wave16[12]; Audio_CustomWave[13] = wave16[13];
Audio_CustomWave[14] = wave16[14]; Audio_CustomWave[15] = wave16[15];
Audio_ApplyWaveBytes(Audio_CustomWave);
}Audio_LoadWave
將預設或快取的自訂波形寫入 CH3 波形 RAM。
語法
void __stackcall Audio_LoadWave(u8 wave_id);參數
wave_idAUDIO_WAVE_* ID 0..7;7 選擇快取的自訂波形。大於 7 不執行任何操作。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
載入不會發聲或改變 Audio_Ch3Wave。三角波預設也會將自訂快取重設為三角波。請呼叫 Audio_Ch3NoteOn 觸發聲音。
使用範例
// Compare a triangle preset with an original packed 32-sample pulse waveform.
#include "gb_sound_example.h"
__prg_rom u8 custom_wave[16]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0,0,0,0,0,0,0,0};
void main() {
sound_begin("WAVE PRESET CUSTOM");
Audio_SetMasterVolume(3,3);
Audio_LoadWave(AUDIO_WAVE_TRIANGLE);
Audio_Ch3NoteOn(33,AUDIO_CH3_LEVEL_100);
sound_wait(45); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
// Loading copies all sixteen bytes and enables the DAC without triggering a note.
Audio_LoadCustomWave(custom_wave);
sound_result[0]=Audio_CustomWave[0]; sound_result[1]=Audio_CustomWave[8];
Audio_Ch3NoteOn(33,AUDIO_CH3_LEVEL_100);
sound_wait(45); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
// The cache survives another preset load; select CUSTOM to reuse it.
Audio_LoadWave(AUDIO_WAVE_SAW);
Audio_LoadWave(AUDIO_WAVE_CUSTOM);
sound_result[2]=WAVE0; sound_result[3]=WAVE8;
Audio_Ch3NoteOn(33,AUDIO_CH3_LEVEL_100);
sound_wait(45); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
sound_end();
}預期結果
依序聽到三角波預設、原創脈波,以及從快取重新載入的同一脈波。各持續 45 影格,間隔 15 影格。三者皆約 220 Hz,只有第一個音色不同。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_wave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-wave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:135
Install a named preset or the cached custom wave. Unknown IDs are ignored. This does not update Audio_Ch3Wave or trigger a new note.
kitaqgb/lib/audio.c:631
void __stackcall Audio_LoadWave(u8 wave_id) {
if (wave_id == AUDIO_WAVE_TRIANGLE) Audio_LoadWave0();
else if (wave_id == AUDIO_WAVE_SAW) Audio_LoadWave1();
else if (wave_id == AUDIO_WAVE_VOWEL_A) Audio_LoadWave2();
else if (wave_id == AUDIO_WAVE_VOWEL_I) Audio_LoadWave3();
else if (wave_id == AUDIO_WAVE_VOWEL_U) Audio_LoadWave4();
else if (wave_id == AUDIO_WAVE_VOWEL_E) Audio_LoadWave5();
else if (wave_id == AUDIO_WAVE_VOWEL_O) Audio_LoadWave6();
else if (wave_id == AUDIO_WAVE_CUSTOM) Audio_ApplyWaveBytes(Audio_CustomWave);
}Audio_PlayMusic
準備從頭播放指定記憶體庫的歌曲,並重設樂器、聲像與 delay。
語法
void __stackcall Audio_PlayMusic(u8 bank, u8 *song);參數
bank串流所在的 ROM 記憶體庫,須符合實際位置。
song歌曲起始位址。驅動借用此陣列,播放期間必須始終可讀。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
請先引入 audio_hwregs_gb.c 再引入 audio.c,並在啟動時呼叫 Audio_Init。每影格恰好呼叫 Audio_Update 一次,約 59.7 Hz。讀取串流會暫時改變 ROM 映射,勿從中斷重入此驅動。
下一次 Audio_Update 才讀取資料。不檢查 NULL。既有效果仍維持啟用。
使用範例
// Original two-note phrase: pause preserves the cursor; the enable gate does not.
#include "gb_sound_example.h"
__prg_rom u8 song[]={
AUDIO_CMD_SET_INST,AUDIO_STREAM_CHANNEL_CH1,2,0xC0,
AUDIO_CMD_NOTE,AUDIO_STREAM_CHANNEL_CH1,33,AUDIO_CMD_WAIT,59,
AUDIO_CMD_NOTE,AUDIO_STREAM_CHANNEL_CH1,40,AUDIO_CMD_WAIT,59,
AUDIO_CMD_LOOP
};
void main() {
u8 delay;
sound_begin("MUSIC PAUSE GATE");
Audio_SetMasterVolume(3,3);
Audio_PlayMusic(0,song);
sound_wait(30);
delay=Audio_Delay;
Audio_SetPaused(1);
sound_wait(30);
sound_result[0]=(u8)(Audio_Delay==delay);
sound_result[1]=Audio_Paused;
Audio_SetPaused(0);
sound_wait(30);
sound_result[2]=Audio_Paused;
// Disabling suppresses note writes; the next 30 updates still consume data.
Audio_SetMusicEnabled(0);
sound_wait(30);
sound_result[3]=Audio_Delay;
sound_result[4]=Audio_MusicEnabled;
// Explicitly stop the sounding channel while leaving the stream running.
Audio_StopChannel(AUDIO_CHANNEL_CH1);
sound_wait(30);
Audio_SetMusicEnabled(1);
sound_wait(30);
Audio_StopMusic();
sound_result[5]=Audio_PlayingMusic;
sound_wait(30);
sound_end();
}預期結果
依序聽到音符、暫停靜音、恢復、停用音樂時保留的音符、明確關閉通道、重新啟用後的下一音符,最後停止。RAM 也驗證暫停期間 30 次更新保留 delay,而停用開關仍使其推進至 30。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_music.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-music.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:83
Retain the bank and song pointer, reset legacy instruments/cursors, and arm playback from the beginning. Supply a valid, persistent song; no bytes are copied and null is not checked. Existing effect streams remain active.
kitaqgb/lib/audio.c:924
void __stackcall Audio_PlayMusic(u8 bank, u8 *song) {
Audio_PlayingMusic = 0;
Audio_MusicBank = bank;
Audio_MusicPointer = song;
Audio_MusicLoopPoint = song;
Audio_Delay = 0;
Audio_LastChMask = 0;
Audio_Ch1Duty = 2;
Audio_Ch2Duty = 2;
Audio_Ch1Env = 0xF1;
Audio_Ch2Env = 0xF2;
Audio_Ch4Env = 0xF1;
Audio_Ch4Param = 0x00;
Audio_Ch3Level = AUDIO_CH3_LEVEL_100;
Audio_Ch3Wave = AUDIO_WAVE_TRIANGLE;
Audio_Ch1Sweep = 0x00;
Audio_Pan = 0xFF;
Audio_UpdateNR51();
Audio_LoadWave(Audio_Ch3Wave);
Audio_PlayingMusic = 1;
}Audio_PlaySFX
擷取目前 ROM 記憶體庫,並請求沿用基本聲像的效果。
語法
void __stackcall Audio_PlaySFX(u8 *sfx, u8 priority);參數
sfx效果位元組串流起點。脈波與 CH3 格式請參閱注意事項。
priority優先權 0..255。數值越大優先;相同值也可取代目前效果。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
效果每次更新消耗一組 (note,value),遇到 note=0 結束。脈波效果的 value 為 NR12,CH3 則為 NR32。CH3 資料前須加上 0xFF,且儲存空間須保留至播放完成。優先權在同一槽內競爭,相同優先權也可取代目前效果。
一般設定下,釋放效果會關閉 CH3。音樂停止時也會使 CH1 靜音,但音樂播放中不會自動重播先前音符。使用 AUDIO_VBLANK_SFX_RESTORE 時,釋放會要求 ISR 恢復音樂。
使用範例
// Each pair lasts one update. Priority controls replacement within each slot.
#include "gb_sound_example.h"
#pragma bank 2
__prg_rom u8 effect[]={33,0xC0,33,0xC0,33,0xC0,33,0xC0,33,0xC0,33,0xC0,
40,0xC0,40,0xC0,40,0xC0,40,0xC0,40,0xC0,40,0xC0,0};
__prg_rom u8 wave_effect[]={AUDIO_SFX_CH3_MARKER,
33,0x20,33,0x20,33,0x20,33,0x20,33,0x20,33,0x20,
40,0x20,40,0x20,40,0x20,40,0x20,40,0x20,40,0x20,0};
#pragma bank 0
void main() {
sound_begin("BANKED SOUND EFFECT");
Audio_SetMasterVolume(3,3);
// Read the marker in bank 2 while restoring the caller's original mapping.
Audio_PlaySFXPannedBanked(2,effect,5,AUDIO_PAN_LEFT);
sound_result[0]=Audio_EffectPriority;
Audio_PlaySFXBanked(2,effect,4);
sound_result[1]=Audio_EffectPriority;
sound_wait(30);
Audio_PlaySFXPannedBanked(2,wave_effect,5,AUDIO_PAN_RIGHT);
sound_result[2]=Audio_EffectPriority3;
sound_wait(30);
// Implicit-bank entry points capture bank 2; the service restores bank 1.
__bankswitch(2);
Audio_PlaySFX(effect,5);
__bankswitch(1);
sound_result[3]=Audio_EffectBank;
sound_wait(30);
__bankswitch(2);
Audio_PlaySFXPanned(effect,5,AUDIO_PAN_RIGHT);
__bankswitch(1);
sound_wait(6);
Audio_StopSfx();
sound_result[4]=(u8)(Audio_EffectPointer==0);
sound_wait(24);
// Disabling effects releases current owners; re-enable before the next request.
Audio_PlaySFXBanked(2,effect,5);
sound_wait(6);
Audio_SetSfxEnabled(0);
sound_result[5]=Audio_SfxEnabled;
sound_result[6]=(u8)(Audio_EffectPointer==0);
sound_wait(24);
Audio_SetSfxEnabled(1);
Audio_PlaySFXBanked(2,effect,5);
sound_wait(30);
sound_result[7]=Audio_SfxEnabled;
sound_end();
}預期結果
記憶體庫 2 資料播放左側短促上升脈波、右側波形效果及中央脈波。後續範例提早停止右側脈波、停用效果,再重新啟用播放。優先權 4 的請求無法取代 5。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_sfx.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-sfx.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:93
Capture the currently mapped ROM bank and start an effect with inherited pan. Use the explicit-bank API when the pointer belongs to another bank.
kitaqgb/lib/audio.c:1085
void __stackcall Audio_PlaySFX(u8 *sfx, u8 priority) {
Audio_PlaySFXBanked(__rom_bank, sfx, priority);
}Audio_PlaySFXBanked
在明確指定的來源記憶體庫中辨識效果格式,並請求以基本聲像播放。
語法
void __stackcall Audio_PlaySFXBanked(u8 bank, u8 *sfx, u8 priority);參數
bank串流所在的 ROM 記憶體庫,須符合實際位置。
sfx效果位元組串流起點。脈波與 CH3 格式請參閱注意事項。
priority優先權 0..255。數值越大優先;相同值也可取代目前效果。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
效果每次更新消耗一組 (note,value),遇到 note=0 結束。脈波效果的 value 為 NR12,CH3 則為 NR32。CH3 資料前須加上 0xFF,且儲存空間須保留至播放完成。優先權在同一槽內競爭,相同優先權也可取代目前效果。
一般設定下,釋放效果會關閉 CH3。音樂停止時也會使 CH1 靜音,但音樂播放中不會自動重播先前音符。使用 AUDIO_VBLANK_SFX_RESTORE 時,釋放會要求 ISR 恢復音樂。
使用範例
// Each pair lasts one update. Priority controls replacement within each slot.
#include "gb_sound_example.h"
#pragma bank 2
__prg_rom u8 effect[]={33,0xC0,33,0xC0,33,0xC0,33,0xC0,33,0xC0,33,0xC0,
40,0xC0,40,0xC0,40,0xC0,40,0xC0,40,0xC0,40,0xC0,0};
__prg_rom u8 wave_effect[]={AUDIO_SFX_CH3_MARKER,
33,0x20,33,0x20,33,0x20,33,0x20,33,0x20,33,0x20,
40,0x20,40,0x20,40,0x20,40,0x20,40,0x20,40,0x20,0};
#pragma bank 0
void main() {
sound_begin("BANKED SOUND EFFECT");
Audio_SetMasterVolume(3,3);
// Read the marker in bank 2 while restoring the caller's original mapping.
Audio_PlaySFXPannedBanked(2,effect,5,AUDIO_PAN_LEFT);
sound_result[0]=Audio_EffectPriority;
Audio_PlaySFXBanked(2,effect,4);
sound_result[1]=Audio_EffectPriority;
sound_wait(30);
Audio_PlaySFXPannedBanked(2,wave_effect,5,AUDIO_PAN_RIGHT);
sound_result[2]=Audio_EffectPriority3;
sound_wait(30);
// Implicit-bank entry points capture bank 2; the service restores bank 1.
__bankswitch(2);
Audio_PlaySFX(effect,5);
__bankswitch(1);
sound_result[3]=Audio_EffectBank;
sound_wait(30);
__bankswitch(2);
Audio_PlaySFXPanned(effect,5,AUDIO_PAN_RIGHT);
__bankswitch(1);
sound_wait(6);
Audio_StopSfx();
sound_result[4]=(u8)(Audio_EffectPointer==0);
sound_wait(24);
// Disabling effects releases current owners; re-enable before the next request.
Audio_PlaySFXBanked(2,effect,5);
sound_wait(6);
Audio_SetSfxEnabled(0);
sound_result[5]=Audio_SfxEnabled;
sound_result[6]=(u8)(Audio_EffectPointer==0);
sound_wait(24);
Audio_SetSfxEnabled(1);
Audio_PlaySFXBanked(2,effect,5);
sound_wait(30);
sound_result[7]=Audio_SfxEnabled;
sound_end();
}預期結果
記憶體庫 2 資料播放左側短促上升脈波、右側波形效果及中央脈波。後續範例提早停止右側脈波、停用效果,再重新啟用播放。優先權 4 的請求無法取代 5。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_sfx.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-sfx.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:95
Start a banked effect with the channel's base pan, subject to priority arbitration.
kitaqgb/lib/audio.c:1078
void __stackcall Audio_PlaySFXBanked(u8 bank, u8 *sfx, u8 priority) {
Audio_PlaySFXPannedBanked(bank, sfx, priority, AUDIO_PAN_INHERIT);
}Audio_PlaySFXPanned
擷取目前 ROM 記憶體庫,並請求覆寫聲像的效果。
語法
void __stackcall Audio_PlaySFXPanned(u8 *sfx, u8 priority, u8 pan);參數
sfx效果位元組串流起點。脈波與 CH3 格式請參閱注意事項。
priority優先權 0..255。數值越大優先;相同值也可取代目前效果。
pan0=中央、1=左、2=右、3=靜音。效果 API 將大於 3 的值(含 0xFF)視為沿用基本聲像。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
效果每次更新消耗一組 (note,value),遇到 note=0 結束。脈波效果的 value 為 NR12,CH3 則為 NR32。CH3 資料前須加上 0xFF,且儲存空間須保留至播放完成。優先權在同一槽內競爭,相同優先權也可取代目前效果。
一般設定下,釋放效果會關閉 CH3。音樂停止時也會使 CH1 靜音,但音樂播放中不會自動重播先前音符。使用 AUDIO_VBLANK_SFX_RESTORE 時,釋放會要求 ISR 恢復音樂。
使用範例
// Each pair lasts one update. Priority controls replacement within each slot.
#include "gb_sound_example.h"
#pragma bank 2
__prg_rom u8 effect[]={33,0xC0,33,0xC0,33,0xC0,33,0xC0,33,0xC0,33,0xC0,
40,0xC0,40,0xC0,40,0xC0,40,0xC0,40,0xC0,40,0xC0,0};
__prg_rom u8 wave_effect[]={AUDIO_SFX_CH3_MARKER,
33,0x20,33,0x20,33,0x20,33,0x20,33,0x20,33,0x20,
40,0x20,40,0x20,40,0x20,40,0x20,40,0x20,40,0x20,0};
#pragma bank 0
void main() {
sound_begin("BANKED SOUND EFFECT");
Audio_SetMasterVolume(3,3);
// Read the marker in bank 2 while restoring the caller's original mapping.
Audio_PlaySFXPannedBanked(2,effect,5,AUDIO_PAN_LEFT);
sound_result[0]=Audio_EffectPriority;
Audio_PlaySFXBanked(2,effect,4);
sound_result[1]=Audio_EffectPriority;
sound_wait(30);
Audio_PlaySFXPannedBanked(2,wave_effect,5,AUDIO_PAN_RIGHT);
sound_result[2]=Audio_EffectPriority3;
sound_wait(30);
// Implicit-bank entry points capture bank 2; the service restores bank 1.
__bankswitch(2);
Audio_PlaySFX(effect,5);
__bankswitch(1);
sound_result[3]=Audio_EffectBank;
sound_wait(30);
__bankswitch(2);
Audio_PlaySFXPanned(effect,5,AUDIO_PAN_RIGHT);
__bankswitch(1);
sound_wait(6);
Audio_StopSfx();
sound_result[4]=(u8)(Audio_EffectPointer==0);
sound_wait(24);
// Disabling effects releases current owners; re-enable before the next request.
Audio_PlaySFXBanked(2,effect,5);
sound_wait(6);
Audio_SetSfxEnabled(0);
sound_result[5]=Audio_SfxEnabled;
sound_result[6]=(u8)(Audio_EffectPointer==0);
sound_wait(24);
Audio_SetSfxEnabled(1);
Audio_PlaySFXBanked(2,effect,5);
sound_wait(30);
sound_result[7]=Audio_SfxEnabled;
sound_end();
}預期結果
記憶體庫 2 資料播放左側短促上升脈波、右側波形效果及中央脈波。後續範例提早停止右側脈波、停用效果,再重新啟用播放。優先權 4 的請求無法取代 5。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_sfx.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-sfx.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:98
Capture the currently mapped ROM bank and request an effect with a pan override. Use the explicit-bank API when the pointer belongs to another bank.
kitaqgb/lib/audio.c:1091
void __stackcall Audio_PlaySFXPanned(u8 *sfx, u8 priority, u8 pan) {
Audio_PlaySFXPannedBanked(__rom_bank, sfx, priority, pan);
}Audio_PlaySFXPannedBanked
明確指定記憶體庫、優先權與聲像,取得脈波或 CH3 效果槽。
語法
void __stackcall Audio_PlaySFXPannedBanked(u8 bank, u8 *sfx, u8 priority, u8 pan);參數
bank串流所在的 ROM 記憶體庫,須符合實際位置。
sfx效果位元組串流起點。脈波與 CH3 格式請參閱注意事項。
priority優先權 0..255。數值越大優先;相同值也可取代目前效果。
pan0=中央、1=左、2=右、3=靜音。效果 API 將大於 3 的值(含 0xFF)視為沿用基本聲像。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
效果每次更新消耗一組 (note,value),遇到 note=0 結束。脈波效果的 value 為 NR12,CH3 則為 NR32。CH3 資料前須加上 0xFF,且儲存空間須保留至播放完成。優先權在同一槽內競爭,相同優先權也可取代目前效果。
一般設定下,釋放效果會關閉 CH3。音樂停止時也會使 CH1 靜音,但音樂播放中不會自動重播先前音符。使用 AUDIO_VBLANK_SFX_RESTORE 時,釋放會要求 ISR 恢復音樂。
使用範例
// Each pair lasts one update. Priority controls replacement within each slot.
#include "gb_sound_example.h"
#pragma bank 2
__prg_rom u8 effect[]={33,0xC0,33,0xC0,33,0xC0,33,0xC0,33,0xC0,33,0xC0,
40,0xC0,40,0xC0,40,0xC0,40,0xC0,40,0xC0,40,0xC0,0};
__prg_rom u8 wave_effect[]={AUDIO_SFX_CH3_MARKER,
33,0x20,33,0x20,33,0x20,33,0x20,33,0x20,33,0x20,
40,0x20,40,0x20,40,0x20,40,0x20,40,0x20,40,0x20,0};
#pragma bank 0
void main() {
sound_begin("BANKED SOUND EFFECT");
Audio_SetMasterVolume(3,3);
// Read the marker in bank 2 while restoring the caller's original mapping.
Audio_PlaySFXPannedBanked(2,effect,5,AUDIO_PAN_LEFT);
sound_result[0]=Audio_EffectPriority;
Audio_PlaySFXBanked(2,effect,4);
sound_result[1]=Audio_EffectPriority;
sound_wait(30);
Audio_PlaySFXPannedBanked(2,wave_effect,5,AUDIO_PAN_RIGHT);
sound_result[2]=Audio_EffectPriority3;
sound_wait(30);
// Implicit-bank entry points capture bank 2; the service restores bank 1.
__bankswitch(2);
Audio_PlaySFX(effect,5);
__bankswitch(1);
sound_result[3]=Audio_EffectBank;
sound_wait(30);
__bankswitch(2);
Audio_PlaySFXPanned(effect,5,AUDIO_PAN_RIGHT);
__bankswitch(1);
sound_wait(6);
Audio_StopSfx();
sound_result[4]=(u8)(Audio_EffectPointer==0);
sound_wait(24);
// Disabling effects releases current owners; re-enable before the next request.
Audio_PlaySFXBanked(2,effect,5);
sound_wait(6);
Audio_SetSfxEnabled(0);
sound_result[5]=Audio_SfxEnabled;
sound_result[6]=(u8)(Audio_EffectPointer==0);
sound_wait(24);
Audio_SetSfxEnabled(1);
Audio_PlaySFXBanked(2,effect,5);
sound_wait(30);
sound_result[7]=Audio_SfxEnabled;
sound_end();
}預期結果
記憶體庫 2 資料播放左側短促上升脈波、右側波形效果及中央脈波。後續範例提早停止右側脈波、停用效果,再重新啟用播放。優先權 4 的請求無法取代 5。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_sfx.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-sfx.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:103
Retain a banked effect stream if its priority equals or exceeds the current owner's priority, or that slot is empty. A leading CH3 marker selects the wave slot and is skipped; other streams use the pulse slot. Paused requests are ignored. Keep stream storage valid until completion; acceptance does not trigger a note.
kitaqgb/lib/audio.c:1041
void __stackcall Audio_PlaySFXPannedBanked(u8 bank, u8 *sfx, u8 priority, u8 pan) {
u8 sfx_pan = pan;
u8 use_ch3 = 0;
if (sfx_pan > AUDIO_PAN_MUTE) sfx_pan = AUDIO_PAN_INHERIT;
if (Audio_Paused != 0) return;
if (sfx != 0) {
use_ch3 = Audio_SfxStartsOnCh3Banked(bank, sfx);
if (use_ch3 != 0) {
if (Audio_EffectPointer3 == 0 || priority >= Audio_EffectPriority3) {
Audio_EffectPointer3 = sfx + 1;
Audio_EffectPriority3 = priority;
Audio_EffectBank3 = bank;
Audio_EffectPan3 = sfx_pan;
Audio_UpdateNR51();
}
return;
}
}
if (Audio_EffectPointer == 0 || priority >= Audio_EffectPriority) {
#ifdef AUDIO_VBLANK_SFX_AUTO_CH2
// Choose pulse-channel ownership when accepting the effect, so its later
// updates and deferred recovery agree on which physical channel was borrowed.
Audio_EffectUsesCh2 = (u8)(AudioVBlank_MusicPlaying != 0 &&
AudioVBlank_MusicEnabled != 0);
#else
Audio_EffectUsesCh2 = 0;
#endif
Audio_EffectPointer = sfx;
Audio_EffectPriority = priority;
Audio_EffectBank = bank;
Audio_EffectPan = sfx_pan;
Audio_UpdateNR51();
}
}Audio_SetCh1Duty
快取下一個 CH1 音符的工作週期索引。
語法
void __stackcall Audio_SetCh1Duty(u8 duty);參數
duty脈波工作週期索引,儲存低兩位元。0=12.5%、1=25%、2=50%、3=75%。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
此呼叫本身不改變目前音效暫存器。須將快取值傳給發聲函式,或使用對應串流才能套用。
使用範例
// Four isolated voices, each lasting 30 frames, separated by 15 silent frames.
#include "gb_sound_example.h"
void main() {
sound_begin("FOUR SOUND CHANNELS");
Audio_SetMasterVolume(3,3);
// CH1: A4, 50% duty, fixed envelope volume 12.
Audio_SetCh1Duty(2);
sound_result[0]=Audio_Ch1Duty;
Audio_Ch1NoteOn(33,0xC0,Audio_Ch1Duty);
sound_result[1]=NR12;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH1); sound_wait(15);
// CH2: A4, 25% duty. Changing the cached duty takes effect on this trigger.
Audio_SetCh2Duty(1);
sound_result[2]=Audio_Ch2Duty;
Audio_Ch2NoteOn(33,0xC0,Audio_Ch2Duty);
sound_result[3]=NR22;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH2); sound_wait(15);
// CH3: the initialized triangle wave, at 50% digital output level.
Audio_SetCh3Level(AUDIO_CH3_LEVEL_50);
sound_result[4]=Audio_Ch3Level;
Audio_Ch3NoteOn(33,Audio_Ch3Level);
sound_result[5]=NR32;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
// CH4: a sustained noise burst; param is NR43, not a pitched note number.
Audio_SetCh4Param(0x35);
sound_result[6]=Audio_Ch4Param;
Audio_Ch4NoteOn(Audio_Ch4Param,0xC0);
sound_result[7]=NR43;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH4); sound_wait(15);
sound_end();
}預期結果
約半秒靜音後,依序聽到 CH1 A4、CH2 A4、CH3 A3 與雜訊。每個聲音持續 30 影格,中間間隔 15 影格。SEQUENCE COMPLETE 表示程式完成;請用錄音判斷聲音。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_channels.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-channels.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:141
Cache the low two duty bits for the next CH1 note; do not change the active register.
kitaqgb/lib/audio.c:644
void __stackcall Audio_SetCh1Duty(u8 duty) {
Audio_Ch1Duty = (u8)(duty & 3);
}Audio_SetCh2Duty
快取下一個 CH2 音符的工作週期索引。
語法
void __stackcall Audio_SetCh2Duty(u8 duty);參數
duty脈波工作週期索引,儲存低兩位元。0=12.5%、1=25%、2=50%、3=75%。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
此呼叫本身不改變目前音效暫存器。須將快取值傳給發聲函式,或使用對應串流才能套用。
使用範例
// Four isolated voices, each lasting 30 frames, separated by 15 silent frames.
#include "gb_sound_example.h"
void main() {
sound_begin("FOUR SOUND CHANNELS");
Audio_SetMasterVolume(3,3);
// CH1: A4, 50% duty, fixed envelope volume 12.
Audio_SetCh1Duty(2);
sound_result[0]=Audio_Ch1Duty;
Audio_Ch1NoteOn(33,0xC0,Audio_Ch1Duty);
sound_result[1]=NR12;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH1); sound_wait(15);
// CH2: A4, 25% duty. Changing the cached duty takes effect on this trigger.
Audio_SetCh2Duty(1);
sound_result[2]=Audio_Ch2Duty;
Audio_Ch2NoteOn(33,0xC0,Audio_Ch2Duty);
sound_result[3]=NR22;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH2); sound_wait(15);
// CH3: the initialized triangle wave, at 50% digital output level.
Audio_SetCh3Level(AUDIO_CH3_LEVEL_50);
sound_result[4]=Audio_Ch3Level;
Audio_Ch3NoteOn(33,Audio_Ch3Level);
sound_result[5]=NR32;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
// CH4: a sustained noise burst; param is NR43, not a pitched note number.
Audio_SetCh4Param(0x35);
sound_result[6]=Audio_Ch4Param;
Audio_Ch4NoteOn(Audio_Ch4Param,0xC0);
sound_result[7]=NR43;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH4); sound_wait(15);
sound_end();
}預期結果
約半秒靜音後,依序聽到 CH1 A4、CH2 A4、CH3 A3 與雜訊。每個聲音持續 30 影格,中間間隔 15 影格。SEQUENCE COMPLETE 表示程式完成;請用錄音判斷聲音。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_channels.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-channels.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:143
Cache the low two duty bits for the next CH2 note; do not change the active register.
kitaqgb/lib/audio.c:649
void __stackcall Audio_SetCh2Duty(u8 duty) {
Audio_Ch2Duty = (u8)(duty & 3);
}Audio_SetCh3Level
快取下一個 CH3 音符的 NR32 輸出音量。
語法
void __stackcall Audio_SetCh3Level(u8 level);參數
levelNR32 編碼:0x00=靜音、0x20=100%、0x40=50%、0x60=25%。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
此呼叫本身不改變目前音效暫存器。須將快取值傳給發聲函式,或使用對應串流才能套用。
使用範例
// Four isolated voices, each lasting 30 frames, separated by 15 silent frames.
#include "gb_sound_example.h"
void main() {
sound_begin("FOUR SOUND CHANNELS");
Audio_SetMasterVolume(3,3);
// CH1: A4, 50% duty, fixed envelope volume 12.
Audio_SetCh1Duty(2);
sound_result[0]=Audio_Ch1Duty;
Audio_Ch1NoteOn(33,0xC0,Audio_Ch1Duty);
sound_result[1]=NR12;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH1); sound_wait(15);
// CH2: A4, 25% duty. Changing the cached duty takes effect on this trigger.
Audio_SetCh2Duty(1);
sound_result[2]=Audio_Ch2Duty;
Audio_Ch2NoteOn(33,0xC0,Audio_Ch2Duty);
sound_result[3]=NR22;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH2); sound_wait(15);
// CH3: the initialized triangle wave, at 50% digital output level.
Audio_SetCh3Level(AUDIO_CH3_LEVEL_50);
sound_result[4]=Audio_Ch3Level;
Audio_Ch3NoteOn(33,Audio_Ch3Level);
sound_result[5]=NR32;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
// CH4: a sustained noise burst; param is NR43, not a pitched note number.
Audio_SetCh4Param(0x35);
sound_result[6]=Audio_Ch4Param;
Audio_Ch4NoteOn(Audio_Ch4Param,0xC0);
sound_result[7]=NR43;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH4); sound_wait(15);
sound_end();
}預期結果
約半秒靜音後,依序聽到 CH1 A4、CH2 A4、CH3 A3 與雜訊。每個聲音持續 30 影格,中間間隔 15 影格。SEQUENCE COMPLETE 表示程式完成;請用錄音判斷聲音。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_channels.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-channels.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:145
Cache the raw NR32 level encoding for the next CH3 note without writing hardware.
kitaqgb/lib/audio.c:654
void __stackcall Audio_SetCh3Level(u8 level) {
Audio_Ch3Level = level;
}Audio_SetCh4Param
快取下一個 CH4 音符的 NR43 雜訊參數。
語法
void __stackcall Audio_SetCh4Param(u8 param);參數
param原始 NR43:位元 7..4 為時脈移位,位元 3 為短 LFSR,位元 2..0 為除數代碼。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
此呼叫本身不改變目前音效暫存器。須將快取值傳給發聲函式,或使用對應串流才能套用。
使用範例
// Four isolated voices, each lasting 30 frames, separated by 15 silent frames.
#include "gb_sound_example.h"
void main() {
sound_begin("FOUR SOUND CHANNELS");
Audio_SetMasterVolume(3,3);
// CH1: A4, 50% duty, fixed envelope volume 12.
Audio_SetCh1Duty(2);
sound_result[0]=Audio_Ch1Duty;
Audio_Ch1NoteOn(33,0xC0,Audio_Ch1Duty);
sound_result[1]=NR12;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH1); sound_wait(15);
// CH2: A4, 25% duty. Changing the cached duty takes effect on this trigger.
Audio_SetCh2Duty(1);
sound_result[2]=Audio_Ch2Duty;
Audio_Ch2NoteOn(33,0xC0,Audio_Ch2Duty);
sound_result[3]=NR22;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH2); sound_wait(15);
// CH3: the initialized triangle wave, at 50% digital output level.
Audio_SetCh3Level(AUDIO_CH3_LEVEL_50);
sound_result[4]=Audio_Ch3Level;
Audio_Ch3NoteOn(33,Audio_Ch3Level);
sound_result[5]=NR32;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
// CH4: a sustained noise burst; param is NR43, not a pitched note number.
Audio_SetCh4Param(0x35);
sound_result[6]=Audio_Ch4Param;
Audio_Ch4NoteOn(Audio_Ch4Param,0xC0);
sound_result[7]=NR43;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH4); sound_wait(15);
sound_end();
}預期結果
約半秒靜音後,依序聽到 CH1 A4、CH2 A4、CH3 A3 與雜訊。每個聲音持續 30 影格,中間間隔 15 影格。SEQUENCE COMPLETE 表示程式完成;請用錄音判斷聲音。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_channels.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-channels.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:147
Cache the raw noise polynomial encoding for the next CH4 note without writing hardware.
kitaqgb/lib/audio.c:659
void __stackcall Audio_SetCh4Param(u8 param) {
Audio_Ch4Param = param;
}Audio_SetMasterVolume
將左右主音量限制在 0..7,立即寫入,並取消進行中的淡入淡出。
語法
void __stackcall Audio_SetMasterVolume(u8 left, u8 right);參數
left左側主音量 0..7,較大值限制為 7。零並非完全靜音。
right右側主音量 0..7,較大值限制為 7。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用範例
// A sustained pulse moves left, right and center, then fades to a quieter level.
#include "gb_sound_example.h"
void main() {
sound_begin("PAN AND VOLUME");
Audio_SetMasterVolume(7,7);
Audio_Ch1NoteOn(33,0xC0,2);
Audio_SetPan(AUDIO_CHANNEL_CH1,AUDIO_PAN_LEFT);
sound_result[0]=NR51;
sound_wait(30);
// Packed low two bits are CH1: 2 means right. Other channels remain centered.
Audio_SetPanPacked(2);
sound_result[1]=NR51;
sound_wait(30);
Audio_SetPanPacked(0);
sound_result[2]=NR51;
Audio_FadeToMasterVolume(1,1,5);
sound_wait(30);
sound_result[3]=NR50;
sound_result[4]=Audio_FadeActive;
sound_wait(30);
// Cancel halfway through a rise: retain volume 4 instead of reaching 7.
Audio_FadeToMasterVolume(7,7,5);
sound_wait(15);
Audio_CancelMasterVolumeFade();
sound_result[5]=NR50;
sound_wait(30);
sound_result[6]=NR50;
// A zero fade interval sets the target immediately. Level zero is not mute.
Audio_FadeToMasterVolume(0,0,0);
sound_result[7]=NR50;
sound_wait(30);
Audio_StopChannel(AUDIO_CHANNEL_CH1);
sound_wait(15);
sound_end();
}預期結果
A4 依序移至左、右、中央。在中央從等級 7 淡出至 1,再升至 4 並保持。等級 0 仍可微弱聽見;停止通道才會靜音。改變路由後,可能留下逐漸衰減的濾波器暫態聲。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_mix.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-mix.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:120
Clamp both output levels to 0..7, cancel any fade, and write NR50 immediately.
kitaqgb/lib/audio.c:515
void __stackcall Audio_SetMasterVolume(u8 left, u8 right) {
Audio_MasterLeft = Audio_ClampVolume(left);
Audio_MasterRight = Audio_ClampVolume(right);
Audio_FadeTargetLeft = Audio_MasterLeft;
Audio_FadeTargetRight = Audio_MasterRight;
Audio_FadeStepFrames = 0;
Audio_FadeCounter = 0;
Audio_FadeActive = 0;
Audio_UpdateNR50();
}Audio_SetMusicEnabled
控制一般音樂解碼器是否寫入新音符。
語法
void __stackcall Audio_SetMusicEnabled(u8 on);參數
on零停用,非零啟用。請依此函式說明區分靜音與停止更新。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
停用後串流仍前進,並處理樂器/聲像控制,不會使目前音符靜音。暫停播放請用 Audio_SetPaused。
使用範例
// Original two-note phrase: pause preserves the cursor; the enable gate does not.
#include "gb_sound_example.h"
__prg_rom u8 song[]={
AUDIO_CMD_SET_INST,AUDIO_STREAM_CHANNEL_CH1,2,0xC0,
AUDIO_CMD_NOTE,AUDIO_STREAM_CHANNEL_CH1,33,AUDIO_CMD_WAIT,59,
AUDIO_CMD_NOTE,AUDIO_STREAM_CHANNEL_CH1,40,AUDIO_CMD_WAIT,59,
AUDIO_CMD_LOOP
};
void main() {
u8 delay;
sound_begin("MUSIC PAUSE GATE");
Audio_SetMasterVolume(3,3);
Audio_PlayMusic(0,song);
sound_wait(30);
delay=Audio_Delay;
Audio_SetPaused(1);
sound_wait(30);
sound_result[0]=(u8)(Audio_Delay==delay);
sound_result[1]=Audio_Paused;
Audio_SetPaused(0);
sound_wait(30);
sound_result[2]=Audio_Paused;
// Disabling suppresses note writes; the next 30 updates still consume data.
Audio_SetMusicEnabled(0);
sound_wait(30);
sound_result[3]=Audio_Delay;
sound_result[4]=Audio_MusicEnabled;
// Explicitly stop the sounding channel while leaving the stream running.
Audio_StopChannel(AUDIO_CHANNEL_CH1);
sound_wait(30);
Audio_SetMusicEnabled(1);
sound_wait(30);
Audio_StopMusic();
sound_result[5]=Audio_PlayingMusic;
sound_wait(30);
sound_end();
}預期結果
依序聽到音符、暫停靜音、恢復、停用音樂時保留的音符、明確關閉通道、重新啟用後的下一音符,最後停止。RAM 也驗證暫停期間 30 次更新保留 delay,而停用開關仍使其推進至 30。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_music.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-music.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:114
Set the music-processing gate. This does not silence notes already playing or stop the legacy stream cursor from consuming commands.
kitaqgb/lib/audio.c:498
void __stackcall Audio_SetMusicEnabled(u8 on) {
if (on != 0) Audio_MusicEnabled = 1;
else Audio_MusicEnabled = 0;
}Audio_SetPan
改變一個實體聲部的基本聲像,再重新套用作用中效果的聲像覆寫。
語法
void __stackcall Audio_SetPan(u8 ch, u8 pan);參數
ch通道 ID:0=CH1、1=CH2、2=CH3、3=CH4。直接 API 與音樂串流使用相同 ID。
pan0=中央、1=左、2=右、3=靜音。效果 API 將大於 3 的值(含 0xFF)視為沿用基本聲像。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
未知通道選擇 CH4。此處 pan 超出 0..3 會靜音,不是效果 API 的沿用設定。
使用範例
// A sustained pulse moves left, right and center, then fades to a quieter level.
#include "gb_sound_example.h"
void main() {
sound_begin("PAN AND VOLUME");
Audio_SetMasterVolume(7,7);
Audio_Ch1NoteOn(33,0xC0,2);
Audio_SetPan(AUDIO_CHANNEL_CH1,AUDIO_PAN_LEFT);
sound_result[0]=NR51;
sound_wait(30);
// Packed low two bits are CH1: 2 means right. Other channels remain centered.
Audio_SetPanPacked(2);
sound_result[1]=NR51;
sound_wait(30);
Audio_SetPanPacked(0);
sound_result[2]=NR51;
Audio_FadeToMasterVolume(1,1,5);
sound_wait(30);
sound_result[3]=NR50;
sound_result[4]=Audio_FadeActive;
sound_wait(30);
// Cancel halfway through a rise: retain volume 4 instead of reaching 7.
Audio_FadeToMasterVolume(7,7,5);
sound_wait(15);
Audio_CancelMasterVolumeFade();
sound_result[5]=NR50;
sound_wait(30);
sound_result[6]=NR50;
// A zero fade interval sets the target immediately. Level zero is not mute.
Audio_FadeToMasterVolume(0,0,0);
sound_result[7]=NR50;
sound_wait(30);
Audio_StopChannel(AUDIO_CHANNEL_CH1);
sound_wait(15);
sound_end();
}預期結果
A4 依序移至左、右、中央。在中央從等級 7 淡出至 1,再升至 4 並保持。等級 0 仍可微弱聽見;停止通道才會靜音。改變路由後,可能留下逐漸衰減的濾波器暫態聲。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_mix.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-mix.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:129
Update the base pan for a physical channel and reapply active effect overrides. Unknown channel IDs select CH4; unsupported pan values mute the selected channel.
kitaqgb/lib/audio.c:558
void __stackcall Audio_SetPan(u8 ch, u8 pan) {
u8 r_bit;
u8 l_bit;
u8 mask;
if (ch == AUDIO_CHANNEL_CH1) {
r_bit = 0x01;
l_bit = 0x10;
} else if (ch == AUDIO_CHANNEL_CH2) {
r_bit = 0x02;
l_bit = 0x20;
} else if (ch == AUDIO_CHANNEL_CH3) {
r_bit = 0x04;
l_bit = 0x40;
} else {
r_bit = 0x08;
l_bit = 0x80;
}
mask = (u8)(l_bit | r_bit);
Audio_Pan = (u8)(Audio_Pan & (u8)~mask);
if (pan == AUDIO_PAN_CENTER) Audio_Pan = (u8)(Audio_Pan | mask);
else if (pan == AUDIO_PAN_LEFT) Audio_Pan = (u8)(Audio_Pan | l_bit);
else if (pan == AUDIO_PAN_RIGHT) Audio_Pan = (u8)(Audio_Pan | r_bit);
Audio_UpdateNR51();
}Audio_SetPanPacked
從一個位元組解出四個基本聲像設定,並更新 NR51 一次。
語法
void __stackcall Audio_SetPanPacked(u8 packed);參數
packed每個實體通道占兩位元:CH1 為 0..1、CH2 為 2..3、CH3 為 4..5、CH4 為 6..7。各欄位使用聲像值。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用範例
// A sustained pulse moves left, right and center, then fades to a quieter level.
#include "gb_sound_example.h"
void main() {
sound_begin("PAN AND VOLUME");
Audio_SetMasterVolume(7,7);
Audio_Ch1NoteOn(33,0xC0,2);
Audio_SetPan(AUDIO_CHANNEL_CH1,AUDIO_PAN_LEFT);
sound_result[0]=NR51;
sound_wait(30);
// Packed low two bits are CH1: 2 means right. Other channels remain centered.
Audio_SetPanPacked(2);
sound_result[1]=NR51;
sound_wait(30);
Audio_SetPanPacked(0);
sound_result[2]=NR51;
Audio_FadeToMasterVolume(1,1,5);
sound_wait(30);
sound_result[3]=NR50;
sound_result[4]=Audio_FadeActive;
sound_wait(30);
// Cancel halfway through a rise: retain volume 4 instead of reaching 7.
Audio_FadeToMasterVolume(7,7,5);
sound_wait(15);
Audio_CancelMasterVolumeFade();
sound_result[5]=NR50;
sound_wait(30);
sound_result[6]=NR50;
// A zero fade interval sets the target immediately. Level zero is not mute.
Audio_FadeToMasterVolume(0,0,0);
sound_result[7]=NR50;
sound_wait(30);
Audio_StopChannel(AUDIO_CHANNEL_CH1);
sound_wait(15);
sound_end();
}預期結果
A4 依序移至左、右、中央。在中央從等級 7 淡出至 1,再升至 4 並保持。等級 0 仍可微弱聽見;停止通道才會靜音。改變路由後,可能留下逐漸衰減的濾波器暫態聲。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_mix.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-mix.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:132
Two bits per channel (CH1 in bits 0-1): center, left, right, mute. Applies all four positions with one NR51 update for sequencer automation.
kitaqgb/lib/audio.c:589
void __stackcall Audio_SetPanPacked(u8 packed) {
u8 mix = 0;
u8 pan = (u8)(packed & 3);
if (pan == AUDIO_PAN_CENTER) mix = (u8)(mix | 0x11);
else if (pan == AUDIO_PAN_LEFT) mix = (u8)(mix | 0x10);
else if (pan == AUDIO_PAN_RIGHT) mix = (u8)(mix | 0x01);
pan = (u8)((packed >> 2) & 3);
if (pan == AUDIO_PAN_CENTER) mix = (u8)(mix | 0x22);
else if (pan == AUDIO_PAN_LEFT) mix = (u8)(mix | 0x20);
else if (pan == AUDIO_PAN_RIGHT) mix = (u8)(mix | 0x02);
pan = (u8)((packed >> 4) & 3);
if (pan == AUDIO_PAN_CENTER) mix = (u8)(mix | 0x44);
else if (pan == AUDIO_PAN_LEFT) mix = (u8)(mix | 0x40);
else if (pan == AUDIO_PAN_RIGHT) mix = (u8)(mix | 0x04);
pan = (u8)((packed >> 6) & 3);
if (pan == AUDIO_PAN_CENTER) mix = (u8)(mix | 0x88);
else if (pan == AUDIO_PAN_LEFT) mix = (u8)(mix | 0x80);
else if (pan == AUDIO_PAN_RIGHT) mix = (u8)(mix | 0x08);
Audio_Pan = mix;
Audio_UpdateNR51();
}Audio_SetPaused
暫停時靜音並保留音樂/效果位置。恢復時重新觸發符合條件的 CH1、CH2、CH4 音符。
語法
void __stackcall Audio_SetPaused(u8 on);參數
on零停用,非零啟用。請依此函式說明區分靜音與停止更新。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
請先引入 audio_hwregs_gb.c 再引入 audio.c,並在啟動時呼叫 Audio_Init。每影格恰好呼叫 Audio_Update 一次,約 59.7 Hz。讀取串流會暫時改變 ROM 映射,勿從中斷重入此驅動。
此常式不重新觸發 CH3。效果會在後續更新繼續。直接發聲呼叫即使在暫停中也可發聲。
使用範例
// Original two-note phrase: pause preserves the cursor; the enable gate does not.
#include "gb_sound_example.h"
__prg_rom u8 song[]={
AUDIO_CMD_SET_INST,AUDIO_STREAM_CHANNEL_CH1,2,0xC0,
AUDIO_CMD_NOTE,AUDIO_STREAM_CHANNEL_CH1,33,AUDIO_CMD_WAIT,59,
AUDIO_CMD_NOTE,AUDIO_STREAM_CHANNEL_CH1,40,AUDIO_CMD_WAIT,59,
AUDIO_CMD_LOOP
};
void main() {
u8 delay;
sound_begin("MUSIC PAUSE GATE");
Audio_SetMasterVolume(3,3);
Audio_PlayMusic(0,song);
sound_wait(30);
delay=Audio_Delay;
Audio_SetPaused(1);
sound_wait(30);
sound_result[0]=(u8)(Audio_Delay==delay);
sound_result[1]=Audio_Paused;
Audio_SetPaused(0);
sound_wait(30);
sound_result[2]=Audio_Paused;
// Disabling suppresses note writes; the next 30 updates still consume data.
Audio_SetMusicEnabled(0);
sound_wait(30);
sound_result[3]=Audio_Delay;
sound_result[4]=Audio_MusicEnabled;
// Explicitly stop the sounding channel while leaving the stream running.
Audio_StopChannel(AUDIO_CHANNEL_CH1);
sound_wait(30);
Audio_SetMusicEnabled(1);
sound_wait(30);
Audio_StopMusic();
sound_result[5]=Audio_PlayingMusic;
sound_wait(30);
sound_end();
}預期結果
依序聽到音符、暫停靜音、恢復、停用音樂時保留的音符、明確關閉通道、重新啟用後的下一音符,最後停止。RAM 也驗證暫停期間 30 次更新保留 delay,而停用開關仍使其推進至 30。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_music.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-music.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:90
On pause entry, silence hardware while retaining cursors. On resume, retrigger eligible legacy CH1, CH2 and CH4 notes; CH3 is not retriggered here. Updates still advance master fades while paused, and effect playback resumes on a later update.
kitaqgb/lib/audio.c:1010
void __stackcall Audio_SetPaused(u8 on) {
if (on != 0) {
if (Audio_Paused == 0) {
Audio_Paused = 1;
Audio_SilenceAll();
}
} else {
if (Audio_Paused != 0) {
Audio_Paused = 0;
if (Audio_PlayingMusic != 0 && Audio_MusicEnabled != 0) {
if ((Audio_LastChMask & AUDIO_RESUME_CH1) != 0 && Audio_EffectPointer == 0) {
Audio_Ch1NoteOn(Audio_LastCh1Note, Audio_Ch1Env, Audio_Ch1Duty);
}
if ((Audio_LastChMask & AUDIO_RESUME_CH2) != 0) {
Audio_Ch2NoteOn(Audio_LastCh2Note, Audio_Ch2Env, Audio_Ch2Duty);
}
if ((Audio_LastChMask & AUDIO_RESUME_CH4) != 0) {
Audio_Ch4NoteOn(Audio_LastCh4Param, Audio_Ch4Env);
}
}
}
}
}Audio_SetSfxEnabled
控制效果音符寫入;停用時也釋放效果槽。
語法
void __stackcall Audio_SetSfxEnabled(u8 on);參數
on零停用,非零啟用。請依此函式說明區分靜音與停止更新。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
一般設定下,釋放效果會關閉 CH3。音樂停止時也會使 CH1 靜音,但音樂播放中不會自動重播先前音符。使用 AUDIO_VBLANK_SFX_RESTORE 時,釋放會要求 ISR 恢復音樂。
停用時開始仍可登錄串流,但更新會抑制音符寫入。請先啟用效果,再請求有聲播放。
使用範例
// Each pair lasts one update. Priority controls replacement within each slot.
#include "gb_sound_example.h"
#pragma bank 2
__prg_rom u8 effect[]={33,0xC0,33,0xC0,33,0xC0,33,0xC0,33,0xC0,33,0xC0,
40,0xC0,40,0xC0,40,0xC0,40,0xC0,40,0xC0,40,0xC0,0};
__prg_rom u8 wave_effect[]={AUDIO_SFX_CH3_MARKER,
33,0x20,33,0x20,33,0x20,33,0x20,33,0x20,33,0x20,
40,0x20,40,0x20,40,0x20,40,0x20,40,0x20,40,0x20,0};
#pragma bank 0
void main() {
sound_begin("BANKED SOUND EFFECT");
Audio_SetMasterVolume(3,3);
// Read the marker in bank 2 while restoring the caller's original mapping.
Audio_PlaySFXPannedBanked(2,effect,5,AUDIO_PAN_LEFT);
sound_result[0]=Audio_EffectPriority;
Audio_PlaySFXBanked(2,effect,4);
sound_result[1]=Audio_EffectPriority;
sound_wait(30);
Audio_PlaySFXPannedBanked(2,wave_effect,5,AUDIO_PAN_RIGHT);
sound_result[2]=Audio_EffectPriority3;
sound_wait(30);
// Implicit-bank entry points capture bank 2; the service restores bank 1.
__bankswitch(2);
Audio_PlaySFX(effect,5);
__bankswitch(1);
sound_result[3]=Audio_EffectBank;
sound_wait(30);
__bankswitch(2);
Audio_PlaySFXPanned(effect,5,AUDIO_PAN_RIGHT);
__bankswitch(1);
sound_wait(6);
Audio_StopSfx();
sound_result[4]=(u8)(Audio_EffectPointer==0);
sound_wait(24);
// Disabling effects releases current owners; re-enable before the next request.
Audio_PlaySFXBanked(2,effect,5);
sound_wait(6);
Audio_SetSfxEnabled(0);
sound_result[5]=Audio_SfxEnabled;
sound_result[6]=(u8)(Audio_EffectPointer==0);
sound_wait(24);
Audio_SetSfxEnabled(1);
Audio_PlaySFXBanked(2,effect,5);
sound_wait(30);
sound_result[7]=Audio_SfxEnabled;
sound_end();
}預期結果
記憶體庫 2 資料播放左側短促上升脈波、右側波形效果及中央脈波。後續範例提早停止右側脈波、停用效果,再重新啟用播放。優先權 4 的請求無法取代 5。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_sfx.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-sfx.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:117
Enable effect note writes, or disable them and release both effect streams. Disabling follows Audio_StopSfx recovery rules rather than silencing all channels.
kitaqgb/lib/audio.c:505
void __stackcall Audio_SetSfxEnabled(u8 on) {
if (on != 0) {
Audio_SfxEnabled = 1;
} else {
Audio_SfxEnabled = 0;
Audio_StopSfx();
}
}Audio_StopChannel
停止一個實體聲部,並從恢復遮罩移除其音樂音符。
語法
void __stackcall Audio_StopChannel(u8 ch);參數
ch通道 ID:0=CH1、1=CH2、2=CH3、3=CH4。直接 API 與音樂串流使用相同 ID。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
CH1/CH3 也會清除其效果槽。0..3 以外不執行操作。VBlank 鎖存的音符另行管理。
使用範例
// Four isolated voices, each lasting 30 frames, separated by 15 silent frames.
#include "gb_sound_example.h"
void main() {
sound_begin("FOUR SOUND CHANNELS");
Audio_SetMasterVolume(3,3);
// CH1: A4, 50% duty, fixed envelope volume 12.
Audio_SetCh1Duty(2);
sound_result[0]=Audio_Ch1Duty;
Audio_Ch1NoteOn(33,0xC0,Audio_Ch1Duty);
sound_result[1]=NR12;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH1); sound_wait(15);
// CH2: A4, 25% duty. Changing the cached duty takes effect on this trigger.
Audio_SetCh2Duty(1);
sound_result[2]=Audio_Ch2Duty;
Audio_Ch2NoteOn(33,0xC0,Audio_Ch2Duty);
sound_result[3]=NR22;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH2); sound_wait(15);
// CH3: the initialized triangle wave, at 50% digital output level.
Audio_SetCh3Level(AUDIO_CH3_LEVEL_50);
sound_result[4]=Audio_Ch3Level;
Audio_Ch3NoteOn(33,Audio_Ch3Level);
sound_result[5]=NR32;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
// CH4: a sustained noise burst; param is NR43, not a pitched note number.
Audio_SetCh4Param(0x35);
sound_result[6]=Audio_Ch4Param;
Audio_Ch4NoteOn(Audio_Ch4Param,0xC0);
sound_result[7]=NR43;
sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH4); sound_wait(15);
sound_end();
}預期結果
約半秒靜音後,依序聽到 CH1 A4、CH2 A4、CH3 A3 與雜訊。每個聲音持續 30 影格,中間間隔 15 影格。SEQUENCE COMPLETE 表示程式完成;請用錄音判斷聲音。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_channels.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-channels.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:110
Stop a physical channel and clear its legacy resume bit. CH1 also clears the pulse effect stream; CH3 clears the wave effect stream. This is the legacy channel API and does not clear a VBlank driver's independently latched notes.
kitaqgb/lib/audio.c:981
void __stackcall Audio_StopChannel(u8 ch) {
if (ch == AUDIO_CHANNEL_CH1) {
Audio_EffectPointer = 0;
Audio_EffectPriority = 0;
Audio_EffectBank = 0;
Audio_EffectPan = AUDIO_PAN_INHERIT;
Audio_LastChMask = (u8)(Audio_LastChMask & (u8)~AUDIO_RESUME_CH1);
Audio_UpdateNR51();
Audio_SilenceCh1();
} else if (ch == AUDIO_CHANNEL_CH2) {
Audio_LastChMask = (u8)(Audio_LastChMask & (u8)~AUDIO_RESUME_CH2);
Audio_SilenceCh2();
} else if (ch == AUDIO_CHANNEL_CH3) {
Audio_EffectPointer3 = 0;
Audio_EffectPriority3 = 0;
Audio_EffectBank3 = 0;
Audio_EffectPan3 = AUDIO_PAN_INHERIT;
Audio_LastChMask = (u8)(Audio_LastChMask & (u8)~AUDIO_RESUME_CH3);
Audio_UpdateNR51();
Audio_Ch3Off();
} else if (ch == AUDIO_CHANNEL_CH4) {
Audio_LastChMask = (u8)(Audio_LastChMask & (u8)~AUDIO_RESUME_CH4);
Audio_SilenceCh4();
}
}Audio_StopMusic
清除歌曲播放狀態與恢復遮罩,並立即將四個聲部靜音。
語法
void Audio_StopMusic();回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
效果指標仍保留,因此後續 Audio_Update 可能播放效果。若要全部停止,也須呼叫 Audio_StopSfx。
使用範例
// Original two-note phrase: pause preserves the cursor; the enable gate does not.
#include "gb_sound_example.h"
__prg_rom u8 song[]={
AUDIO_CMD_SET_INST,AUDIO_STREAM_CHANNEL_CH1,2,0xC0,
AUDIO_CMD_NOTE,AUDIO_STREAM_CHANNEL_CH1,33,AUDIO_CMD_WAIT,59,
AUDIO_CMD_NOTE,AUDIO_STREAM_CHANNEL_CH1,40,AUDIO_CMD_WAIT,59,
AUDIO_CMD_LOOP
};
void main() {
u8 delay;
sound_begin("MUSIC PAUSE GATE");
Audio_SetMasterVolume(3,3);
Audio_PlayMusic(0,song);
sound_wait(30);
delay=Audio_Delay;
Audio_SetPaused(1);
sound_wait(30);
sound_result[0]=(u8)(Audio_Delay==delay);
sound_result[1]=Audio_Paused;
Audio_SetPaused(0);
sound_wait(30);
sound_result[2]=Audio_Paused;
// Disabling suppresses note writes; the next 30 updates still consume data.
Audio_SetMusicEnabled(0);
sound_wait(30);
sound_result[3]=Audio_Delay;
sound_result[4]=Audio_MusicEnabled;
// Explicitly stop the sounding channel while leaving the stream running.
Audio_StopChannel(AUDIO_CHANNEL_CH1);
sound_wait(30);
Audio_SetMusicEnabled(1);
sound_wait(30);
Audio_StopMusic();
sound_result[5]=Audio_PlayingMusic;
sound_wait(30);
sound_end();
}預期結果
依序聽到音符、暫停靜音、恢復、停用音樂時保留的音符、明確關閉通道、重新啟用後的下一音符,最後停止。RAM 也驗證暫停期間 30 次更新保留 delay,而停用開關仍使其推進至 30。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_music.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-music.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:86
Stop legacy music and clear its resume mask, then silence all physical channels. Effect pointers remain active and may produce sound on a later update.
kitaqgb/lib/audio.c:952
void Audio_StopMusic() {
Audio_PlayingMusic = 0;
Audio_LastChMask = 0;
Audio_SilenceAll();
}Audio_StopSfx
清除兩個效果串流及聲像覆寫,再釋放借用的通道。
語法
void Audio_StopSfx();回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
效果每次更新消耗一組 (note,value),遇到 note=0 結束。脈波效果的 value 為 NR12,CH3 則為 NR32。CH3 資料前須加上 0xFF,且儲存空間須保留至播放完成。優先權在同一槽內競爭,相同優先權也可取代目前效果。
一般設定下,釋放效果會關閉 CH3。音樂停止時也會使 CH1 靜音,但音樂播放中不會自動重播先前音符。使用 AUDIO_VBLANK_SFX_RESTORE 時,釋放會要求 ISR 恢復音樂。
使用範例
// Each pair lasts one update. Priority controls replacement within each slot.
#include "gb_sound_example.h"
#pragma bank 2
__prg_rom u8 effect[]={33,0xC0,33,0xC0,33,0xC0,33,0xC0,33,0xC0,33,0xC0,
40,0xC0,40,0xC0,40,0xC0,40,0xC0,40,0xC0,40,0xC0,0};
__prg_rom u8 wave_effect[]={AUDIO_SFX_CH3_MARKER,
33,0x20,33,0x20,33,0x20,33,0x20,33,0x20,33,0x20,
40,0x20,40,0x20,40,0x20,40,0x20,40,0x20,40,0x20,0};
#pragma bank 0
void main() {
sound_begin("BANKED SOUND EFFECT");
Audio_SetMasterVolume(3,3);
// Read the marker in bank 2 while restoring the caller's original mapping.
Audio_PlaySFXPannedBanked(2,effect,5,AUDIO_PAN_LEFT);
sound_result[0]=Audio_EffectPriority;
Audio_PlaySFXBanked(2,effect,4);
sound_result[1]=Audio_EffectPriority;
sound_wait(30);
Audio_PlaySFXPannedBanked(2,wave_effect,5,AUDIO_PAN_RIGHT);
sound_result[2]=Audio_EffectPriority3;
sound_wait(30);
// Implicit-bank entry points capture bank 2; the service restores bank 1.
__bankswitch(2);
Audio_PlaySFX(effect,5);
__bankswitch(1);
sound_result[3]=Audio_EffectBank;
sound_wait(30);
__bankswitch(2);
Audio_PlaySFXPanned(effect,5,AUDIO_PAN_RIGHT);
__bankswitch(1);
sound_wait(6);
Audio_StopSfx();
sound_result[4]=(u8)(Audio_EffectPointer==0);
sound_wait(24);
// Disabling effects releases current owners; re-enable before the next request.
Audio_PlaySFXBanked(2,effect,5);
sound_wait(6);
Audio_SetSfxEnabled(0);
sound_result[5]=Audio_SfxEnabled;
sound_result[6]=(u8)(Audio_EffectPointer==0);
sound_wait(24);
Audio_SetSfxEnabled(1);
Audio_PlaySFXBanked(2,effect,5);
sound_wait(30);
sound_result[7]=Audio_SfxEnabled;
sound_end();
}預期結果
記憶體庫 2 資料播放左側短促上升脈波、右側波形效果及中央脈波。後續範例提早停止右側脈波、停用效果,再重新啟用播放。優先權 4 的請求無法取代 5。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_sfx.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-sfx.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:106
Clear both effect streams and their pan overrides. When not paused, release borrowed channels through the configured legacy or VBlank recovery path.
kitaqgb/lib/audio.c:960
void Audio_StopSfx() {
Audio_EffectPointer = 0;
Audio_EffectPriority = 0;
Audio_EffectBank = 0;
Audio_EffectPointer3 = 0;
Audio_EffectPriority3 = 0;
Audio_EffectBank3 = 0;
Audio_EffectPan = AUDIO_PAN_INHERIT;
Audio_EffectPan3 = AUDIO_PAN_INHERIT;
Audio_UpdateNR51();
if (Audio_Paused != 0) return;
Audio_ReleaseCh1AfterSfx();
Audio_RestoreCh3FromMusic();
}Audio_Update
推進一次音量淡入淡出;未暫停時,先處理效果,再處理音樂。
語法
void Audio_Update();回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
請先引入 audio_hwregs_gb.c 再引入 audio.c,並在啟動時呼叫 Audio_Init。每影格恰好呼叫 Audio_Update 一次,約 59.7 Hz。讀取串流會暫時改變 ROM 映射,勿從中斷重入此驅動。
暫停期間淡入淡出仍持續。讀取 WAIT n 後會有 n 次等待呼叫,因此下一命令在 n+1 次更新後發生。
使用範例
// Original two-note phrase: pause preserves the cursor; the enable gate does not.
#include "gb_sound_example.h"
__prg_rom u8 song[]={
AUDIO_CMD_SET_INST,AUDIO_STREAM_CHANNEL_CH1,2,0xC0,
AUDIO_CMD_NOTE,AUDIO_STREAM_CHANNEL_CH1,33,AUDIO_CMD_WAIT,59,
AUDIO_CMD_NOTE,AUDIO_STREAM_CHANNEL_CH1,40,AUDIO_CMD_WAIT,59,
AUDIO_CMD_LOOP
};
void main() {
u8 delay;
sound_begin("MUSIC PAUSE GATE");
Audio_SetMasterVolume(3,3);
Audio_PlayMusic(0,song);
sound_wait(30);
delay=Audio_Delay;
Audio_SetPaused(1);
sound_wait(30);
sound_result[0]=(u8)(Audio_Delay==delay);
sound_result[1]=Audio_Paused;
Audio_SetPaused(0);
sound_wait(30);
sound_result[2]=Audio_Paused;
// Disabling suppresses note writes; the next 30 updates still consume data.
Audio_SetMusicEnabled(0);
sound_wait(30);
sound_result[3]=Audio_Delay;
sound_result[4]=Audio_MusicEnabled;
// Explicitly stop the sounding channel while leaving the stream running.
Audio_StopChannel(AUDIO_CHANNEL_CH1);
sound_wait(30);
Audio_SetMusicEnabled(1);
sound_wait(30);
Audio_StopMusic();
sound_result[5]=Audio_PlayingMusic;
sound_wait(30);
sound_end();
}預期結果
依序聽到音符、暫停靜音、恢復、停用音樂時保留的音符、明確關閉通道、重新啟用後的下一音符,最後停止。RAM 也驗證暫停期間 30 次更新保留 delay,而停用開關仍使其推進至 30。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_music.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-music.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio.h:79
Advance the master fade first. Unless paused, service both effect streams then the optional legacy music decoder. Call once per frame for frame-based timing.
kitaqgb/lib/audio.c:849
void Audio_Update() {
Audio_UpdateFade();
if (Audio_Paused != 0) return;
Audio_ServiceSfx();
#ifndef AUDIO_EXCLUDE_LEGACY_MUSIC_SERVICE
Audio_ServiceMusic();
#endif
}audio_vblank.h — 透過 VBlank IRQ 播放音樂
在 VBlank 處理音樂、協調效果通道使用權,並提供影格 hook。勿再以一般音樂解碼器推進同一歌曲。
audio_vblank.c 實作 __kq_vblank_vector,請勿另裝衝突的 VBlank 向量。範例定義 Audio_NoiseEffectActive、排除一般音樂解碼器,僅用 Audio_Update 處理效果與淡入淡出。變更歌曲指標或共用狀態時,須遮蔽中斷。
直接讀取的歌曲資料須放在固定 ROM 或 ISR 永遠可見的區域。每筆記錄為五個位元組:delay、CH1、CH2、CH3、CH4。音符欄位的 0xFF 保持目前聲音,0xFD 停止;delay 欄位的 0xFF 結束播放,0xFE 循環。這是記錄排列,不是通道 ID 編號。WRAM 佇列播放是獨立模式,須用 AudioVBlank_QueueRefill 提交完整五位元組記錄。
AudioVBlank_DisableIrq
只清除 IE 的 VBlank 位元,其他中斷來源與聲音不變。
語法
void AudioVBlank_DisableIrq();回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
audio_vblank.c 實作 __kq_vblank_vector,請勿另裝衝突的 VBlank 向量。範例定義 Audio_NoiseEffectActive、排除一般音樂解碼器,僅用 Audio_Update 處理效果與淡入淡出。變更歌曲指標或共用狀態時,須遮蔽中斷。
直接讀取的歌曲資料須放在固定 ROM 或 ISR 永遠可見的區域。每筆記錄為五個位元組:delay、CH1、CH2、CH3、CH4。音符欄位的 0xFF 保持目前聲音,0xFD 停止;delay 欄位的 0xFF 結束播放,0xFE 循環。這是記錄排列,不是通道 ID 編號。WRAM 佇列播放是獨立模式,須用 AudioVBlank_QueueRefill 提交完整五位元組記錄。
使用範例
// Direct fixed-bank music with an actual VBlank ISR and a counting frame hook.
#define SOUND_VBLANK
#include "gb_sound_example.h"
__wram u8 hook_count;
__prg_rom u8 irq_song[]={30,33,0xFF,0xFF,0xFF,30,40,0xFF,0xFF,0xFF,0xFE};
void frame_hook() { hook_count++; }
void main() {
u8 before;
sound_begin("VBLANK MUSIC GATES");
Audio_NoiseEffectActive=0;
AudioVBlank_Init();
sound_result[0]=AudioVBlank_MusicPlaying;
AudioVBlank_Ch1Envelope=0xC0;
Audio_SetMasterVolume(3,3);
hook_count=0; AudioVBlank_FrameHook=frame_hook;
AudioVBlank_SetMusic(irq_song);
AudioVBlank_Play();
AudioVBlank_EnableIrq();
sound_wait(45);
// Disable music processing while the hook and current note remain active.
__asm { DI }
AudioVBlank_SetEnabled(0); before=hook_count;
__asm { EI }
sound_wait(30);
sound_result[1]=(u8)(hook_count!=before);
__asm { DI }
AudioVBlank_Stop();
__asm { EI }
sound_wait(30);
__asm { DI }
AudioVBlank_SetEnabled(1); AudioVBlank_PlayMusic(irq_song);
__asm { EI }
sound_wait(45);
AudioVBlank_DisableIrq();
before=hook_count;
sound_wait(30);
sound_result[2]=(u8)(hook_count==before);
sound_result[3]=(u8)(AudioVBlank_IE&1);
AudioVBlank_Stop(); sound_wait(30);
sound_end();
}預期結果
ISR 播放兩音符歌曲。請比較:停止音樂更新會保留目前聲音,Stop 會靜音,而重啟後停用 IRQ 也會保留聲音。RAM 驗證音樂停用時 hook 仍執行,IRQ 停用時才停止。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_vblank.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-vblank.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio_vblank.h:118
Clear only the VBlank bit in IE. Other interrupt sources and current sound remain unchanged.
kitaqgb/lib/audio_vblank_control.inc:129
void AudioVBlank_DisableIrq()
{
AudioVBlank_IE = (u8)(AudioVBlank_IE & 0xFE);
}AudioVBlank_EnableIrq
設定 IE 的 VBlank 位元,並執行 EI 以全域啟用 CPU 中斷。
語法
void AudioVBlank_EnableIrq();回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
audio_vblank.c 實作 __kq_vblank_vector,請勿另裝衝突的 VBlank 向量。範例定義 Audio_NoiseEffectActive、排除一般音樂解碼器,僅用 Audio_Update 處理效果與淡入淡出。變更歌曲指標或共用狀態時,須遮蔽中斷。
直接讀取的歌曲資料須放在固定 ROM 或 ISR 永遠可見的區域。每筆記錄為五個位元組:delay、CH1、CH2、CH3、CH4。音符欄位的 0xFF 保持目前聲音,0xFD 停止;delay 欄位的 0xFF 結束播放,0xFE 循環。這是記錄排列,不是通道 ID 編號。WRAM 佇列播放是獨立模式,須用 AudioVBlank_QueueRefill 提交完整五位元組記錄。
使用範例
// Direct fixed-bank music with an actual VBlank ISR and a counting frame hook.
#define SOUND_VBLANK
#include "gb_sound_example.h"
__wram u8 hook_count;
__prg_rom u8 irq_song[]={30,33,0xFF,0xFF,0xFF,30,40,0xFF,0xFF,0xFF,0xFE};
void frame_hook() { hook_count++; }
void main() {
u8 before;
sound_begin("VBLANK MUSIC GATES");
Audio_NoiseEffectActive=0;
AudioVBlank_Init();
sound_result[0]=AudioVBlank_MusicPlaying;
AudioVBlank_Ch1Envelope=0xC0;
Audio_SetMasterVolume(3,3);
hook_count=0; AudioVBlank_FrameHook=frame_hook;
AudioVBlank_SetMusic(irq_song);
AudioVBlank_Play();
AudioVBlank_EnableIrq();
sound_wait(45);
// Disable music processing while the hook and current note remain active.
__asm { DI }
AudioVBlank_SetEnabled(0); before=hook_count;
__asm { EI }
sound_wait(30);
sound_result[1]=(u8)(hook_count!=before);
__asm { DI }
AudioVBlank_Stop();
__asm { EI }
sound_wait(30);
__asm { DI }
AudioVBlank_SetEnabled(1); AudioVBlank_PlayMusic(irq_song);
__asm { EI }
sound_wait(45);
AudioVBlank_DisableIrq();
before=hook_count;
sound_wait(30);
sound_result[2]=(u8)(hook_count==before);
sound_result[3]=(u8)(AudioVBlank_IE&1);
AudioVBlank_Stop(); sound_wait(30);
sound_end();
}預期結果
ISR 播放兩音符歌曲。請比較:停止音樂更新會保留目前聲音,Stop 會靜音,而重啟後停用 IRQ 也會保留聲音。RAM 驗證音樂停用時 hook 仍執行,IRQ 停用時才停止。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_vblank.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-vblank.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio_vblank.h:116
Enable the VBlank source in IE and execute EI, enabling CPU interrupts globally. Install the correct interrupt vector and initialize driver state first.
kitaqgb/lib/audio_vblank_control.inc:122
void AudioVBlank_EnableIrq()
{
AudioVBlank_IE = (u8)(AudioVBlank_IE | 0x01);
__asm { EI }
}AudioVBlank_Init
初始化 VBlank 音樂狀態、佇列、樂器與 hook。不初始化 APU,也不遮蔽中斷。
語法
void AudioVBlank_Init();回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
audio_vblank.c 實作 __kq_vblank_vector,請勿另裝衝突的 VBlank 向量。範例定義 Audio_NoiseEffectActive、排除一般音樂解碼器,僅用 Audio_Update 處理效果與淡入淡出。變更歌曲指標或共用狀態時,須遮蔽中斷。
直接讀取的歌曲資料須放在固定 ROM 或 ISR 永遠可見的區域。每筆記錄為五個位元組:delay、CH1、CH2、CH3、CH4。音符欄位的 0xFF 保持目前聲音,0xFD 停止;delay 欄位的 0xFF 結束播放,0xFE 循環。這是記錄排列,不是通道 ID 編號。WRAM 佇列播放是獨立模式,須用 AudioVBlank_QueueRefill 提交完整五位元組記錄。
使用範例
// Direct fixed-bank music with an actual VBlank ISR and a counting frame hook.
#define SOUND_VBLANK
#include "gb_sound_example.h"
__wram u8 hook_count;
__prg_rom u8 irq_song[]={30,33,0xFF,0xFF,0xFF,30,40,0xFF,0xFF,0xFF,0xFE};
void frame_hook() { hook_count++; }
void main() {
u8 before;
sound_begin("VBLANK MUSIC GATES");
Audio_NoiseEffectActive=0;
AudioVBlank_Init();
sound_result[0]=AudioVBlank_MusicPlaying;
AudioVBlank_Ch1Envelope=0xC0;
Audio_SetMasterVolume(3,3);
hook_count=0; AudioVBlank_FrameHook=frame_hook;
AudioVBlank_SetMusic(irq_song);
AudioVBlank_Play();
AudioVBlank_EnableIrq();
sound_wait(45);
// Disable music processing while the hook and current note remain active.
__asm { DI }
AudioVBlank_SetEnabled(0); before=hook_count;
__asm { EI }
sound_wait(30);
sound_result[1]=(u8)(hook_count!=before);
__asm { DI }
AudioVBlank_Stop();
__asm { EI }
sound_wait(30);
__asm { DI }
AudioVBlank_SetEnabled(1); AudioVBlank_PlayMusic(irq_song);
__asm { EI }
sound_wait(45);
AudioVBlank_DisableIrq();
before=hook_count;
sound_wait(30);
sound_result[2]=(u8)(hook_count==before);
sound_result[3]=(u8)(AudioVBlank_IE&1);
AudioVBlank_Stop(); sound_wait(30);
sound_end();
}預期結果
ISR 播放兩音符歌曲。請比較:停止音樂更新會保留目前聲音,Stop 會靜音,而重啟後停用 IRQ 也會保留聲音。RAM 驗證音樂停用時 hook 仍執行,IRQ 停用時才停止。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_vblank.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-vblank.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio_vblank.h:85
Reset software playback state, queue counters, instruments and the frame hook. Call before enabling this ISR; the routine does not mask interrupts or initialize the APU registers and cannot synchronize with an active handler.
kitaqgb/lib/audio_vblank_control.inc:6
void AudioVBlank_Init()
{
AudioVBlank_MusicEnabled = 1;
AudioVBlank_MusicPlaying = 0;
AudioVBlank_MusicDelay = 0;
AudioVBlank_MusicStart = 0;
AudioVBlank_MusicPointer = 0;
AudioVBlank_MusicLoopPoint = 0;
AudioVBlank_Step = 0;
AudioVBlank_Ch2Note = AUDIO_VBLANK_REST;
AudioVBlank_Ch1Note = AUDIO_VBLANK_REST;
AudioVBlank_Ch3Note = AUDIO_VBLANK_REST;
AudioVBlank_Ch2LatchedNote = AUDIO_VBLANK_STOP;
AudioVBlank_Ch1LatchedNote = AUDIO_VBLANK_STOP;
AudioVBlank_Ch3LatchedNote = AUDIO_VBLANK_STOP;
AudioVBlank_RestoreCh1Pending = 0;
AudioVBlank_RestoreCh3Pending = 0;
AudioVBlank_Ch4Param = AUDIO_VBLANK_REST;
AudioVBlank_Ch1Envelope = 0xF1;
AudioVBlank_Ch2Envelope = 0xF2;
AudioVBlank_Ch4Envelope = 0xF1;
AudioVBlank_Ch1Duty = 0x80;
AudioVBlank_Ch2Duty = 0x80;
AudioVBlank_Ch1Sweep = 0x00;
AudioVBlank_Ch3Level = 0x20;
AudioVBlank_ControlCommand = 0;
AudioVBlank_ControlArg0 = 0;
AudioVBlank_ControlArg1 = 0;
AudioVBlank_ControlArg2 = 0;
AudioVBlank_QueueMode = 0;
AudioVBlank_QueueReadIndex = 0;
AudioVBlank_QueueWriteIndex = 0;
AudioVBlank_QueueCount = 0;
AudioVBlank_QueueUnderruns = 0;
AudioVBlank_FrameHook = 0;
}AudioVBlank_Play
從頭重新播放所選歌曲並離開佇列模式。歌曲為 NULL 時停止播放。
語法
void AudioVBlank_Play();回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
audio_vblank.c 實作 __kq_vblank_vector,請勿另裝衝突的 VBlank 向量。範例定義 Audio_NoiseEffectActive、排除一般音樂解碼器,僅用 Audio_Update 處理效果與淡入淡出。變更歌曲指標或共用狀態時,須遮蔽中斷。
直接讀取的歌曲資料須放在固定 ROM 或 ISR 永遠可見的區域。每筆記錄為五個位元組:delay、CH1、CH2、CH3、CH4。音符欄位的 0xFF 保持目前聲音,0xFD 停止;delay 欄位的 0xFF 結束播放,0xFE 循環。這是記錄排列,不是通道 ID 編號。WRAM 佇列播放是獨立模式,須用 AudioVBlank_QueueRefill 提交完整五位元組記錄。
使用範例
// Direct fixed-bank music with an actual VBlank ISR and a counting frame hook.
#define SOUND_VBLANK
#include "gb_sound_example.h"
__wram u8 hook_count;
__prg_rom u8 irq_song[]={30,33,0xFF,0xFF,0xFF,30,40,0xFF,0xFF,0xFF,0xFE};
void frame_hook() { hook_count++; }
void main() {
u8 before;
sound_begin("VBLANK MUSIC GATES");
Audio_NoiseEffectActive=0;
AudioVBlank_Init();
sound_result[0]=AudioVBlank_MusicPlaying;
AudioVBlank_Ch1Envelope=0xC0;
Audio_SetMasterVolume(3,3);
hook_count=0; AudioVBlank_FrameHook=frame_hook;
AudioVBlank_SetMusic(irq_song);
AudioVBlank_Play();
AudioVBlank_EnableIrq();
sound_wait(45);
// Disable music processing while the hook and current note remain active.
__asm { DI }
AudioVBlank_SetEnabled(0); before=hook_count;
__asm { EI }
sound_wait(30);
sound_result[1]=(u8)(hook_count!=before);
__asm { DI }
AudioVBlank_Stop();
__asm { EI }
sound_wait(30);
__asm { DI }
AudioVBlank_SetEnabled(1); AudioVBlank_PlayMusic(irq_song);
__asm { EI }
sound_wait(45);
AudioVBlank_DisableIrq();
before=hook_count;
sound_wait(30);
sound_result[2]=(u8)(hook_count==before);
sound_result[3]=(u8)(AudioVBlank_IE&1);
AudioVBlank_Stop(); sound_wait(30);
sound_end();
}預期結果
ISR 播放兩音符歌曲。請比較:停止音樂更新會保留目前聲音,Stop 會靜音,而重啟後停用 IRQ 也會保留聲音。RAM 驗證音樂停用時 hook 仍執行,IRQ 停用時才停止。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_vblank.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-vblank.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio_vblank.h:103
Restart the selected direct song at its beginning, leaving queue mode. A null song invokes Stop; this does not enable the music or IRQ gates.
kitaqgb/lib/audio_vblank_control.inc:58
void AudioVBlank_Play()
{
if (AudioVBlank_MusicStart == 0) {
AudioVBlank_Stop();
return;
}
AudioVBlank_MusicPointer = AudioVBlank_MusicStart;
AudioVBlank_MusicLoopPoint = AudioVBlank_MusicStart;
AudioVBlank_MusicDelay = 0;
AudioVBlank_Step = 0;
AudioVBlank_QueueMode = 0;
AudioVBlank_MusicPlaying = 1;
}AudioVBlank_PlayMusic
選擇直接讀取的歌曲,並準備從頭播放。
語法
void __stackcall AudioVBlank_PlayMusic(u8 *song);參數
song歌曲起始位址。驅動借用此陣列,播放期間必須始終可讀。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
audio_vblank.c 實作 __kq_vblank_vector,請勿另裝衝突的 VBlank 向量。範例定義 Audio_NoiseEffectActive、排除一般音樂解碼器,僅用 Audio_Update 處理效果與淡入淡出。變更歌曲指標或共用狀態時,須遮蔽中斷。
直接讀取的歌曲資料須放在固定 ROM 或 ISR 永遠可見的區域。每筆記錄為五個位元組:delay、CH1、CH2、CH3、CH4。音符欄位的 0xFF 保持目前聲音,0xFD 停止;delay 欄位的 0xFF 結束播放,0xFE 循環。這是記錄排列,不是通道 ID 編號。WRAM 佇列播放是獨立模式,須用 AudioVBlank_QueueRefill 提交完整五位元組記錄。
使用範例
// Direct fixed-bank music with an actual VBlank ISR and a counting frame hook.
#define SOUND_VBLANK
#include "gb_sound_example.h"
__wram u8 hook_count;
__prg_rom u8 irq_song[]={30,33,0xFF,0xFF,0xFF,30,40,0xFF,0xFF,0xFF,0xFE};
void frame_hook() { hook_count++; }
void main() {
u8 before;
sound_begin("VBLANK MUSIC GATES");
Audio_NoiseEffectActive=0;
AudioVBlank_Init();
sound_result[0]=AudioVBlank_MusicPlaying;
AudioVBlank_Ch1Envelope=0xC0;
Audio_SetMasterVolume(3,3);
hook_count=0; AudioVBlank_FrameHook=frame_hook;
AudioVBlank_SetMusic(irq_song);
AudioVBlank_Play();
AudioVBlank_EnableIrq();
sound_wait(45);
// Disable music processing while the hook and current note remain active.
__asm { DI }
AudioVBlank_SetEnabled(0); before=hook_count;
__asm { EI }
sound_wait(30);
sound_result[1]=(u8)(hook_count!=before);
__asm { DI }
AudioVBlank_Stop();
__asm { EI }
sound_wait(30);
__asm { DI }
AudioVBlank_SetEnabled(1); AudioVBlank_PlayMusic(irq_song);
__asm { EI }
sound_wait(45);
AudioVBlank_DisableIrq();
before=hook_count;
sound_wait(30);
sound_result[2]=(u8)(hook_count==before);
sound_result[3]=(u8)(AudioVBlank_IE&1);
AudioVBlank_Stop(); sound_wait(30);
sound_end();
}預期結果
ISR 播放兩音符歌曲。請比較:停止音樂更新會保留目前聲音,Stop 會靜音,而重啟後停用 IRQ 也會保留聲音。RAM 驗證音樂停用時 hook 仍執行,IRQ 停用時才停止。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_vblank.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-vblank.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio_vblank.h:105
Select and restart a directly addressed song. This is not the banked WRAM-queue path.
kitaqgb/lib/audio_vblank_control.inc:73
void __stackcall AudioVBlank_PlayMusic(u8 *song)
{
AudioVBlank_SetMusic(song);
AudioVBlank_Play();
}AudioVBlank_QueuePlay
此 API 在本機版中的差異,請參閱 2026-10-03 差異與驗證。
在佇列模式已啟用且至少有一筆記錄時啟用播放。保留游標、延遲、音樂啟用及暫停狀態。開始新串流前,請先重設並預先填入佇列。
語法
u8 AudioVBlank_QueuePlay();回傳值
接受請求時傳回一;佇列為空或不是佇列模式時傳回零。實際取用資料還需要 ISR 正常執行、音樂已啟用,且驅動程式未暫停。
使用條件與限制
呼叫 AudioVBlank_Init 後,依序呼叫 QueueReset、QueueRefill 與 QueuePlay。請編譯一般的 audio_vblank.c;定義 AUDIO_VBLANK_CORE_ONLY 會排除以 C 撰寫的佇列填入函式。主程式填入可容納 16 筆五位元組記錄的佇列,再由 VBlank ISR 取用。
僅由主程式中的單一處填入資料,不可遞迴呼叫,也不可從 ISR 或 FrameHook 呼叫。每次將記錄設為可取用的短暫步驟都會保存 IE、遮罩中斷來源,之後還原 IE 與 SVBK;IME 不變。呼叫端必須自行選取並維持來源 ROM/RAM 記憶體庫。
含時間資訊的記錄依序為 delay、ch1_note、ch2_note、ch3_note、ch4_noise_param。END 也必須提供完整的五位元組記錄。LOOP 由填入端重送所需記錄來實現;不可直接傳入未轉換的可變長度直接播放命令串流。
使用範例
if(AudioVBlank_QueuePlay()==0) sound_result[0]++;
AudioVBlank_EnableIrq();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
將原創的八音樂句播放六次後停止。共 49 筆記錄——48 個音符加上 END——透過 16 槽佇列送出。檢查涵蓋全部 49 筆記錄均被接受、資料供應不足次數為零、播放停止、空佇列/滿佇列/空指標/零筆數、CGB WRAM 記憶體庫還原、IME 保持不變,以及播放時有聲、結束後靜音。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\audio_vblank_queue.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\audio_vblank_queue.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio_vblank.h:96
Start/resume queued playback; return 1 on success, 0 for an empty/nonqueue mode. Does not enable the interrupt, music gate or clear pause. Queue before starting.
kitaqgb/lib/audio_vblank_queue.inc:112
u8 AudioVBlank_QueuePlay()
{
u8 saved_ie;
u8 started;
saved_ie = AudioVBlank_IE;
AudioVBlank_IE = 0;
started = 0;
if (AudioVBlank_QueueMode != 0 && AudioVBlank_QueueCount != 0) {
AudioVBlank_MusicPlaying = 1;
started = 1;
}
AudioVBlank_IE = saved_ie;
return started;
}AudioVBlank_QueueRefill
此 API 在本機版中的差異,請參閱 2026-10-03 差異與驗證。
將完整的五位元組記錄複製到空槽中,每筆都在複製完成後才設為可供取用。單次呼叫最多接受 16 筆記錄。
語法
u8 __stackcall AudioVBlank_QueueRefill(const u8 *records, u8 count);參數
records位於目前可讀取記憶體庫中的記錄陣列。每筆被接受的記錄必須有五個可讀取位元組。空指標會使函式傳回零。
count嘗試提交的記錄筆數,不是位元組數。大於 16 的值會限制為 16;零不執行任何操作。
回傳值
傳回實際接受的記錄筆數,範圍為 0~16。佇列已滿、輸入為空指標、筆數為零或不在佇列模式時傳回零。來源指標應前進「傳回值乘以五」個位元組。ISR 可能在呼叫期間釋出槽位,因此結果不一定等於呼叫開始時的空槽數。
使用條件與限制
呼叫 AudioVBlank_Init 後,依序呼叫 QueueReset、QueueRefill 與 QueuePlay。請編譯一般的 audio_vblank.c;定義 AUDIO_VBLANK_CORE_ONLY 會排除以 C 撰寫的佇列填入函式。主程式填入可容納 16 筆五位元組記錄的佇列,再由 VBlank ISR 取用。
僅由主程式中的單一處填入資料,不可遞迴呼叫,也不可從 ISR 或 FrameHook 呼叫。每次將記錄設為可取用的短暫步驟都會保存 IE、遮罩中斷來源,之後還原 IE 與 SVBK;IME 不變。呼叫端必須自行選取並維持來源 ROM/RAM 記憶體庫。
含時間資訊的記錄依序為 delay、ch1_note、ch2_note、ch3_note、ch4_noise_param。END 也必須提供完整的五位元組記錄。LOOP 由填入端重送所需記錄來實現;不可直接傳入未轉換的可變長度直接播放命令串流。
使用範例
next=AudioVBlank_QueueRefill(queue_song,16);
// next counts records; each record occupies five source bytes.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
將原創的八音樂句播放六次後停止。共 49 筆記錄——48 個音符加上 END——透過 16 槽佇列送出。檢查涵蓋全部 49 筆記錄均被接受、資料供應不足次數為零、播放停止、空佇列/滿佇列/空指標/零筆數、CGB WRAM 記憶體庫還原、IME 保持不變,以及播放時有聲、結束後靜音。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\audio_vblank_queue.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\audio_vblank_queue.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio_vblank.h:93
Copy complete records from the currently mapped source; return records accepted. Each call attempts at most 16 records and stops when full. Null/zero returns 0. Supports ROM and RAM sources, restores SVBK and IE, and never changes IME. Single foreground producer only: do not call from an ISR or frame hook. LOOP must be expanded by the producer. END occupies a full five-byte record.
kitaqgb/lib/audio_vblank_queue.inc:93
u8 __stackcall AudioVBlank_QueueRefill(const u8 *records, u8 count)
{
u8 accepted;
u8 i;
if (records == 0 || count == 0 || AudioVBlank_QueueMode == 0) return 0;
if (count > AUDIO_VBLANK_QUEUE_RECORDS) count = AUDIO_VBLANK_QUEUE_RECORDS;
accepted = 0;
while (accepted < count) {
if (AudioVBlank_QueueCount >= AUDIO_VBLANK_QUEUE_RECORDS) break;
for (i = 0; i < 5; i++) AudioVBlank_QueueStaging[i] = records[i];
if (AudioVBlank_QueuePublish() == 0) break;
records += 5;
accepted++;
}
return accepted;
}AudioVBlank_QueueReset
此 API 在本機版中的差異,請參閱 2026-10-03 差異與驗證。
停止播放並靜音,切換至佇列模式,將讀寫位置、記錄數與資料供應不足計數歸零。尚未處理的記錄會被丟棄,以準備新的串流。
語法
void AudioVBlank_QueueReset();回傳值
無傳回值。音樂啟用與暫停設定保持不變。
使用條件與限制
呼叫 AudioVBlank_Init 後,依序呼叫 QueueReset、QueueRefill 與 QueuePlay。請編譯一般的 audio_vblank.c;定義 AUDIO_VBLANK_CORE_ONLY 會排除以 C 撰寫的佇列填入函式。主程式填入可容納 16 筆五位元組記錄的佇列,再由 VBlank ISR 取用。
僅由主程式中的單一處填入資料,不可遞迴呼叫,也不可從 ISR 或 FrameHook 呼叫。每次將記錄設為可取用的短暫步驟都會保存 IE、遮罩中斷來源,之後還原 IE 與 SVBK;IME 不變。呼叫端必須自行選取並維持來源 ROM/RAM 記憶體庫。
含時間資訊的記錄依序為 delay、ch1_note、ch2_note、ch3_note、ch4_noise_param。END 也必須提供完整的五位元組記錄。LOOP 由填入端重送所需記錄來實現;不可直接傳入未轉換的可變長度直接播放命令串流。
使用範例
AudioVBlank_QueueReset(); // Silence playback and discard any queued records.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
將原創的八音樂句播放六次後停止。共 49 筆記錄——48 個音符加上 END——透過 16 槽佇列送出。檢查涵蓋全部 49 筆記錄均被接受、資料供應不足次數為零、播放停止、空佇列/滿佇列/空指標/零筆數、CGB WRAM 記憶體庫還原、IME 保持不變,以及播放時有聲、結束後靜音。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\audio_vblank_queue.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\audio_vblank_queue.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio_vblank.h:87
Stop music and select an empty WRAM queue; preserve IE, IME and enable/pause gates.
kitaqgb/lib/audio_vblank_queue.inc:76
void AudioVBlank_QueueReset()
{
u8 saved_ie;
saved_ie = AudioVBlank_IE;
AudioVBlank_IE = 0;
AudioVBlank_Stop();
AudioVBlank_QueueMode = 1;
AudioVBlank_QueueReadIndex = 0;
AudioVBlank_QueueWriteIndex = 0;
AudioVBlank_QueueCount = 0;
AudioVBlank_QueueUnderruns = 0;
AudioVBlank_IE = saved_ie;
}AudioVBlank_RequestRestoreCh1
沒有待處理請求時設定脈波僅釋放請求 2,保留既有恢復請求 1。
語法
void AudioVBlank_RequestRestoreCh1();回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
audio_vblank.c 實作 __kq_vblank_vector,請勿另裝衝突的 VBlank 向量。範例定義 Audio_NoiseEffectActive、排除一般音樂解碼器,僅用 Audio_Update 處理效果與淡入淡出。變更歌曲指標或共用狀態時,須遮蔽中斷。
直接呼叫恢復函式時,呼叫端須確認效果已釋放聲部,並在之後清除待處理旗標。僅呼叫請求函式不會寫入音效暫存器。
使用範例
// Exercise the recovery API with IRQ disabled and explicit effect ownership.
#define SOUND_VBLANK
#include "gb_sound_example.h"
void main() {
sound_begin("EFFECT RECOVERY");
Audio_NoiseEffectActive=0; AudioVBlank_Init();
Audio_SetMasterVolume(3,3);
AudioVBlank_MusicPlaying=1;
AudioVBlank_Ch1Envelope=0xC0; AudioVBlank_Ch1LatchedNote=33;
AudioVBlank_Ch3LatchedNote=33;
// Value 1 represents a suppressed BGM event and survives a release request.
AudioVBlank_RestoreCh1Pending=1;
AudioVBlank_RequestRestoreCh1();
sound_result[0]=AudioVBlank_RestoreCh1Pending;
AudioVBlank_RestoreCh1(); AudioVBlank_RestoreCh1Pending=0;
sound_wait(30);
// Without a pending event, RequestRestore creates release-only value 2.
AudioVBlank_RequestRestoreCh1();
sound_result[1]=AudioVBlank_RestoreCh1Pending;
AudioVBlank_RestoreCh1(); AudioVBlank_RestoreCh1Pending=0;
sound_wait(30);
AudioVBlank_RestoreCh3Pending=1;
AudioVBlank_RequestRestoreCh3();
sound_result[2]=AudioVBlank_RestoreCh3Pending;
AudioVBlank_RestoreCh3(); AudioVBlank_RestoreCh3Pending=0;
sound_wait(30);
AudioVBlank_RequestRestoreCh3();
sound_result[3]=AudioVBlank_RestoreCh3Pending;
AudioVBlank_RestoreCh3(); AudioVBlank_RestoreCh3Pending=0;
sound_wait(30);
AudioVBlank_Stop();
sound_end();
}預期結果
依序聽到脈波恢復、靜音、波形恢復、靜音,各 30 影格。釋放請求保留待處理值 1;沒有待處理事件時提出請求,則得到僅釋放值 2。此處停用 IRQ,由呼叫端明確管理通道使用權。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_recovery.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-recovery.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio_vblank.h:129
Request deferred pulse-channel release only when no recovery is pending. Preserve value 1, which records a music event suppressed while an effect owned it.
kitaqgb/lib/audio_vblank.c:908
void AudioVBlank_RequestRestoreCh1()
{
if (AudioVBlank_RestoreCh1Pending == 0)
AudioVBlank_RestoreCh1Pending = 2;
}AudioVBlank_RequestRestoreCh3
沒有待處理請求時設定波形僅釋放請求 2,保留既有恢復請求 1。
語法
void AudioVBlank_RequestRestoreCh3();回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
audio_vblank.c 實作 __kq_vblank_vector,請勿另裝衝突的 VBlank 向量。範例定義 Audio_NoiseEffectActive、排除一般音樂解碼器,僅用 Audio_Update 處理效果與淡入淡出。變更歌曲指標或共用狀態時,須遮蔽中斷。
直接呼叫恢復函式時,呼叫端須確認效果已釋放聲部,並在之後清除待處理旗標。僅呼叫請求函式不會寫入音效暫存器。
使用範例
// Exercise the recovery API with IRQ disabled and explicit effect ownership.
#define SOUND_VBLANK
#include "gb_sound_example.h"
void main() {
sound_begin("EFFECT RECOVERY");
Audio_NoiseEffectActive=0; AudioVBlank_Init();
Audio_SetMasterVolume(3,3);
AudioVBlank_MusicPlaying=1;
AudioVBlank_Ch1Envelope=0xC0; AudioVBlank_Ch1LatchedNote=33;
AudioVBlank_Ch3LatchedNote=33;
// Value 1 represents a suppressed BGM event and survives a release request.
AudioVBlank_RestoreCh1Pending=1;
AudioVBlank_RequestRestoreCh1();
sound_result[0]=AudioVBlank_RestoreCh1Pending;
AudioVBlank_RestoreCh1(); AudioVBlank_RestoreCh1Pending=0;
sound_wait(30);
// Without a pending event, RequestRestore creates release-only value 2.
AudioVBlank_RequestRestoreCh1();
sound_result[1]=AudioVBlank_RestoreCh1Pending;
AudioVBlank_RestoreCh1(); AudioVBlank_RestoreCh1Pending=0;
sound_wait(30);
AudioVBlank_RestoreCh3Pending=1;
AudioVBlank_RequestRestoreCh3();
sound_result[2]=AudioVBlank_RestoreCh3Pending;
AudioVBlank_RestoreCh3(); AudioVBlank_RestoreCh3Pending=0;
sound_wait(30);
AudioVBlank_RequestRestoreCh3();
sound_result[3]=AudioVBlank_RestoreCh3Pending;
AudioVBlank_RestoreCh3(); AudioVBlank_RestoreCh3Pending=0;
sound_wait(30);
AudioVBlank_Stop();
sound_end();
}預期結果
依序聽到脈波恢復、靜音、波形恢復、靜音,各 30 影格。釋放請求保留待處理值 1;沒有待處理事件時提出請求,則得到僅釋放值 2。此處停用 IRQ,由呼叫端明確管理通道使用權。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_recovery.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-recovery.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio_vblank.h:132
Request a deferred wave-channel release only if no recovery is pending. Preserve value 1, which records a new music event suppressed by the effect.
kitaqgb/lib/audio_vblank.c:916
void AudioVBlank_RequestRestoreCh3()
{
if (AudioVBlank_RestoreCh3Pending == 0)
AudioVBlank_RestoreCh3Pending = 2;
}AudioVBlank_RestoreCh1
將鎖存的音樂音符還原至效果借用的脈波聲部(CH1 或 CH2),或靜音釋放。
語法
void AudioVBlank_RestoreCh1();回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
audio_vblank.c 實作 __kq_vblank_vector,請勿另裝衝突的 VBlank 向量。範例定義 Audio_NoiseEffectActive、排除一般音樂解碼器,僅用 Audio_Update 處理效果與淡入淡出。變更歌曲指標或共用狀態時,須遮蔽中斷。
直接呼叫恢復函式時,呼叫端須確認效果已釋放聲部,並在之後清除待處理旗標。僅呼叫請求函式不會寫入音效暫存器。
使用範例
// Exercise the recovery API with IRQ disabled and explicit effect ownership.
#define SOUND_VBLANK
#include "gb_sound_example.h"
void main() {
sound_begin("EFFECT RECOVERY");
Audio_NoiseEffectActive=0; AudioVBlank_Init();
Audio_SetMasterVolume(3,3);
AudioVBlank_MusicPlaying=1;
AudioVBlank_Ch1Envelope=0xC0; AudioVBlank_Ch1LatchedNote=33;
AudioVBlank_Ch3LatchedNote=33;
// Value 1 represents a suppressed BGM event and survives a release request.
AudioVBlank_RestoreCh1Pending=1;
AudioVBlank_RequestRestoreCh1();
sound_result[0]=AudioVBlank_RestoreCh1Pending;
AudioVBlank_RestoreCh1(); AudioVBlank_RestoreCh1Pending=0;
sound_wait(30);
// Without a pending event, RequestRestore creates release-only value 2.
AudioVBlank_RequestRestoreCh1();
sound_result[1]=AudioVBlank_RestoreCh1Pending;
AudioVBlank_RestoreCh1(); AudioVBlank_RestoreCh1Pending=0;
sound_wait(30);
AudioVBlank_RestoreCh3Pending=1;
AudioVBlank_RequestRestoreCh3();
sound_result[2]=AudioVBlank_RestoreCh3Pending;
AudioVBlank_RestoreCh3(); AudioVBlank_RestoreCh3Pending=0;
sound_wait(30);
AudioVBlank_RequestRestoreCh3();
sound_result[3]=AudioVBlank_RestoreCh3Pending;
AudioVBlank_RestoreCh3(); AudioVBlank_RestoreCh3Pending=0;
sound_wait(30);
AudioVBlank_Stop();
sound_end();
}預期結果
依序聽到脈波恢復、靜音、波形恢復、靜音,各 30 影格。釋放請求保留待處理值 1;沒有待處理事件時提出請求,則得到僅釋放值 2。此處停用 IRQ,由呼叫端明確管理通道使用權。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_recovery.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-recovery.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio_vblank.h:122
Recover the borrowed pulse channel (CH1 or CH2) from its latched music event. Pending value 2, disabled music, or a non-note latch silences it instead. The caller must first establish that the effect has released the channel.
kitaqgb/lib/audio_vblank.c:769
void AudioVBlank_RestoreCh1()
{
__asm {
LD_A_MEM Audio_EffectUsesCh2
OR_A
JR_NZ audiovb_restore_ch2
LD_A_MEM AudioVBlank_RestoreCh1Pending
CP_IMM 2
JR_Z audiovb_restore_ch1_off
LD_A_MEM AudioVBlank_MusicPlaying
OR_A
JR_Z audiovb_restore_ch1_off
LD_A_MEM AudioVBlank_MusicEnabled
OR_A
JR_Z audiovb_restore_ch1_off
LD_A_MEM Audio_MusicEnabled
OR_A
JR_Z audiovb_restore_ch1_off
LD_A_MEM AudioVBlank_Ch1LatchedNote
CP_IMM 0x44
JR_NC audiovb_restore_ch1_off
LD_C_A
LD_A_MEM AudioVBlank_Ch1Sweep
LDH_MEM_A 0x10
LD_A_MEM AudioVBlank_Ch1Duty
LDH_MEM_A 0x11
LD_A_MEM AudioVBlank_Ch1Envelope
LDH_MEM_A 0x12
LD_A_C
LD_E_A
LD_D_IMM 0
LD_HL_IMM AudioVBlank_FreqLo
ADD_HL_DE
LD_A_HL
LDH_MEM_A 0x13
LD_HL_IMM AudioVBlank_FreqHi
ADD_HL_DE
LD_A_HL
OR_IMM 0x80
LDH_MEM_A 0x14
JR audiovb_restore_ch1_done
audiovb_restore_ch1_off:
XOR_A
LDH_MEM_A 0x12
audiovb_restore_ch1_done:
JR audiovb_restore_square_done
audiovb_restore_ch2:
LD_A_MEM AudioVBlank_RestoreCh1Pending
CP_IMM 2
JR_Z audiovb_restore_ch2_off
LD_A_MEM AudioVBlank_MusicPlaying
OR_A
JR_Z audiovb_restore_ch2_off
LD_A_MEM AudioVBlank_MusicEnabled
OR_A
JR_Z audiovb_restore_ch2_off
LD_A_MEM Audio_MusicEnabled
OR_A
JR_Z audiovb_restore_ch2_off
LD_A_MEM AudioVBlank_Ch2LatchedNote
CP_IMM 0x44
JR_NC audiovb_restore_ch2_off
LD_C_A
LD_A_MEM AudioVBlank_Ch2Duty
LDH_MEM_A 0x16
LD_A_MEM AudioVBlank_Ch2Envelope
LDH_MEM_A 0x17
LD_A_C
LD_E_A
LD_D_IMM 0
LD_HL_IMM AudioVBlank_FreqLo
ADD_HL_DE
LD_A_HL
LDH_MEM_A 0x18
LD_HL_IMM AudioVBlank_FreqHi
ADD_HL_DE
LD_A_HL
OR_IMM 0x80
LDH_MEM_A 0x19
JR audiovb_restore_square_done
audiovb_restore_ch2_off:
XOR_A
LDH_MEM_A 0x17
audiovb_restore_square_done:
}
}AudioVBlank_RestoreCh3
效果釋放後還原 CH3 鎖存的音符,或停用其 DAC。
語法
void AudioVBlank_RestoreCh3();回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
audio_vblank.c 實作 __kq_vblank_vector,請勿另裝衝突的 VBlank 向量。範例定義 Audio_NoiseEffectActive、排除一般音樂解碼器,僅用 Audio_Update 處理效果與淡入淡出。變更歌曲指標或共用狀態時,須遮蔽中斷。
直接呼叫恢復函式時,呼叫端須確認效果已釋放聲部,並在之後清除待處理旗標。僅呼叫請求函式不會寫入音效暫存器。
使用範例
// Exercise the recovery API with IRQ disabled and explicit effect ownership.
#define SOUND_VBLANK
#include "gb_sound_example.h"
void main() {
sound_begin("EFFECT RECOVERY");
Audio_NoiseEffectActive=0; AudioVBlank_Init();
Audio_SetMasterVolume(3,3);
AudioVBlank_MusicPlaying=1;
AudioVBlank_Ch1Envelope=0xC0; AudioVBlank_Ch1LatchedNote=33;
AudioVBlank_Ch3LatchedNote=33;
// Value 1 represents a suppressed BGM event and survives a release request.
AudioVBlank_RestoreCh1Pending=1;
AudioVBlank_RequestRestoreCh1();
sound_result[0]=AudioVBlank_RestoreCh1Pending;
AudioVBlank_RestoreCh1(); AudioVBlank_RestoreCh1Pending=0;
sound_wait(30);
// Without a pending event, RequestRestore creates release-only value 2.
AudioVBlank_RequestRestoreCh1();
sound_result[1]=AudioVBlank_RestoreCh1Pending;
AudioVBlank_RestoreCh1(); AudioVBlank_RestoreCh1Pending=0;
sound_wait(30);
AudioVBlank_RestoreCh3Pending=1;
AudioVBlank_RequestRestoreCh3();
sound_result[2]=AudioVBlank_RestoreCh3Pending;
AudioVBlank_RestoreCh3(); AudioVBlank_RestoreCh3Pending=0;
sound_wait(30);
AudioVBlank_RequestRestoreCh3();
sound_result[3]=AudioVBlank_RestoreCh3Pending;
AudioVBlank_RestoreCh3(); AudioVBlank_RestoreCh3Pending=0;
sound_wait(30);
AudioVBlank_Stop();
sound_end();
}預期結果
依序聽到脈波恢復、靜音、波形恢復、靜音,各 30 影格。釋放請求保留待處理值 1;沒有待處理事件時提出請求,則得到僅釋放值 2。此處停用 IRQ,由呼叫端明確管理通道使用權。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_recovery.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-recovery.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio_vblank.h:126
Recover a latched wave-channel music event after effect release, or disable the DAC for a release-only request, disabled music, or a non-note latch. The caller owns effect arbitration and clearing the pending flag.
kitaqgb/lib/audio_vblank.c:860
void AudioVBlank_RestoreCh3()
{
__asm {
LD_A_MEM AudioVBlank_RestoreCh3Pending
CP_IMM 2
JR_Z audiovb_restore_ch3_off
LD_A_MEM AudioVBlank_MusicPlaying
OR_A
JR_Z audiovb_restore_ch3_off
LD_A_MEM AudioVBlank_MusicEnabled
OR_A
JR_Z audiovb_restore_ch3_off
LD_A_MEM Audio_MusicEnabled
OR_A
JR_Z audiovb_restore_ch3_off
LD_A_MEM AudioVBlank_Ch3LatchedNote
CP_IMM 0x44
JR_NC audiovb_restore_ch3_off
LD_C_A
LD_A_IMM 0x80
LDH_MEM_A 0x1A
XOR_A
LDH_MEM_A 0x1B
LD_A_MEM AudioVBlank_Ch3Level
LDH_MEM_A 0x1C
LD_A_C
LD_E_A
LD_D_IMM 0
LD_HL_IMM AudioVBlank_FreqLo
ADD_HL_DE
LD_A_HL
LDH_MEM_A 0x1D
LD_HL_IMM AudioVBlank_FreqHi
ADD_HL_DE
LD_A_HL
OR_IMM 0x80
LDH_MEM_A 0x1E
JR audiovb_restore_ch3_done
audiovb_restore_ch3_off:
XOR_A
LDH_MEM_A 0x1A
audiovb_restore_ch3_done:
}
}AudioVBlank_SetEnabled
控制 VBlank 音樂處理,停用時清除恢復請求。目前聲音與 IRQ 不變。
語法
void __stackcall AudioVBlank_SetEnabled(u8 on);參數
on零停用,非零啟用。請依此函式說明區分靜音與停止更新。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
audio_vblank.c 實作 __kq_vblank_vector,請勿另裝衝突的 VBlank 向量。範例定義 Audio_NoiseEffectActive、排除一般音樂解碼器,僅用 Audio_Update 處理效果與淡入淡出。變更歌曲指標或共用狀態時,須遮蔽中斷。
直接讀取的歌曲資料須放在固定 ROM 或 ISR 永遠可見的區域。每筆記錄為五個位元組:delay、CH1、CH2、CH3、CH4。音符欄位的 0xFF 保持目前聲音,0xFD 停止;delay 欄位的 0xFF 結束播放,0xFE 循環。這是記錄排列,不是通道 ID 編號。WRAM 佇列播放是獨立模式,須用 AudioVBlank_QueueRefill 提交完整五位元組記錄。
使用範例
// Direct fixed-bank music with an actual VBlank ISR and a counting frame hook.
#define SOUND_VBLANK
#include "gb_sound_example.h"
__wram u8 hook_count;
__prg_rom u8 irq_song[]={30,33,0xFF,0xFF,0xFF,30,40,0xFF,0xFF,0xFF,0xFE};
void frame_hook() { hook_count++; }
void main() {
u8 before;
sound_begin("VBLANK MUSIC GATES");
Audio_NoiseEffectActive=0;
AudioVBlank_Init();
sound_result[0]=AudioVBlank_MusicPlaying;
AudioVBlank_Ch1Envelope=0xC0;
Audio_SetMasterVolume(3,3);
hook_count=0; AudioVBlank_FrameHook=frame_hook;
AudioVBlank_SetMusic(irq_song);
AudioVBlank_Play();
AudioVBlank_EnableIrq();
sound_wait(45);
// Disable music processing while the hook and current note remain active.
__asm { DI }
AudioVBlank_SetEnabled(0); before=hook_count;
__asm { EI }
sound_wait(30);
sound_result[1]=(u8)(hook_count!=before);
__asm { DI }
AudioVBlank_Stop();
__asm { EI }
sound_wait(30);
__asm { DI }
AudioVBlank_SetEnabled(1); AudioVBlank_PlayMusic(irq_song);
__asm { EI }
sound_wait(45);
AudioVBlank_DisableIrq();
before=hook_count;
sound_wait(30);
sound_result[2]=(u8)(hook_count==before);
sound_result[3]=(u8)(AudioVBlank_IE&1);
AudioVBlank_Stop(); sound_wait(30);
sound_end();
}預期結果
ISR 播放兩音符歌曲。請比較:停止音樂更新會保留目前聲音,Stop 會靜音,而重啟後停用 IRQ 也會保留聲音。RAM 驗證音樂停用時 hook 仍執行,IRQ 停用時才停止。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_vblank.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-vblank.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio_vblank.h:113
Gate music processing and clear pending CH1/CH3 recovery on disable. No audio register is written here: disabling does not itself silence a note already playing or disable the VBlank interrupt.
kitaqgb/lib/audio_vblank_control.inc:109
void __stackcall AudioVBlank_SetEnabled(u8 on)
{
if (on != 0) AudioVBlank_MusicEnabled = 1;
else {
AudioVBlank_MusicEnabled = 0;
// Do not carry a stale SFX-recovery request into a later song.
AudioVBlank_RestoreCh1Pending = 0;
AudioVBlank_RestoreCh3Pending = 0;
}
}AudioVBlank_SetMusic
選擇直接讀取的歌曲並重設游標,不改變播放旗標。
語法
void __stackcall AudioVBlank_SetMusic(u8 *song);參數
song歌曲起始位址。驅動借用此陣列,播放期間必須始終可讀。
回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
audio_vblank.c 實作 __kq_vblank_vector,請勿另裝衝突的 VBlank 向量。範例定義 Audio_NoiseEffectActive、排除一般音樂解碼器,僅用 Audio_Update 處理效果與淡入淡出。變更歌曲指標或共用狀態時,須遮蔽中斷。
直接讀取的歌曲資料須放在固定 ROM 或 ISR 永遠可見的區域。每筆記錄為五個位元組:delay、CH1、CH2、CH3、CH4。音符欄位的 0xFF 保持目前聲音,0xFD 停止;delay 欄位的 0xFF 結束播放,0xFE 循環。這是記錄排列,不是通道 ID 編號。WRAM 佇列播放是獨立模式,須用 AudioVBlank_QueueRefill 提交完整五位元組記錄。
使用範例
// Direct fixed-bank music with an actual VBlank ISR and a counting frame hook.
#define SOUND_VBLANK
#include "gb_sound_example.h"
__wram u8 hook_count;
__prg_rom u8 irq_song[]={30,33,0xFF,0xFF,0xFF,30,40,0xFF,0xFF,0xFF,0xFE};
void frame_hook() { hook_count++; }
void main() {
u8 before;
sound_begin("VBLANK MUSIC GATES");
Audio_NoiseEffectActive=0;
AudioVBlank_Init();
sound_result[0]=AudioVBlank_MusicPlaying;
AudioVBlank_Ch1Envelope=0xC0;
Audio_SetMasterVolume(3,3);
hook_count=0; AudioVBlank_FrameHook=frame_hook;
AudioVBlank_SetMusic(irq_song);
AudioVBlank_Play();
AudioVBlank_EnableIrq();
sound_wait(45);
// Disable music processing while the hook and current note remain active.
__asm { DI }
AudioVBlank_SetEnabled(0); before=hook_count;
__asm { EI }
sound_wait(30);
sound_result[1]=(u8)(hook_count!=before);
__asm { DI }
AudioVBlank_Stop();
__asm { EI }
sound_wait(30);
__asm { DI }
AudioVBlank_SetEnabled(1); AudioVBlank_PlayMusic(irq_song);
__asm { EI }
sound_wait(45);
AudioVBlank_DisableIrq();
before=hook_count;
sound_wait(30);
sound_result[2]=(u8)(hook_count==before);
sound_result[3]=(u8)(AudioVBlank_IE&1);
AudioVBlank_Stop(); sound_wait(30);
sound_end();
}預期結果
ISR 播放兩音符歌曲。請比較:停止音樂更新會保留目前聲音,Stop 會靜音,而重啟後停用 IRQ 也會保留聲音。RAM 驗證音樂停用時 hook 仍執行,IRQ 停用時才停止。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_vblank.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-vblank.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio_vblank.h:100
Select a directly addressed song and reset its cursors, leaving the playing flag unchanged. Song storage must remain accessible to the fixed-bank ISR; coordinate this multi-field update with interrupt execution.
kitaqgb/lib/audio_vblank_control.inc:46
void __stackcall AudioVBlank_SetMusic(u8 *song)
{
AudioVBlank_MusicStart = song;
AudioVBlank_MusicPointer = song;
AudioVBlank_MusicLoopPoint = song;
AudioVBlank_MusicDelay = 0;
AudioVBlank_Step = 0;
AudioVBlank_QueueMode = 0;
}AudioVBlank_Stop
清除播放、delay 與恢復狀態,立即將脈波、雜訊與波形聲部靜音。IRQ 保持啟用。
語法
void AudioVBlank_Stop();回傳值
無回傳值。會改變音效暫存器或驅動狀態。
使用條件與限制
audio_vblank.c 實作 __kq_vblank_vector,請勿另裝衝突的 VBlank 向量。範例定義 Audio_NoiseEffectActive、排除一般音樂解碼器,僅用 Audio_Update 處理效果與淡入淡出。變更歌曲指標或共用狀態時,須遮蔽中斷。
直接讀取的歌曲資料須放在固定 ROM 或 ISR 永遠可見的區域。每筆記錄為五個位元組:delay、CH1、CH2、CH3、CH4。音符欄位的 0xFF 保持目前聲音,0xFD 停止;delay 欄位的 0xFF 結束播放,0xFE 循環。這是記錄排列,不是通道 ID 編號。WRAM 佇列播放是獨立模式,須用 AudioVBlank_QueueRefill 提交完整五位元組記錄。
使用範例
// Direct fixed-bank music with an actual VBlank ISR and a counting frame hook.
#define SOUND_VBLANK
#include "gb_sound_example.h"
__wram u8 hook_count;
__prg_rom u8 irq_song[]={30,33,0xFF,0xFF,0xFF,30,40,0xFF,0xFF,0xFF,0xFE};
void frame_hook() { hook_count++; }
void main() {
u8 before;
sound_begin("VBLANK MUSIC GATES");
Audio_NoiseEffectActive=0;
AudioVBlank_Init();
sound_result[0]=AudioVBlank_MusicPlaying;
AudioVBlank_Ch1Envelope=0xC0;
Audio_SetMasterVolume(3,3);
hook_count=0; AudioVBlank_FrameHook=frame_hook;
AudioVBlank_SetMusic(irq_song);
AudioVBlank_Play();
AudioVBlank_EnableIrq();
sound_wait(45);
// Disable music processing while the hook and current note remain active.
__asm { DI }
AudioVBlank_SetEnabled(0); before=hook_count;
__asm { EI }
sound_wait(30);
sound_result[1]=(u8)(hook_count!=before);
__asm { DI }
AudioVBlank_Stop();
__asm { EI }
sound_wait(30);
__asm { DI }
AudioVBlank_SetEnabled(1); AudioVBlank_PlayMusic(irq_song);
__asm { EI }
sound_wait(45);
AudioVBlank_DisableIrq();
before=hook_count;
sound_wait(30);
sound_result[2]=(u8)(hook_count==before);
sound_result[3]=(u8)(AudioVBlank_IE&1);
AudioVBlank_Stop(); sound_wait(30);
sound_end();
}預期結果
ISR 播放兩音符歌曲。請比較:停止音樂更新會保留目前聲音,Stop 會靜音,而重啟後停用 IRQ 也會保留聲音。RAM 驗證音樂停用時 hook 仍執行,IRQ 停用時才停止。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_vblank.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-vblank.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/audio_vblank.h:109
Stop software playback and silence pulse/noise envelopes and the wave DAC. Song pointers and the IRQ enable remain unchanged; the routine writes the physical channels directly, so coordinate ownership with sound effects.
kitaqgb/lib/audio_vblank_control.inc:82
void AudioVBlank_Stop()
{
AudioVBlank_MusicPlaying = 0;
AudioVBlank_MusicDelay = 0;
AudioVBlank_Step = 0;
AudioVBlank_Ch2Note = AUDIO_VBLANK_REST;
AudioVBlank_Ch1Note = AUDIO_VBLANK_REST;
AudioVBlank_Ch3Note = AUDIO_VBLANK_REST;
AudioVBlank_Ch2LatchedNote = AUDIO_VBLANK_STOP;
AudioVBlank_Ch1LatchedNote = AUDIO_VBLANK_STOP;
AudioVBlank_Ch3LatchedNote = AUDIO_VBLANK_STOP;
AudioVBlank_RestoreCh1Pending = 0;
AudioVBlank_RestoreCh3Pending = 0;
AudioVBlank_Ch4Param = AUDIO_VBLANK_REST;
__asm {
XOR_A
LDH_MEM_A 0x12
LDH_MEM_A 0x17
LDH_MEM_A 0x1C
LDH_MEM_A 0x1A
LDH_MEM_A 0x21
}
}bank.h — 考慮 bank 的程式碼與資料存取
ROM 區塊是映射到 CPU 位址空間的一塊卡匣儲存區域。不同區塊可出現在相同 CPU 位址,因此只靠 16 位元指標無法確定跨區塊資料。BankPtr 是緊密排列的三位元組描述子,包含一位元組區塊編號與兩位元組指標。使用 farptr_make 建立,再透過 farptr_read8、farptr_read16 或 farptr_read 存取資料。
GB 範例使用 MBC5 卡匣:固定區塊 0 的程式碼可持續透過 $0000–$3FFF 存取,區塊 1、2、3 則映射到 $4000–$7FFF。請將 bank_switch 與呼叫後繼續執行的程式碼放在固定 ROM 中。查詢函式庫保存的編號前,應先用 bank_switch 初始化記錄。GB 的 far_call 接受回呼指標,而 __farcall 要求函式名稱。
bank_get_current
傳回 bank_switch 最後記錄的區塊編號。讀取的是軟體記錄,而非卡匣暫存器。
語法
u8 bank_get_current();回傳值
bank_switch 最近保存的 u8 值;初始化前為 0。
使用條件與限制
函式庫記錄初值為 0,不會查詢卡匣啟動時的映射。請用 bank_switch 初始化。直接呼叫切換內建函式或寫入 mapper 不會更新這份獨立記錄,因此 bank_get_current 無法驗證實際硬體映射。
使用範例
starting_bank=bank_get_current(); // Last value recorded by bank_switch.
bank_expect(starting_bank==2,1);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
最初的 bank_switch(2) 記錄並選擇區塊 2。之後直接切換到區塊 1,從 home1 讀到 A1,而 bank_get_current 仍回報 2。切回後,home2 再次讀出 B2。
完整程式示範如何以區塊編號與近位址確定資料、如何跨區塊呼叫回呼,以及如何區分函式庫記錄與實際映射。所有數值皆為十六進位。BANK IN 與 BANK OUT 應為 02,BYTE HEX 為 D3,WORD HEX 為 5C7A,FAILED CHECKS 與 FIRST FAILURE 均為 00。CGB 與 FC 顯示藍字,DMG 顯示黑字。
CALL COUNT 為 03:far_call、__farcall 與 __farcall_ptr 各執行一次回呼。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\banked_data_calls.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/bank.h:21
Return the last bank recorded by bank_switch; this does not read cartridge hardware.
kitaqgb/lib/bank.c:15
u8 bank_get_current()
{
return kq_bank_current;
}bank_switch
此 API 在本機版中的差異,請參閱 2026-10-03 差異與驗證。
選擇 ROM 記憶體區塊,並在 bank 函式庫與編譯器的區塊狀態中記錄編號。遠端讀取與呼叫透過編譯器的記錄還原原本的映射。
語法
void bank_switch(u8 bank);參數
bank無號 8 位元 ROM 區塊編號。呼叫時應與函式配置一致,讀取時用來選擇來源映射。請使用目標卡匣支援的範圍。
回傳值
無(void)。
使用條件與限制
持續生效的區塊切換不能使目前程式碼或返回位址失去映射。請如範例所示,將呼叫位置、使用的 bank_switch 本體及後續程式碼放在共用或固定區塊 0。
函式庫記錄初值為 0,不會查詢卡匣啟動時的映射。請用 bank_switch 初始化。直接呼叫切換內建函式或寫入 mapper 不會更新這份獨立記錄,因此 bank_get_current 無法驗證實際硬體映射。
這些 GB 區塊介面只攜帶 8 位元編號,不設定 MBC5 的第 9 位元。仍須遵守卡匣規則,包括 mapper 對編號 0 的處理。範例明確使用 MBC5 區塊 1–3;不要混用未記錄的 mapper 直接寫入。
使用範例
bank_switch(2); // Select the payload window and update library bookkeeping.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
最初的 bank_switch(2) 記錄並選擇區塊 2。之後直接切換到區塊 1,從 home1 讀到 A1,而 bank_get_current 仍回報 2。切回後,home2 再次讀出 B2。
完整程式示範如何以區塊編號與近位址確定資料、如何跨區塊呼叫回呼,以及如何區分函式庫記錄與實際映射。所有數值皆為十六進位。BANK IN 與 BANK OUT 應為 02,BYTE HEX 為 D3,WORD HEX 為 5C7A,FAILED CHECKS 與 FIRST FAILURE 均為 00。CGB 與 FC 顯示藍字,DMG 顯示黑字。
CALL COUNT 為 03:far_call、__farcall 與 __farcall_ptr 各執行一次回呼。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\banked_data_calls.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/bank.h:19
Update both the library bank record and the compiler shadow used by far reads and calls. Invoke this permanent bank change from fixed-bank code.
kitaqgb/lib/bank.c:8
void bank_switch(u8 bank)
{
kq_bank_current = bank;
__bankswitch(bank);
}far_call
將區塊編號與回呼指標交給 __farcall_ptr。此函式庫函式執行無參數回呼,並在還原呼叫端區塊後傳回。
語法
void far_call(u8 bank, const void* func);參數
bank無號 8 位元 ROM 區塊編號。呼叫時應與函式配置一致,讀取時用來選擇來源映射。請使用目標卡匣支援的範圍。
func無參數回呼的有效可執行位址,可由函式名稱或執行時指標提供。執行時不檢查空指標或錯誤的區塊與位址組合。
回傳值
無(void)。
使用條件與限制
這些呼叫不傳遞使用者引數,也不會自動使回呼可在中斷中重入。請正確管理回呼自身的資料、堆疊與中斷使用。還原區塊的呼叫路徑已測試巢狀及重複呼叫;此範例不涵蓋實機或任意中斷交錯。
這些 GB 區塊介面只攜帶 8 位元編號,不設定 MBC5 的第 9 位元。仍須遵守卡匣規則,包括 mapper 對編號 0 的處理。範例明確使用 MBC5 區塊 1–3;不要混用未記錄的 mapper 直接寫入。
使用範例
far_call(3,callback); // No arguments; callback reads payload[0] in bank 3.
bank_expect(callback_count==1 && callback_byte==0xD3,15);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
在完整程式的此處,far_call 使 callback_count 達到 1。回呼從區塊 3 讀取 D3。隨後透過近指標讀取 home2 並確認 B2,驗證傳回時已還原區塊 2。
完整程式示範如何以區塊編號與近位址確定資料、如何跨區塊呼叫回呼,以及如何區分函式庫記錄與實際映射。所有數值皆為十六進位。BANK IN 與 BANK OUT 應為 02,BYTE HEX 為 D3,WORD HEX 為 5C7A,FAILED CHECKS 與 FIRST FAILURE 均為 00。CGB 與 FC 顯示藍字,DMG 顯示黑字。
CALL COUNT 為 03:far_call、__farcall 與 __farcall_ptr 各執行一次回呼。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\banked_data_calls.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/bank.h:30
Invoke a no-argument callback in its ROM bank, then restore the caller bank. The pointer must identify executable code; no arguments are forwarded.
kitaqgb/lib/bank.c:40
void far_call(u8 bank, const void* func)
{
__farcall_ptr(bank, func);
}far_data_read
透過遠端記憶體複製內建函式,將指定 ROM 區塊的 len 個位元組複製到呼叫端提供的 RAM,並在傳回前還原原區塊。
語法
void far_data_read(u8 bank, const void* addr, void* dst, u16 len);參數
bank無號 8 位元 ROM 區塊編號。呼叫時應與函式配置一致,讀取時用來選擇來源映射。請使用目標卡匣支援的範圍。
addr指向所選ROM區塊中可讀取位元組的近指標,指標本身不含區塊編號。
dst目標可寫入記憶體,容量必須足以容納實際複製的全部位元組。除了零位元組傳送外,不會檢查null或無效目標位址。
len位元組數,範圍0–65535。設為0時不複製記憶體,但仍會執行區塊選取與恢復。
回傳值
無(void)。
使用條件與限制
整個來源範圍必須在預期ROM映射中可讀取,整個目標範圍必須可寫入。複製不會在區塊視窗邊界自動切換至下一區塊,不提供memmove式的重疊處理,也不控制VRAM安全寫入時機。寫入VRAM請使用圖形傳送API。
遠端讀取與複製是同步操作,會使用編譯器共用工作區。操作期間不要讓中斷執行另一筆區塊傳輸並覆寫同一工作區。GB 複製輔助程式還使用一個共用 HRAM 位置保存返回區塊。範例從固定程式碼執行,不設置競爭的區塊傳輸中斷。
這些 GB 區塊介面只攜帶 8 位元編號,不設定 MBC5 的第 9 位元。仍須遵守卡匣規則,包括 mapper 對編號 0 的處理。範例明確使用 MBC5 區塊 1–3;不要混用未記錄的 mapper 直接寫入。
使用範例
far_data_read(3,payload,buffer,4); // Copy into four writable RAM bytes.
bank_expect(buffer[0]==0xD3 && buffer[1]==0x7A && buffer[2]==0x5C && buffer[3]==0x96,7);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此片段透過 far_data_read 複製 4 個位元組,並將緩衝區與 D3 7A 5C 96 比較。呼叫端的來源描述子或指標維持不變;完整程式還分別檢查零長度複製與區塊還原。
完整程式示範如何以區塊編號與近位址確定資料、如何跨區塊呼叫回呼,以及如何區分函式庫記錄與實際映射。所有數值皆為十六進位。BANK IN 與 BANK OUT 應為 02,BYTE HEX 為 D3,WORD HEX 為 5C7A,FAILED CHECKS 與 FIRST FAILURE 均為 00。CGB 與 FC 顯示藍字,DMG 顯示黑字。
CALL COUNT 為 03:far_call、__farcall 與 __farcall_ptr 各執行一次回呼。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\banked_data_calls.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/bank.h:27
Copy len bytes from banked ROM into caller-owned writable storage.
kitaqgb/lib/bank.c:33
void far_data_read(u8 bank, const void* addr, void* dst, u16 len)
{
__farmemcpy(dst, bank, addr, len);
}far_data_read16
透過 __farpeek16 讀取連續兩個位元組,組成小端序字組。第一個位元組對應低 8 位元。
語法
u16 far_data_read16(u8 bank, const void* addr);參數
bank無號 8 位元 ROM 區塊編號。呼叫時應與函式配置一致,讀取時用來選擇來源映射。請使用目標卡匣支援的範圍。
addr指向所選ROM區塊中可讀取位元組的近指標,指標本身不含區塊編號。
回傳值
以 u16(0–65535)傳回讀到的小端序字組。
使用條件與限制
目標位元組或字組的全部內容必須在選定 CPU 映射中可讀取。這些讀取不檢查指標、不裁切位址,也不會在視窗邊界自動切換到下一個 ROM 區塊。讀取一個字組需要連續兩個有效位元組。
遠端讀取與複製是同步操作,會使用編譯器共用工作區。操作期間不要讓中斷執行另一筆區塊傳輸並覆寫同一工作區。GB 複製輔助程式還使用一個共用 HRAM 位置保存返回區塊。範例從固定程式碼執行,不設置競爭的區塊傳輸中斷。
這些 GB 區塊介面只攜帶 8 位元編號,不設定 MBC5 的第 9 位元。仍須遵守卡匣規則,包括 mapper 對編號 0 的處理。範例明確使用 MBC5 區塊 1–3;不要混用未記錄的 mapper 直接寫入。
使用範例
word_value=far_data_read16(3,payload+1); // Little-endian 7A 5C -> 0x5C7A.
bank_expect(word_value==0x5C7A,6);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式片段使用 far_data_read16 讀取區塊 3 中的 payload+1 並檢查 5C7A。完整程式還透過近指標讀取 home2,確認已還原區塊 2 的映射。
完整程式示範如何以區塊編號與近位址確定資料、如何跨區塊呼叫回呼,以及如何區分函式庫記錄與實際映射。所有數值皆為十六進位。BANK IN 與 BANK OUT 應為 02,BYTE HEX 為 D3,WORD HEX 為 5C7A,FAILED CHECKS 與 FIRST FAILURE 均為 00。CGB 與 FC 顯示藍字,DMG 顯示黑字。
CALL COUNT 為 03:far_call、__farcall 與 __farcall_ptr 各執行一次回呼。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\banked_data_calls.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/bank.h:25
Read a 16-bit value from the supplied bank and address through the far-read intrinsic.
kitaqgb/lib/bank.c:27
u16 far_data_read16(u8 bank, const void* addr)
{
return __farpeek16(bank, addr);
}far_data_read8
透過 __farpeek8 從指定 ROM 區塊與位址讀取一個位元組,還原原區塊後傳回該值。
語法
u8 far_data_read8(u8 bank, const void* addr);參數
bank無號 8 位元 ROM 區塊編號。呼叫時應與函式配置一致,讀取時用來選擇來源映射。請使用目標卡匣支援的範圍。
addr指向所選ROM區塊中可讀取位元組的近指標,指標本身不含區塊編號。
回傳值
以 u8(0–255)傳回讀到的位元組。
使用條件與限制
目標位元組或字組的全部內容必須在選定 CPU 映射中可讀取。這些讀取不檢查指標、不裁切位址,也不會在視窗邊界自動切換到下一個 ROM 區塊。讀取一個字組需要連續兩個有效位元組。
遠端讀取與複製是同步操作,會使用編譯器共用工作區。操作期間不要讓中斷執行另一筆區塊傳輸並覆寫同一工作區。GB 複製輔助程式還使用一個共用 HRAM 位置保存返回區塊。範例從固定程式碼執行,不設置競爭的區塊傳輸中斷。
這些 GB 區塊介面只攜帶 8 位元編號,不設定 MBC5 的第 9 位元。仍須遵守卡匣規則,包括 mapper 對編號 0 的處理。範例明確使用 MBC5 區塊 1–3;不要混用未記錄的 mapper 直接寫入。
使用範例
byte_value=far_data_read8(3,payload); // One byte: 0xD3.
bank_expect(byte_value==0xD3,5);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式片段使用 far_data_read8 讀取區塊 3 中的 payload 並檢查 D3。完整程式還透過近指標讀取 home2,確認已還原區塊 2 的映射。
完整程式示範如何以區塊編號與近位址確定資料、如何跨區塊呼叫回呼,以及如何區分函式庫記錄與實際映射。所有數值皆為十六進位。BANK IN 與 BANK OUT 應為 02,BYTE HEX 為 D3,WORD HEX 為 5C7A,FAILED CHECKS 與 FIRST FAILURE 均為 00。CGB 與 FC 顯示藍字,DMG 顯示黑字。
CALL COUNT 為 03:far_call、__farcall 與 __farcall_ptr 各執行一次回呼。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\banked_data_calls.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/bank.h:23
Read one byte through the compiler intrinsic that accepts an explicit ROM bank.
kitaqgb/lib/bank.c:21
u8 far_data_read8(u8 bank, const void* addr)
{
return __farpeek8(bank, addr);
}farptr_make
將一個位元組的區塊編號與 CPU 可見指標寫入呼叫端的 BankPtr。此操作只建立描述子,不切換區塊,也不讀取指向的資料。
語法
void farptr_make(BankPtr* out, u8 bank, const u8* ptr);參數
out指向可寫入一筆三位元組 BankPtr 的儲存空間。out 為 null 時不執行寫入。
bank無號 8 位元 ROM 區塊編號。呼叫時應與函式配置一致,讀取時用來選擇來源映射。請使用目標卡匣支援的範圍。
ptr要保存到描述子中的 CPU 可見 16 位元位址。依原值保存,不檢查該位址是否存在於指定區塊中。
回傳值
無(void)。
使用範例
farptr_make(&pointer,3,payload+1); // Store a bank and address; do not read ROM.
bank_expect(pointer.bank==3 && pointer.ptr==payload+1,8);
farptr_make(0,1,home1); // A null destination is ignored.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
描述子設為區塊 3 與 payload+1。後續讀取分別得到 7A、5C7A 與三個位元組 7A 5C 96。輸出為 null 的呼叫不得改變狀態。
完整程式示範如何以區塊編號與近位址確定資料、如何跨區塊呼叫回呼,以及如何區分函式庫記錄與實際映射。所有數值皆為十六進位。BANK IN 與 BANK OUT 應為 02,BYTE HEX 為 D3,WORD HEX 為 5C7A,FAILED CHECKS 與 FIRST FAILURE 均為 00。CGB 與 FC 顯示藍字,DMG 顯示黑字。
CALL COUNT 為 03:far_call、__farcall 與 __farcall_ptr 各執行一次回呼。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\banked_data_calls.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/bank.h:32
Store a bank/address pair without accessing ROM; a null output pointer is ignored.
kitaqgb/lib/bank.c:46
void farptr_make(BankPtr* out, u8 bank, const u8* ptr)
{
if (out == 0) return;
out->bank = bank;
out->ptr = ptr;
}farptr_read
從 BankPtr 指向的位置向可寫入 RAM 複製 len 個位元組。描述子以值傳遞,因此呼叫端的指標仍指向來源資料起點。
語法
void farptr_read(BankPtr ptr, void* dst, u16 len);參數
ptr包含 bank 與 ptr 的 BankPtr 值。傳入描述子本身,而非它的位址。呼叫端的描述子不會被修改。
dst目標可寫入記憶體,容量必須足以容納實際複製的全部位元組。除了零位元組傳送外,不會檢查null或無效目標位址。
len位元組數,範圍0–65535。設為0時不複製記憶體,但仍會執行區塊選取與恢復。
回傳值
無(void)。
使用條件與限制
整個來源範圍必須在預期ROM映射中可讀取,整個目標範圍必須可寫入。複製不會在區塊視窗邊界自動切換至下一區塊,不提供memmove式的重疊處理,也不控制VRAM安全寫入時機。寫入VRAM請使用圖形傳送API。
遠端讀取與複製是同步操作,會使用編譯器共用工作區。操作期間不要讓中斷執行另一筆區塊傳輸並覆寫同一工作區。GB 複製輔助程式還使用一個共用 HRAM 位置保存返回區塊。範例從固定程式碼執行,不設置競爭的區塊傳輸中斷。
這些 GB 區塊介面只攜帶 8 位元編號,不設定 MBC5 的第 9 位元。仍須遵守卡匣規則,包括 mapper 對編號 0 的處理。範例明確使用 MBC5 區塊 1–3;不要混用未記錄的 mapper 直接寫入。
使用範例
farptr_read(pointer,buffer,3);
bank_expect(buffer[0]==0x7A && buffer[1]==0x5C && buffer[2]==0x96,11);
bank_expect(pointer.bank==3 && pointer.ptr==payload+1,23);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此片段透過 farptr_read 複製 3 個位元組,並將緩衝區與 7A 5C 96 比較。呼叫端的來源描述子或指標維持不變;完整程式還分別檢查零長度複製與區塊還原。
完整程式示範如何以區塊編號與近位址確定資料、如何跨區塊呼叫回呼,以及如何區分函式庫記錄與實際映射。所有數值皆為十六進位。BANK IN 與 BANK OUT 應為 02,BYTE HEX 為 D3,WORD HEX 為 5C7A,FAILED CHECKS 與 FIRST FAILURE 均為 00。CGB 與 FC 顯示藍字,DMG 顯示黑字。
CALL COUNT 為 03:far_call、__farcall 與 __farcall_ptr 各執行一次回呼。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\banked_data_calls.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/bank.h:38
Copy len bytes from a bank-qualified pointer; dst must have room for the full copy.
kitaqgb/lib/bank.c:66
void farptr_read(BankPtr ptr, void* dst, u16 len)
{
__farmemcpy(dst, ptr.bank, ptr.ptr, len);
}farptr_read16
從 BankPtr 保存的區塊與位址讀取小端序字組。描述子以值傳遞,指標不會向前移動。
語法
u16 farptr_read16(BankPtr ptr);參數
ptr包含 bank 與 ptr 的 BankPtr 值。傳入描述子本身,而非它的位址。呼叫端的描述子不會被修改。
回傳值
以 u16(0–65535)傳回讀到的小端序字組。
使用條件與限制
目標位元組或字組的全部內容必須在選定 CPU 映射中可讀取。這些讀取不檢查指標、不裁切位址,也不會在視窗邊界自動切換到下一個 ROM 區塊。讀取一個字組需要連續兩個有效位元組。
遠端讀取與複製是同步操作,會使用編譯器共用工作區。操作期間不要讓中斷執行另一筆區塊傳輸並覆寫同一工作區。GB 複製輔助程式還使用一個共用 HRAM 位置保存返回區塊。範例從固定程式碼執行,不設置競爭的區塊傳輸中斷。
這些 GB 區塊介面只攜帶 8 位元編號,不設定 MBC5 的第 9 位元。仍須遵守卡匣規則,包括 mapper 對編號 0 的處理。範例明確使用 MBC5 區塊 1–3;不要混用未記錄的 mapper 直接寫入。
使用範例
bank_expect(farptr_read16(pointer)==0x5C7A,10);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式片段使用 farptr_read16 讀取區塊 3 中的 pointer.ptr 並檢查 5C7A。完整程式還透過近指標讀取 home2,確認已還原區塊 2 的映射。
完整程式示範如何以區塊編號與近位址確定資料、如何跨區塊呼叫回呼,以及如何區分函式庫記錄與實際映射。所有數值皆為十六進位。BANK IN 與 BANK OUT 應為 02,BYTE HEX 為 D3,WORD HEX 為 5C7A,FAILED CHECKS 與 FIRST FAILURE 均為 00。CGB 與 FC 顯示藍字,DMG 顯示黑字。
CALL COUNT 為 03:far_call、__farcall 與 __farcall_ptr 各執行一次回呼。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\banked_data_calls.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/bank.h:36
Read a 16-bit value using both components of the bank-qualified pointer.
kitaqgb/lib/bank.c:60
u16 farptr_read16(BankPtr ptr)
{
return __farpeek16(ptr.bank, ptr.ptr);
}farptr_read8
使用以值傳遞的 BankPtr 之兩個欄位讀取一個位元組。描述子提供一般近指標不包含的區塊編號。
語法
u8 farptr_read8(BankPtr ptr);參數
ptr包含 bank 與 ptr 的 BankPtr 值。傳入描述子本身,而非它的位址。呼叫端的描述子不會被修改。
回傳值
以 u8(0–255)傳回讀到的位元組。
使用條件與限制
目標位元組或字組的全部內容必須在選定 CPU 映射中可讀取。這些讀取不檢查指標、不裁切位址,也不會在視窗邊界自動切換到下一個 ROM 區塊。讀取一個字組需要連續兩個有效位元組。
遠端讀取與複製是同步操作,會使用編譯器共用工作區。操作期間不要讓中斷執行另一筆區塊傳輸並覆寫同一工作區。GB 複製輔助程式還使用一個共用 HRAM 位置保存返回區塊。範例從固定程式碼執行,不設置競爭的區塊傳輸中斷。
這些 GB 區塊介面只攜帶 8 位元編號,不設定 MBC5 的第 9 位元。仍須遵守卡匣規則,包括 mapper 對編號 0 的處理。範例明確使用 MBC5 區塊 1–3;不要混用未記錄的 mapper 直接寫入。
使用範例
bank_expect(farptr_read8(pointer)==0x7A,9);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式片段使用 farptr_read8 讀取區塊 3 中的 pointer.ptr 並檢查 7A。完整程式還透過近指標讀取 home2,確認已還原區塊 2 的映射。
完整程式示範如何以區塊編號與近位址確定資料、如何跨區塊呼叫回呼,以及如何區分函式庫記錄與實際映射。所有數值皆為十六進位。BANK IN 與 BANK OUT 應為 02,BYTE HEX 為 D3,WORD HEX 為 5C7A,FAILED CHECKS 與 FIRST FAILURE 均為 00。CGB 與 FC 顯示藍字,DMG 顯示黑字。
CALL COUNT 為 03:far_call、__farcall 與 __farcall_ptr 各執行一次回呼。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\banked_data_calls.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/bank.h:34
Read one byte using both components of the bank-qualified pointer.
kitaqgb/lib/bank.c:54
u8 farptr_read8(BankPtr ptr)
{
return __farpeek8(ptr.bank, ptr.ptr);
}camera.h — 世界座標與可見區域
管理 Q8.8 相機位置、目標與邊界,並轉換世界/畫面座標。可選用呼叫端持有的 Camera8_8 物件,或使用小寫 API 操作單一共用相機。
Camera_Add
將 Q8.8 位移加到目前位置,再套用已啟用的範圍限制。
語法
void Camera_Add(Camera8_8* cam, s16 dfx, s16 dfy);參數
cam指向已初始化且由呼叫端持有的
Camera8_8的有效指標。dfx帶正負號的 Q8.8 位移;256 表示移動一個像素。
dfy帶正負號的 Q8.8 位移;256 表示移動一個像素。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
座標包含 8 個小數位元。位置、目標及中間運算的和與差都必須位於 s16 範圍內。請另外使用 Camera_ApplyBg 或緩衝區提交來更新顯示。
使用範例
Camera_Add(&cam,256,512);result[13]=cam.fx;result[14]=cam.fy;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範 Q8.8 追蹤、範圍限制與座標轉換。追蹤結果 X/Y 為 3584/4096,套用邊界後為 3072/3584。待套用期間 BG X 維持 13,提交後變為 8。附圖顯示相機位於 (8,16) 時,世界 (32,32) 的 32×24 矩形出現在畫面 (24,16)。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/camera.h:34
Add Q8.8 deltas and clamp afterward. Keep the intermediate sums within s16; clamping cannot repair arithmetic that already overflowed.
kitaqgb/lib/camera.c:79
void Camera_Add(Camera8_8* cam, s16 dfx, s16 dfy)
{
cam->fx += dfx;
cam->fy += dfy;
Camera_ApplyBounds(cam);
}camera_apply
立即將共用相機目前位置套用至背景捲動。
語法
void camera_apply();回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
不會等待 VBlank;若不希望在影格中途改變設定,請由呼叫端同步。負小數也向下取整:−1/256 會變成 −1 像素,即暫存器值 255。
使用範例
camera_apply();result[31]=M_SCX;result[32]=M_SCY;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範 Q8.8 追蹤、範圍限制與座標轉換。追蹤結果 X/Y 為 3584/4096,套用邊界後為 3072/3584。待套用期間 BG X 維持 13,提交後變為 8。附圖顯示相機位於 (8,16) 時,世界 (32,32) 的 32×24 矩形出現在畫面 (24,16)。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/camera.h:64
Write the shared camera's current integer position to background scroll registers.
kitaqgb/lib/camera.c:179
void camera_apply()
{
Camera_ApplyBg(&camera_default);
}Camera_ApplyBg
將相機位置向下取整為整數像素,立即把低 8 位元寫入背景捲動設定。
語法
void Camera_ApplyBg(const Camera8_8* cam);參數
cam指向已初始化且由呼叫端持有的
Camera8_8的有效指標。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
不會等待 VBlank;若不希望在影格中途改變設定,請由呼叫端同步。負小數也向下取整:−1/256 會變成 −1 像素,即暫存器值 255。
使用範例
Camera_ApplyBg(&cam);result[21]=M_SCX;result[22]=M_SCY;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範 Q8.8 追蹤、範圍限制與座標轉換。追蹤結果 X/Y 為 3584/4096,套用邊界後為 3072/3584。待套用期間 BG X 維持 13,提交後變為 8。附圖顯示相機位於 (8,16) 時,世界 (32,32) 的 32×24 矩形出現在畫面 (24,16)。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/camera.h:40
Discard fractional bits and write the low eight integer bits to background scroll registers.
kitaqgb/lib/camera.c:109
void Camera_ApplyBg(const Camera8_8* cam)
{
__scroll_bg_set((u8)(cam->fx >> 8), (u8)(cam->fy >> 8));
}Camera_ApplyBgBuffered
將相機位置向下取整為整數像素,存為待套用的背景捲動值。
語法
void Camera_ApplyBgBuffered(const Camera8_8* cam);參數
cam指向已初始化且由呼叫端持有的
Camera8_8的有效指標。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
呼叫 Scroll_Flush 或 __scroll_flush 前,硬體及追蹤中的目前值均不變。此呼叫不會等待 VBlank。
使用範例
Camera_Set(&cam,2048,4096);Camera_ApplyBgBuffered(&cam);result[23]=M_SCX;Scroll_Flush();result[24]=M_SCX;result[25]=M_SCY;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範 Q8.8 追蹤、範圍限制與座標轉換。追蹤結果 X/Y 為 3584/4096,套用邊界後為 3072/3584。待套用期間 BG X 維持 13,提交後變為 8。附圖顯示相機位於 (8,16) 時,世界 (32,32) 的 32×24 矩形出現在畫面 (24,16)。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/camera.h:42
Convert the Q8.8 position to byte scroll values and stage them for a later flush.
kitaqgb/lib/camera.c:115
void Camera_ApplyBgBuffered(const Camera8_8* cam)
{
__scroll_bg_set_buffered((u8)(cam->fx >> 8), (u8)(cam->fy >> 8));
}camera_clamp
將世界尺寸減去畫面尺寸所得的邊界套用至共用相機。
語法
void camera_clamp(u16 world_w_px, u16 world_h_px, u8 screen_w_px, u8 screen_h_px);參數
world_w_px以整數像素表示的世界尺寸;超出畫面尺寸的正差值須保持在 0–127。
world_h_px以整數像素表示的世界尺寸;超出畫面尺寸的正差值須保持在 0–127。
screen_w_px以整數像素表示的可視區域尺寸;若不小於世界尺寸,該軸的移動範圍為零。
screen_h_px以整數像素表示的可視區域尺寸;若不小於世界尺寸,該軸的移動範圍為零。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
世界比可視區域小時,移動範圍為零。正差值達 128 以上時,轉換後會超出帶正負號 Q8.8 的範圍。參數使用 u16 並不代表相機可在任意大的世界中移動。 這些呼叫共用同一個相機;需要獨立相機物件時,請使用大寫開頭的 API。從整數像素轉換成 Q8.8 的位置必須位於 −128 到 127 之間。
使用範例
camera_clamp(176,160,160,144);result[29]=camera_world_to_screen_x(100);result[30]=camera_world_to_screen_y(90);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範 Q8.8 追蹤、範圍限制與座標轉換。追蹤結果 X/Y 為 3584/4096,套用邊界後為 3072/3584。待套用期間 BG X 維持 13,提交後變為 8。附圖顯示相機位於 (8,16) 時,世界 (32,32) 的 32×24 矩形出現在畫面 (24,16)。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/camera.h:62
Derive and apply world/screen bounds to the shared convenience camera.
kitaqgb/lib/camera.c:173
void camera_clamp(u16 world_w_px, u16 world_h_px, u8 screen_w_px, u8 screen_h_px)
{
Camera_ClampToSize(&camera_default, world_w_px, world_h_px, screen_w_px, screen_h_px);
}Camera_ClampToSize
以世界尺寸減去畫面尺寸,設定所得的非負相機移動範圍。
語法
void Camera_ClampToSize(Camera8_8* cam, u16 world_w_px, u16 world_h_px, u8 screen_w_px, u8 screen_h_px);參數
cam指向已初始化且由呼叫端持有的
Camera8_8的有效指標。world_w_px以整數像素表示的世界尺寸;超出畫面尺寸的正差值須保持在 0–127。
world_h_px以整數像素表示的世界尺寸;超出畫面尺寸的正差值須保持在 0–127。
screen_w_px以整數像素表示的可視區域尺寸;若不小於世界尺寸,該軸的移動範圍為零。
screen_h_px以整數像素表示的可視區域尺寸;若不小於世界尺寸,該軸的移動範圍為零。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
世界比可視區域小時,移動範圍為零。正差值達 128 以上時,轉換後會超出帶正負號 Q8.8 的範圍。參數使用 u16 並不代表相機可在任意大的世界中移動。
使用範例
Camera_ClampToSize(&cam,176,160,160,144);result[15]=cam.max_fx;result[16]=cam.max_fy;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範 Q8.8 追蹤、範圍限制與座標轉換。追蹤結果 X/Y 為 3584/4096,套用邊界後為 3072/3584。待套用期間 BG X 維持 13,提交後變為 8。附圖顯示相機位於 (8,16) 時,世界 (32,32) 的 32×24 矩形出現在畫面 (24,16)。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/camera.h:46
Derive nonnegative camera extents from world minus screen size, then convert them to Q8.8 bounds. Extents must fit signed Q8.8; the u16 input type does not imply support for arbitrary large worlds.
kitaqgb/lib/camera.c:123
void Camera_ClampToSize(Camera8_8* cam, u16 world_w_px, u16 world_h_px, u8 screen_w_px, u8 screen_h_px)
{
s16 max_x = 0;
s16 max_y = 0;
if (world_w_px > screen_w_px) max_x = (s16)((u16)(world_w_px - screen_w_px) << 8);
if (world_h_px > screen_h_px) max_y = (s16)((u16)(world_h_px - screen_h_px) << 8);
Camera_SetBounds(cam, (s16)0, (s16)0, max_x, max_y);
}Camera_ClearBounds
停用範圍限制,不改變位置、目標或已儲存的邊界。
語法
void Camera_ClearBounds(Camera8_8* cam);參數
cam指向已初始化且由呼叫端持有的
Camera8_8的有效指標。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
座標包含 8 個小數位元。位置、目標及中間運算的和與差都必須位於 s16 範圍內。請另外使用 Camera_ApplyBg 或緩衝區提交來更新顯示。
使用範例
Camera_ClearBounds(&cam);result[12]=cam.use_bounds;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範 Q8.8 追蹤、範圍限制與座標轉換。追蹤結果 X/Y 為 3584/4096,套用邊界後為 3072/3584。待套用期間 BG X 維持 13,提交後變為 8。附圖顯示相機位於 (8,16) 時,世界 (32,32) 的 32×24 矩形出現在畫面 (24,16)。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/camera.h:31
Disable clamping while retaining the stored bounds and current position.
kitaqgb/lib/camera.c:72
void Camera_ClearBounds(Camera8_8* cam)
{
cam->use_bounds = 0;
}Camera_ClearTarget
停用追蹤,保留目前位置及已儲存的目標。
語法
void Camera_ClearTarget(Camera8_8* cam);參數
cam指向已初始化且由呼叫端持有的
Camera8_8的有效指標。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
座標包含 8 個小數位元。位置、目標及中間運算的和與差都必須位於 s16 範圍內。請另外使用 Camera_ApplyBg 或緩衝區提交來更新顯示。
使用範例
Camera_ClearTarget(&cam);result[8]=cam.use_target;result[9]=cam.target_fx;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範 Q8.8 追蹤、範圍限制與座標轉換。追蹤結果 X/Y 為 3584/4096,套用邊界後為 3072/3584。待套用期間 BG X 維持 13,提交後變為 8。附圖顯示相機位於 (8,16) 時,世界 (32,32) 的 32×24 矩形出現在畫面 (24,16)。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/camera.h:27
Disable target following without moving the camera or erasing the stored target.
kitaqgb/lib/camera.c:55
void Camera_ClearTarget(Camera8_8* cam)
{
cam->use_target = 0;
}camera_follow_xy
立即移動共用相機,讓世界中的指定點出現在要求的畫面錨點。
語法
void camera_follow_xy(s16 x, s16 y, u8 screen_cx, u8 screen_cy);參數
x以整數像素表示的世界 X 座標;結果與中間差值必須位於
s16範圍內。y以整數像素表示的世界 Y 座標;結果與中間差值必須位於
s16範圍內。screen_cx畫面錨點座標,以整數像素表示,範圍為 0–255。
screen_cy畫面錨點座標,以整數像素表示,範圍為 0–255。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
座標包含 8 個小數位元。位置、目標及中間運算的和與差都必須位於 s16 範圍內。請另外使用 Camera_ApplyBg 或緩衝區提交來更新顯示。 這些呼叫共用同一個相機;需要獨立相機物件時,請使用大寫開頭的 API。從整數像素轉換成 Q8.8 的位置必須位於 −128 到 127 之間。
使用範例
camera_follow_xy(100,90,80,72);result[27]=camera_world_to_screen_x(100);result[28]=camera_world_to_screen_y(90);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範 Q8.8 追蹤、範圍限制與座標轉換。追蹤結果 X/Y 為 3584/4096,套用邊界後為 3072/3584。待套用期間 BG X 維持 13,提交後變為 8。附圖顯示相機位於 (8,16) 時,世界 (32,32) 的 32×24 矩形出現在畫面 (24,16)。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/camera.h:60
Position the shared camera so the world point appears at the requested screen anchor. This is an immediate move, not the smoothed target-following path.
kitaqgb/lib/camera.c:165
void camera_follow_xy(s16 x, s16 y, u8 screen_cx, u8 screen_cy)
{
s16 cx = (s16)(x - screen_cx);
s16 cy = (s16)(y - screen_cy);
Camera_Set(&camera_default, (s16)(cx << 8), (s16)(cy << 8));
}Camera_Init
將位置、目標及邊界歸零,停用追蹤與範圍限制。
語法
void Camera_Init(Camera8_8* cam);參數
cam要初始化的可寫入
Camera8_8,不可為 NULL。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
座標包含 8 個小數位元。位置、目標及中間運算的和與差都必須位於 s16 範圍內。請另外使用 Camera_ApplyBg 或緩衝區提交來更新顯示。
使用範例
Camera_Init(&cam);result[0]=cam.fx;result[1]=cam.use_target;result[2]=cam.use_bounds;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範 Q8.8 追蹤、範圍限制與座標轉換。追蹤結果 X/Y 為 3584/4096,套用邊界後為 3072/3584。待套用期間 BG X 維持 13,提交後變為 8。附圖顯示相機位於 (8,16) 時,世界 (32,32) 的 32×24 矩形出現在畫面 (24,16)。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/camera.h:21
Zero all position/target/bound fields and disable targeting and bounds.
kitaqgb/lib/camera.c:24
void Camera_Init(Camera8_8* cam)
{
cam->fx = 0;
cam->fy = 0;
cam->target_fx = 0;
cam->target_fy = 0;
cam->min_fx = 0;
cam->min_fy = 0;
cam->max_fx = 0;
cam->max_fy = 0;
cam->use_target = 0;
cam->use_bounds = 0;
}Camera_ScreenToWorldX
將相機 X 座標的整數部分加到整數畫面 X 座標,取得世界 X 座標。
語法
s16 Camera_ScreenToWorldX(const Camera8_8* cam, s16 screen_x);參數
cam指向已初始化且由呼叫端持有的
Camera8_8的有效指標。screen_x以整數像素表示的畫面 X 座標;結果與中間差值必須位於
s16範圍內。
回傳值
以 s16 傳回轉換後的整數像素座標;不檢查可見性,也不裁切。
使用條件與限制
座標包含 8 個小數位元。位置、目標及中間運算的和與差都必須位於 s16 範圍內。請另外使用 Camera_ApplyBg 或緩衝區提交來更新顯示。
使用範例
result[19]=Camera_ScreenToWorldX(&cam,27);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範 Q8.8 追蹤、範圍限制與座標轉換。追蹤結果 X/Y 為 3584/4096,套用邊界後為 3072/3584。待套用期間 BG X 維持 13,提交後變為 8。附圖顯示相機位於 (8,16) 時,世界 (32,32) 的 32×24 矩形出現在畫面 (24,16)。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/camera.h:52
Convert integer-pixel screen X back to world X using the camera's integer component.
kitaqgb/lib/camera.c:146
s16 Camera_ScreenToWorldX(const Camera8_8* cam, s16 screen_x)
{
return (s16)(screen_x + (cam->fx >> 8));
}Camera_ScreenToWorldY
將相機 Y 座標的整數部分加到整數畫面 Y 座標,取得世界 Y 座標。
語法
s16 Camera_ScreenToWorldY(const Camera8_8* cam, s16 screen_y);參數
cam指向已初始化且由呼叫端持有的
Camera8_8的有效指標。screen_y以整數像素表示的畫面 Y 座標;結果與中間差值必須位於
s16範圍內。
回傳值
以 s16 傳回轉換後的整數像素座標;不檢查可見性,也不裁切。
使用條件與限制
座標包含 8 個小數位元。位置、目標及中間運算的和與差都必須位於 s16 範圍內。請另外使用 Camera_ApplyBg 或緩衝區提交來更新顯示。
使用範例
result[20]=Camera_ScreenToWorldY(&cam,24);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範 Q8.8 追蹤、範圍限制與座標轉換。追蹤結果 X/Y 為 3584/4096,套用邊界後為 3072/3584。待套用期間 BG X 維持 13,提交後變為 8。附圖顯示相機位於 (8,16) 時,世界 (32,32) 的 32×24 矩形出現在畫面 (24,16)。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/camera.h:54
Convert integer-pixel screen Y back to world Y using the camera's integer component.
kitaqgb/lib/camera.c:152
s16 Camera_ScreenToWorldY(const Camera8_8* cam, s16 screen_y)
{
return (s16)(screen_y + (cam->fy >> 8));
}Camera_Set
替換目前相機位置;若已啟用範圍限制,立即將位置限制在邊界內。
語法
void Camera_Set(Camera8_8* cam, s16 fx, s16 fy);參數
cam指向已初始化且由呼叫端持有的
Camera8_8的有效指標。fxX 座標。 帶正負號的 Q8.8 座標;256 為一個像素,範圍為 −128 到 127+255/256 像素。
fyY 座標。 帶正負號的 Q8.8 座標;256 為一個像素,範圍為 −128 到 127+255/256 像素。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
座標包含 8 個小數位元。位置、目標及中間運算的和與差都必須位於 s16 範圍內。請另外使用 Camera_ApplyBg 或緩衝區提交來更新顯示。
使用範例
Camera_Set(&cam,2560,5120);result[3]=cam.fx;result[4]=cam.fy;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範 Q8.8 追蹤、範圍限制與座標轉換。追蹤結果 X/Y 為 3584/4096,套用邊界後為 3072/3584。待套用期間 BG X 維持 13,提交後變為 8。附圖顯示相機位於 (8,16) 時,世界 (32,32) 的 32×24 矩形出現在畫面 (24,16)。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/camera.h:23
Replace the current Q8.8 position and immediately apply enabled bounds.
kitaqgb/lib/camera.c:39
void Camera_Set(Camera8_8* cam, s16 fx, s16 fy)
{
cam->fx = fx;
cam->fy = fy;
Camera_ApplyBounds(cam);
}camera_set
以整數像素座標移動共用相機,並套用已啟用的範圍限制。
語法
void camera_set(s16 x, s16 y);參數
x以整數像素表示的世界 X 座標;結果與中間差值必須位於
s16範圍內。y以整數像素表示的世界 Y 座標;結果與中間差值必須位於
s16範圍內。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
座標包含 8 個小數位元。位置、目標及中間運算的和與差都必須位於 s16 範圍內。請另外使用 Camera_ApplyBg 或緩衝區提交來更新顯示。 這些呼叫共用同一個相機;需要獨立相機物件時,請使用大寫開頭的 API。從整數像素轉換成 Q8.8 的位置必須位於 −128 到 127 之間。
使用範例
camera_set(5,6);result[26]=camera_world_to_screen_x(20);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範 Q8.8 追蹤、範圍限制與座標轉換。追蹤結果 X/Y 為 3584/4096,套用邊界後為 3072/3584。待套用期間 BG X 維持 13,提交後變為 8。附圖顯示相機位於 (8,16) 時,世界 (32,32) 的 32×24 矩形出現在畫面 (24,16)。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/camera.h:57
Set the shared camera from integer pixels, converting to the representable Q8.8 range.
kitaqgb/lib/camera.c:158
void camera_set(s16 x, s16 y)
{
Camera_Set(&camera_default, (s16)(x << 8), (s16)(y << 8));
}Camera_SetBounds
設定最小與最大座標、啟用範圍限制,並立即限制目前位置。
語法
void Camera_SetBounds(Camera8_8* cam, s16 min_fx, s16 min_fy, s16 max_fx, s16 max_fy);參數
cam指向已初始化且由呼叫端持有的
Camera8_8的有效指標。min_fx最小 X 座標。 帶正負號的 Q8.8 座標;256 為一個像素,範圍為 −128 到 127+255/256 像素。
min_fy最小 Y 座標。 帶正負號的 Q8.8 座標;256 為一個像素,範圍為 −128 到 127+255/256 像素。
max_fx最大 X 座標。 帶正負號的 Q8.8 座標;256 為一個像素,範圍為 −128 到 127+255/256 像素。
max_fy最大 Y 座標。 帶正負號的 Q8.8 座標;256 為一個像素,範圍為 −128 到 127+255/256 像素。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
各軸請傳入最小值 ≤ 最大值的邊界;函式不會重新排序邊界。已儲存的目標不會被限制。
使用範例
Camera_SetBounds(&cam,0,0,3072,3584);result[10]=cam.fx;result[11]=cam.fy;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範 Q8.8 追蹤、範圍限制與座標轉換。追蹤結果 X/Y 為 3584/4096,套用邊界後為 3072/3584。待套用期間 BG X 維持 13,提交後變為 8。附圖顯示相機位於 (8,16) 時,世界 (32,32) 的 32×24 矩形出現在畫面 (24,16)。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/camera.h:29
Install ordered Q8.8 bounds, enable them and clamp the current position immediately.
kitaqgb/lib/camera.c:61
void Camera_SetBounds(Camera8_8* cam, s16 min_fx, s16 min_fy, s16 max_fx, s16 max_fy)
{
cam->min_fx = min_fx;
cam->min_fy = min_fy;
cam->max_fx = max_fx;
cam->max_fy = max_fy;
cam->use_bounds = 1;
Camera_ApplyBounds(cam);
}Camera_SetTarget
儲存目標並啟用追蹤,不移動目前位置。
語法
void Camera_SetTarget(Camera8_8* cam, s16 fx, s16 fy);參數
cam指向已初始化且由呼叫端持有的
Camera8_8的有效指標。fxX 座標。 帶正負號的 Q8.8 座標;256 為一個像素,範圍為 −128 到 127+255/256 像素。
fyY 座標。 帶正負號的 Q8.8 座標;256 為一個像素,範圍為 −128 到 127+255/256 像素。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
座標包含 8 個小數位元。位置、目標及中間運算的和與差都必須位於 s16 範圍內。請另外使用 Camera_ApplyBg 或緩衝區提交來更新顯示。
使用範例
Camera_SetTarget(&cam,4608,3072);result[5]=cam.use_target;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範 Q8.8 追蹤、範圍限制與座標轉換。追蹤結果 X/Y 為 3584/4096,套用邊界後為 3072/3584。待套用期間 BG X 維持 13,提交後變為 8。附圖顯示相機位於 (8,16) 時,世界 (32,32) 的 32×24 矩形出現在畫面 (24,16)。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/camera.h:25
Store a Q8.8 target and enable subsequent step-toward-target updates.
kitaqgb/lib/camera.c:47
void Camera_SetTarget(Camera8_8* cam, s16 fx, s16 fy)
{
cam->target_fx = fx;
cam->target_fy = fy;
cam->use_target = 1;
}Camera_StepTowardTarget
將剩餘距離向右位移後,以所得距離接近目標;停用追蹤時不執行任何動作。
語法
void Camera_StepTowardTarget(Camera8_8* cam, u8 shift);參數
cam指向已初始化且由呼叫端持有的
Camera8_8的有效指標。shift用於除以 2 的次方的指數:0 使用全部位移,1 使用一半;大於 7 的值會限制為 7。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
微小的正位移可能被截為零,微小的負位移則可能在算術右移後變成 −1。是否到達目標會在範圍限制前判定。因此,範圍外的目標可能讓追蹤持續啟用,也可能在最終受限位置仍不等於目標時清除追蹤狀態。
使用範例
Camera_StepTowardTarget(&cam,1);result[6]=cam.fx;result[7]=cam.fy;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範 Q8.8 追蹤、範圍限制與座標轉換。追蹤結果 X/Y 為 3584/4096,套用邊界後為 3072/3584。待套用期間 BG X 維持 13,提交後變為 8。附圖顯示相機位於 (8,16) 時,世界 (32,32) 的 32×24 矩形出現在畫面 (24,16)。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/camera.h:38
Move by the signed target delta shifted by 0..7 bits, then apply bounds. Quantization can make a small delta produce no movement; only exact equality clears targeting, and a target outside the bounds may remain active indefinitely.
kitaqgb/lib/camera.c:89
void Camera_StepTowardTarget(Camera8_8* cam, u8 shift)
{
s16 dx;
s16 dy;
if (cam->use_target == 0) return;
if (shift > 7) shift = 7;
// Keep target-minus-position differences within s16 as well as the individual positions.
dx = cam->target_fx - cam->fx;
dy = cam->target_fy - cam->fy;
if (dx != 0) cam->fx += (dx >> shift);
if (dy != 0) cam->fy += (dy >> shift);
if (cam->fx == cam->target_fx && cam->fy == cam->target_fy) cam->use_target = 0;
Camera_ApplyBounds(cam);
}camera_world_to_screen_x
從世界 X 減去共用相機 X 的整數部分,轉換成畫面 X。
語法
s16 camera_world_to_screen_x(s16 world_x);參數
world_x以整數像素表示的世界 X 座標;結果與中間差值必須位於
s16範圍內。
回傳值
以 s16 傳回轉換後的整數像素座標;不檢查可見性,也不裁切。
使用條件與限制
座標包含 8 個小數位元。位置、目標及中間運算的和與差都必須位於 s16 範圍內。請另外使用 Camera_ApplyBg 或緩衝區提交來更新顯示。 這些呼叫共用同一個相機;需要獨立相機物件時,請使用大寫開頭的 API。從整數像素轉換成 Q8.8 的位置必須位於 −128 到 127 之間。
使用範例
result[33]=camera_world_to_screen_x(20);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範 Q8.8 追蹤、範圍限制與座標轉換。追蹤結果 X/Y 為 3584/4096,套用邊界後為 3072/3584。待套用期間 BG X 維持 13,提交後變為 8。附圖顯示相機位於 (8,16) 時,世界 (32,32) 的 32×24 矩形出現在畫面 (24,16)。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/camera.h:66
Convert integer-pixel world X using the shared convenience camera.
kitaqgb/lib/camera.c:185
s16 camera_world_to_screen_x(s16 world_x)
{
return Camera_WorldToScreenX(&camera_default, world_x);
}camera_world_to_screen_y
從世界 Y 減去共用相機 Y 的整數部分,轉換成畫面 Y。
語法
s16 camera_world_to_screen_y(s16 world_y);參數
world_y以整數像素表示的世界 Y 座標;結果與中間差值必須位於
s16範圍內。
回傳值
以 s16 傳回轉換後的整數像素座標;不檢查可見性,也不裁切。
使用條件與限制
座標包含 8 個小數位元。位置、目標及中間運算的和與差都必須位於 s16 範圍內。請另外使用 Camera_ApplyBg 或緩衝區提交來更新顯示。 這些呼叫共用同一個相機;需要獨立相機物件時,請使用大寫開頭的 API。從整數像素轉換成 Q8.8 的位置必須位於 −128 到 127 之間。
使用範例
result[34]=camera_world_to_screen_y(20);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範 Q8.8 追蹤、範圍限制與座標轉換。追蹤結果 X/Y 為 3584/4096,套用邊界後為 3072/3584。待套用期間 BG X 維持 13,提交後變為 8。附圖顯示相機位於 (8,16) 時,世界 (32,32) 的 32×24 矩形出現在畫面 (24,16)。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/camera.h:68
Convert integer-pixel world Y using the shared convenience camera.
kitaqgb/lib/camera.c:191
s16 camera_world_to_screen_y(s16 world_y)
{
return Camera_WorldToScreenY(&camera_default, world_y);
}Camera_WorldToScreenX
從整數世界 X 座標減去相機 X 座標的整數部分,取得畫面 X 座標。
語法
s16 Camera_WorldToScreenX(const Camera8_8* cam, s16 world_x);參數
cam指向已初始化且由呼叫端持有的
Camera8_8的有效指標。world_x以整數像素表示的世界 X 座標;結果與中間差值必須位於
s16範圍內。
回傳值
以 s16 傳回轉換後的整數像素座標;不檢查可見性,也不裁切。
使用條件與限制
座標包含 8 個小數位元。位置、目標及中間運算的和與差都必須位於 s16 範圍內。請另外使用 Camera_ApplyBg 或緩衝區提交來更新顯示。
使用範例
result[17]=Camera_WorldToScreenX(&cam,40);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範 Q8.8 追蹤、範圍限制與座標轉換。追蹤結果 X/Y 為 3584/4096,套用邊界後為 3072/3584。待套用期間 BG X 維持 13,提交後變為 8。附圖顯示相機位於 (8,16) 時,世界 (32,32) 的 32×24 矩形出現在畫面 (24,16)。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/camera.h:48
Convert an integer-pixel world X by subtracting the camera's integer X component.
kitaqgb/lib/camera.c:134
s16 Camera_WorldToScreenX(const Camera8_8* cam, s16 world_x)
{
return (s16)(world_x - (cam->fx >> 8));
}Camera_WorldToScreenY
從整數世界 Y 座標減去相機 Y 座標的整數部分,取得畫面 Y 座標。
語法
s16 Camera_WorldToScreenY(const Camera8_8* cam, s16 world_y);參數
cam指向已初始化且由呼叫端持有的
Camera8_8的有效指標。world_y以整數像素表示的世界 Y 座標;結果與中間差值必須位於
s16範圍內。
回傳值
以 s16 傳回轉換後的整數像素座標;不檢查可見性,也不裁切。
使用條件與限制
座標包含 8 個小數位元。位置、目標及中間運算的和與差都必須位於 s16 範圍內。請另外使用 Camera_ApplyBg 或緩衝區提交來更新顯示。
使用範例
result[18]=Camera_WorldToScreenY(&cam,40);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範 Q8.8 追蹤、範圍限制與座標轉換。追蹤結果 X/Y 為 3584/4096,套用邊界後為 3072/3584。待套用期間 BG X 維持 13,提交後變為 8。附圖顯示相機位於 (8,16) 時,世界 (32,32) 的 32×24 矩形出現在畫面 (24,16)。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/camera.h:50
Convert an integer-pixel world Y by subtracting the camera's integer Y component.
kitaqgb/lib/camera.c:140
s16 Camera_WorldToScreenY(const Camera8_8* cam, s16 world_y)
{
return (s16)(world_y - (cam->fy >> 8));
}cgb_palette.h — CGB 背景與 OBJ 調色盤
cgb_palette.h與cgb_palette.c提供RGB15封裝及CGB調色盤即時更新。背景/視窗使用BG函式,精靈使用OBJ函式。單色及RGB分量函式修改一色,範圍函式寫入連續色彩字組,整組調色盤函式寫入4個字組。raw範圍函式使用絕對色彩槽位,暫存器內建函式使用位元組位置。透過地圖屬性或OAM另外指定調色盤歸屬。請如完整範例所示,只將實作包含至程式一次。
調色盤操作與具模式保護的暫存器寫入,在DMG模式下不寫入任何內容。此處safe指CGB模式檢查,不代表等待PPU可存取或禁止中斷。請在LCD關閉時設定,或在可存取的PPU階段內完成夠短的更新。函式不等待VBlank,也不保護多位元組更新免受中斷影響。
背景/視窗與OBJ調色盤屬於獨立儲存區。函式庫的色彩寫入會啟用索引自動遞增,並保留修改後的索引暫存器。OBJ顏色編號0雖可儲存及讀取,繪製精靈時仍為透明。
cgb_bg_color
此 API 在本機版中的差異,請參閱 2026-10-03 差異與驗證。
立即向背景/視窗調色盤寫入一個封裝的RGB15顏色。以調色盤編號和顏色編號選取32個色彩槽位之一;不修改圖塊資料,也不改變圖塊使用的調色盤。
語法
void cgb_bg_color(u8 palette_index, u8 color_index, u16 rgb15);參數
palette_index調色盤編號0~7,只使用低3位元(
& 7)。color_index所選調色盤內的顏色編號0~3,只使用低2位元(
& 3)。rgb15封裝的15位元RGB色彩,通常為0~32767。先寫入所給
u16的低位元組,再寫高位元組;函式庫不會明確清除位元15。可用CGB_RGB15或cgb_rgb15產生有效值。
回傳值
無(void)。
使用條件與限制
調色盤操作與具模式保護的暫存器寫入,在DMG模式下不寫入任何內容。此處safe指CGB模式檢查,不代表等待PPU可存取或禁止中斷。請在LCD關閉時設定,或在可存取的PPU階段內完成夠短的更新。函式不等待VBlank,也不保護多位元組更新免受中斷影響。
背景/視窗與OBJ調色盤屬於獨立儲存區。函式庫的色彩寫入會啟用索引自動遞增,並保留修改後的索引暫存器。OBJ顏色編號0雖可儲存及讀取,繪製精靈時仍為透明。
使用範例
cgb_bg_color(1,3,31); // Red background color 3 of palette 1.
expect_color(0,7,31);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本程式示範相同圖塊圖樣如何分別使用BG與OBJ的調色盤。每個三角形為8×8像素,從頂列左側1個像素逐列擴展到底列8個像素。在x=16、32、48、64、80、96、112處,y=24的BG行依序為紅、藍、綠、紅、藍、綠、紅;y=64的OBJ行依序為藍、綠、紅、藍、綠、紅、藍。各欄依序使用單色、RGB分量、索引範圍、整組調色盤、絕對範圍、標準暫存器名稱及暫存器別名寫入。
y=88處的7個8×8格依序顯示:紅色三角形(x=16)、bank 1中線寬1像素的藍色方框(32)、水平翻轉的綠色三角形(48)、垂直翻轉的紅色三角形(64)、雙向翻轉的藍色三角形(80)、位於紅色精靈前方且顏色0區域透出紅色的綠色三角形(96),以及關閉BG優先權後覆蓋三角形的實心紅色精靈(112)。座標以螢幕左上角為原點,單位為像素。空白處為白色,文字為黑色。
FAILED CHECKS 000表示RGB遮罩、含輸入2的布林旗標、調色盤索引回繞、跨調色盤寫入、在槽位31截斷、null/零長度不寫入,以及LCD關閉時的色彩讀回檢查均通過。測試4種組合:雙模式ROM分別在DMG與CGB執行、DMG專用ROM在DMG執行、CGB專用ROM在CGB執行。DMG下CGB MODE為0,三角形皆為黑色,bank與翻轉屬性不影響顯示,最下行最後兩格為黑色方塊。CGB測試中CGB MODE為1。未測試實機及LCD顯示期間的調色盤存取衝突。




建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/cgb_palette.h:22
Set one background color through the indexed palette wrapper.
kitaqgb/lib/cgb_palette.c:110
void cgb_bg_color(u8 palette_index, u8 color_index, u16 rgb15)
{
cgb__write_color_bg_raw(cgb__palette_color_slot(palette_index, color_index), rgb15);
}cgb_bg_colors
從指定的調色盤及起始顏色編號開始,向背景/視窗調色盤連續寫入RGB15色彩。可跨越每組4色的邊界,但會在整個32色儲存區的末端停止。
語法
void cgb_bg_colors(u8 palette_index, u8 start_color_index, const u16* colors, u8 color_count);參數
palette_index調色盤編號0~7,只使用低3位元(
& 7)。start_color_index所選調色盤內的顏色編號0~3,只使用低2位元(
& 3)。colors指向所需色彩字組的可讀
const u16*。呼叫期間立即讀取,不加入佇列。來源陣列及其ROM bank須保持可存取;不會自動切換bank。空指標不產生寫入。color_count色彩字組數量,不是位元組數,以
u8(0~255)傳入。0表示不操作。實際數量最多為32 - 正規化後的起始槽位,來源陣列也只讀取這些字組。
回傳值
無(void)。
使用條件與限制
調色盤操作與具模式保護的暫存器寫入,在DMG模式下不寫入任何內容。此處safe指CGB模式檢查,不代表等待PPU可存取或禁止中斷。請在LCD關閉時設定,或在可存取的PPU階段內完成夠短的更新。函式不等待VBlank,也不保護多位元組更新免受中斷影響。
背景/視窗與OBJ調色盤屬於獨立儲存區。函式庫的色彩寫入會啟用索引自動遞增,並保留修改後的索引暫存器。OBJ顏色編號0雖可儲存及讀取,繪製精靈時仍為透明。
使用範例
cgb_bg_colors(3,2,tail_green,2); // Two color words; color 3 becomes green.
expect_color(0,14,0); expect_color(0,15,992);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本程式示範相同圖塊圖樣如何分別使用BG與OBJ的調色盤。每個三角形為8×8像素,從頂列左側1個像素逐列擴展到底列8個像素。在x=16、32、48、64、80、96、112處,y=24的BG行依序為紅、藍、綠、紅、藍、綠、紅;y=64的OBJ行依序為藍、綠、紅、藍、綠、紅、藍。各欄依序使用單色、RGB分量、索引範圍、整組調色盤、絕對範圍、標準暫存器名稱及暫存器別名寫入。
y=88處的7個8×8格依序顯示:紅色三角形(x=16)、bank 1中線寬1像素的藍色方框(32)、水平翻轉的綠色三角形(48)、垂直翻轉的紅色三角形(64)、雙向翻轉的藍色三角形(80)、位於紅色精靈前方且顏色0區域透出紅色的綠色三角形(96),以及關閉BG優先權後覆蓋三角形的實心紅色精靈(112)。座標以螢幕左上角為原點,單位為像素。空白處為白色,文字為黑色。
FAILED CHECKS 000表示RGB遮罩、含輸入2的布林旗標、調色盤索引回繞、跨調色盤寫入、在槽位31截斷、null/零長度不寫入,以及LCD關閉時的色彩讀回檢查均通過。測試4種組合:雙模式ROM分別在DMG與CGB執行、DMG專用ROM在DMG執行、CGB專用ROM在CGB執行。DMG下CGB MODE為0,三角形皆為黑色,bank與翻轉屬性不影響顯示,最下行最後兩格為黑色方塊。CGB測試中CGB MODE為1。未測試實機及LCD顯示期間的調色盤存取衝突。




建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/cgb_palette.h:32
Write background colors starting at the indexed slot. The range may cross palette boundaries and is clamped only at the end of all 32 slots.
kitaqgb/lib/cgb_palette.c:135
void cgb_bg_colors(u8 palette_index, u8 start_color_index, const u16* colors, u8 color_count)
{
cgb__write_colors_bg_raw(cgb__palette_color_slot(palette_index, start_color_index), colors, color_count);
}cgb_bg_colors_raw
使用絕對色彩槽位編號,向背景/視窗調色盤連續寫入RGB15值。起點是0~31的單一編號,而非調色盤編號與顏色編號的組合。輸入為色彩字組陣列,不是原始圖塊位元組。
語法
void cgb_bg_colors_raw(u8 start_color_slot, const u16* colors, u8 color_count);參數
start_color_slot絕對色彩槽位0~31,先以
& 31正規化,再限制寫入數量。槽位=調色盤編號×4+顏色編號,不是位元組偏移。colors指向所需色彩字組的可讀
const u16*。呼叫期間立即讀取,不加入佇列。來源陣列及其ROM bank須保持可存取;不會自動切換bank。空指標不產生寫入。color_count色彩字組數量,不是位元組數,以
u8(0~255)傳入。0表示不操作。實際數量最多為32 - 正規化後的起始槽位,來源陣列也只讀取這些字組。
回傳值
無(void)。
使用條件與限制
調色盤操作與具模式保護的暫存器寫入,在DMG模式下不寫入任何內容。此處safe指CGB模式檢查,不代表等待PPU可存取或禁止中斷。請在LCD關閉時設定,或在可存取的PPU階段內完成夠短的更新。函式不等待VBlank,也不保護多位元組更新免受中斷影響。
背景/視窗與OBJ調色盤屬於獨立儲存區。函式庫的色彩寫入會啟用索引自動遞增,並保留修改後的索引暫存器。OBJ顏色編號0雖可儲存及讀取,繪製精靈時仍為透明。
使用範例
cgb_bg_colors_raw(23,blue_word,1); // Absolute slot 23 = palette 5, color 3.
expect_color(0,23,31744);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本程式示範相同圖塊圖樣如何分別使用BG與OBJ的調色盤。每個三角形為8×8像素,從頂列左側1個像素逐列擴展到底列8個像素。在x=16、32、48、64、80、96、112處,y=24的BG行依序為紅、藍、綠、紅、藍、綠、紅;y=64的OBJ行依序為藍、綠、紅、藍、綠、紅、藍。各欄依序使用單色、RGB分量、索引範圍、整組調色盤、絕對範圍、標準暫存器名稱及暫存器別名寫入。
y=88處的7個8×8格依序顯示:紅色三角形(x=16)、bank 1中線寬1像素的藍色方框(32)、水平翻轉的綠色三角形(48)、垂直翻轉的紅色三角形(64)、雙向翻轉的藍色三角形(80)、位於紅色精靈前方且顏色0區域透出紅色的綠色三角形(96),以及關閉BG優先權後覆蓋三角形的實心紅色精靈(112)。座標以螢幕左上角為原點,單位為像素。空白處為白色,文字為黑色。
FAILED CHECKS 000表示RGB遮罩、含輸入2的布林旗標、調色盤索引回繞、跨調色盤寫入、在槽位31截斷、null/零長度不寫入,以及LCD關閉時的色彩讀回檢查均通過。測試4種組合:雙模式ROM分別在DMG與CGB執行、DMG專用ROM在DMG執行、CGB專用ROM在CGB執行。DMG下CGB MODE為0,三角形皆為黑色,bank與翻轉屬性不影響顯示,最下行最後兩格為黑色方塊。CGB測試中CGB MODE為1。未測試實機及LCD顯示期間的調色盤存取衝突。




建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/cgb_palette.h:42
Expose sequential background writes using an absolute color-slot index.
kitaqgb/lib/cgb_palette.c:159
void cgb_bg_colors_raw(u8 start_color_slot, const u16* colors, u8 color_count)
{
cgb__write_colors_bg_raw(start_color_slot, colors, color_count);
}cgb_bg_palette
以4個RGB15值設定一組背景/視窗調色盤的全部4色。相當於從顏色0開始寫入4色;不會替圖塊或精靈選取此調色盤。
語法
void cgb_bg_palette(u8 palette_index, const u16* colors);參數
palette_index調色盤編號0~7,只使用低3位元(
& 7)。colors指向所需色彩字組的可讀
const u16*。呼叫期間立即讀取,不加入佇列。來源陣列及其ROM bank須保持可存取;不會自動切換bank。空指標不產生寫入。
回傳值
無(void)。
使用條件與限制
調色盤操作與具模式保護的暫存器寫入,在DMG模式下不寫入任何內容。此處safe指CGB模式檢查,不代表等待PPU可存取或禁止中斷。請在LCD關閉時設定,或在可存取的PPU階段內完成夠短的更新。函式不等待VBlank,也不保護多位元組更新免受中斷影響。
背景/視窗與OBJ調色盤屬於獨立儲存區。函式庫的色彩寫入會啟用索引自動遞增,並保留修改後的索引暫存器。OBJ顏色編號0雖可儲存及讀取,繪製精靈時仍為透明。
使用範例
cgb_bg_palette(4,red_palette); // Exactly four color words for BG palette 4.
expect_color(0,16,32767); expect_color(0,19,31);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本程式示範相同圖塊圖樣如何分別使用BG與OBJ的調色盤。每個三角形為8×8像素,從頂列左側1個像素逐列擴展到底列8個像素。在x=16、32、48、64、80、96、112處,y=24的BG行依序為紅、藍、綠、紅、藍、綠、紅;y=64的OBJ行依序為藍、綠、紅、藍、綠、紅、藍。各欄依序使用單色、RGB分量、索引範圍、整組調色盤、絕對範圍、標準暫存器名稱及暫存器別名寫入。
y=88處的7個8×8格依序顯示:紅色三角形(x=16)、bank 1中線寬1像素的藍色方框(32)、水平翻轉的綠色三角形(48)、垂直翻轉的紅色三角形(64)、雙向翻轉的藍色三角形(80)、位於紅色精靈前方且顏色0區域透出紅色的綠色三角形(96),以及關閉BG優先權後覆蓋三角形的實心紅色精靈(112)。座標以螢幕左上角為原點,單位為像素。空白處為白色,文字為黑色。
FAILED CHECKS 000表示RGB遮罩、含輸入2的布林旗標、調色盤索引回繞、跨調色盤寫入、在槽位31截斷、null/零長度不寫入,以及LCD關閉時的色彩讀回檢查均通過。測試4種組合:雙模式ROM分別在DMG與CGB執行、DMG專用ROM在DMG執行、CGB專用ROM在CGB執行。DMG下CGB MODE為0,三角形皆為黑色,bank與翻轉屬性不影響顯示,最下行最後兩格為黑色方塊。CGB測試中CGB MODE為1。未測試實機及LCD顯示期間的調色盤存取衝突。




建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/cgb_palette.h:37
Write four consecutive colors for one background palette.
kitaqgb/lib/cgb_palette.c:147
void cgb_bg_palette(u8 palette_index, const u16* colors)
{
cgb_bg_colors(palette_index, 0, colors, 4);
}cgb_bg_rgb
此 API 在本機版中的差異,請參閱 2026-10-03 差異與驗證。
以cgb_rgb15封裝紅、綠、藍分量,再向背景/視窗調色盤寫入一個顏色。適合分別提供三個分量,而非封裝色彩值的情況。
語法
void cgb_bg_rgb(u8 palette_index, u8 color_index, u8 r5, u8 g5, u8 b5);參數
palette_index調色盤編號0~7,只使用低3位元(
& 7)。color_index所選調色盤內的顏色編號0~3,只使用低2位元(
& 3)。r5, g5, b5依序為紅、綠、藍分量,通常各為0~31。使用遮罩,不做飽和處理;巨集展開中每個引數出現一次。
回傳值
無(void)。
使用條件與限制
調色盤操作與具模式保護的暫存器寫入,在DMG模式下不寫入任何內容。此處safe指CGB模式檢查,不代表等待PPU可存取或禁止中斷。請在LCD關閉時設定,或在可存取的PPU階段內完成夠短的更新。函式不等待VBlank,也不保護多位元組更新免受中斷影響。
背景/視窗與OBJ調色盤屬於獨立儲存區。函式庫的色彩寫入會啟用索引自動遞增,並保留修改後的索引暫存器。OBJ顏色編號0雖可儲存及讀取,繪製精靈時仍為透明。
使用範例
cgb_bg_rgb(2,3,0,0,31); // Blue, supplied as three five-bit components.
expect_color(0,11,31744);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本程式示範相同圖塊圖樣如何分別使用BG與OBJ的調色盤。每個三角形為8×8像素,從頂列左側1個像素逐列擴展到底列8個像素。在x=16、32、48、64、80、96、112處,y=24的BG行依序為紅、藍、綠、紅、藍、綠、紅;y=64的OBJ行依序為藍、綠、紅、藍、綠、紅、藍。各欄依序使用單色、RGB分量、索引範圍、整組調色盤、絕對範圍、標準暫存器名稱及暫存器別名寫入。
y=88處的7個8×8格依序顯示:紅色三角形(x=16)、bank 1中線寬1像素的藍色方框(32)、水平翻轉的綠色三角形(48)、垂直翻轉的紅色三角形(64)、雙向翻轉的藍色三角形(80)、位於紅色精靈前方且顏色0區域透出紅色的綠色三角形(96),以及關閉BG優先權後覆蓋三角形的實心紅色精靈(112)。座標以螢幕左上角為原點,單位為像素。空白處為白色,文字為黑色。
FAILED CHECKS 000表示RGB遮罩、含輸入2的布林旗標、調色盤索引回繞、跨調色盤寫入、在槽位31截斷、null/零長度不寫入,以及LCD關閉時的色彩讀回檢查均通過。測試4種組合:雙模式ROM分別在DMG與CGB執行、DMG專用ROM在DMG執行、CGB專用ROM在CGB執行。DMG下CGB MODE為0,三角形皆為黑色,bank與翻轉屬性不影響顯示,最下行最後兩格為黑色方塊。CGB測試中CGB MODE為1。未測試實機及LCD顯示期間的調色盤存取衝突。




建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/cgb_palette.h:26
Pack component values and write one background color.
kitaqgb/lib/cgb_palette.c:122
void cgb_bg_rgb(u8 palette_index, u8 color_index, u8 r5, u8 g5, u8 b5)
{
cgb_bg_color(palette_index, color_index, cgb_rgb15(r5, g5, b5));
}cgb_obj_color
此 API 在本機版中的差異,請參閱 2026-10-03 差異與驗證。
立即向精靈(OBJ)調色盤寫入一個封裝的RGB15顏色。以調色盤編號和顏色編號選取32個色彩槽位之一;不修改圖塊資料,也不改變圖塊使用的調色盤。
語法
void cgb_obj_color(u8 palette_index, u8 color_index, u16 rgb15);參數
palette_index調色盤編號0~7,只使用低3位元(
& 7)。color_index所選調色盤內的顏色編號0~3,只使用低2位元(
& 3)。rgb15封裝的15位元RGB色彩,通常為0~32767。先寫入所給
u16的低位元組,再寫高位元組;函式庫不會明確清除位元15。可用CGB_RGB15或cgb_rgb15產生有效值。
回傳值
無(void)。
使用條件與限制
調色盤操作與具模式保護的暫存器寫入,在DMG模式下不寫入任何內容。此處safe指CGB模式檢查,不代表等待PPU可存取或禁止中斷。請在LCD關閉時設定,或在可存取的PPU階段內完成夠短的更新。函式不等待VBlank,也不保護多位元組更新免受中斷影響。
背景/視窗與OBJ調色盤屬於獨立儲存區。函式庫的色彩寫入會啟用索引自動遞增,並保留修改後的索引暫存器。OBJ顏色編號0雖可儲存及讀取,繪製精靈時仍為透明。
使用範例
cgb_obj_color(1,3,31744); // Blue sprite color at the same palette/color indices.
expect_color(1,7,31744);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本程式示範相同圖塊圖樣如何分別使用BG與OBJ的調色盤。每個三角形為8×8像素,從頂列左側1個像素逐列擴展到底列8個像素。在x=16、32、48、64、80、96、112處,y=24的BG行依序為紅、藍、綠、紅、藍、綠、紅;y=64的OBJ行依序為藍、綠、紅、藍、綠、紅、藍。各欄依序使用單色、RGB分量、索引範圍、整組調色盤、絕對範圍、標準暫存器名稱及暫存器別名寫入。
y=88處的7個8×8格依序顯示:紅色三角形(x=16)、bank 1中線寬1像素的藍色方框(32)、水平翻轉的綠色三角形(48)、垂直翻轉的紅色三角形(64)、雙向翻轉的藍色三角形(80)、位於紅色精靈前方且顏色0區域透出紅色的綠色三角形(96),以及關閉BG優先權後覆蓋三角形的實心紅色精靈(112)。座標以螢幕左上角為原點,單位為像素。空白處為白色,文字為黑色。
FAILED CHECKS 000表示RGB遮罩、含輸入2的布林旗標、調色盤索引回繞、跨調色盤寫入、在槽位31截斷、null/零長度不寫入,以及LCD關閉時的色彩讀回檢查均通過。測試4種組合:雙模式ROM分別在DMG與CGB執行、DMG專用ROM在DMG執行、CGB專用ROM在CGB執行。DMG下CGB MODE為0,三角形皆為黑色,bank與翻轉屬性不影響顯示,最下行最後兩格為黑色方塊。CGB測試中CGB MODE為1。未測試實機及LCD顯示期間的調色盤存取衝突。




建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/cgb_palette.h:24
Set one object color through the indexed palette wrapper.
kitaqgb/lib/cgb_palette.c:116
void cgb_obj_color(u8 palette_index, u8 color_index, u16 rgb15)
{
cgb__write_color_obj_raw(cgb__palette_color_slot(palette_index, color_index), rgb15);
}cgb_obj_colors
從指定的調色盤及起始顏色編號開始,向精靈(OBJ)調色盤連續寫入RGB15色彩。可跨越每組4色的邊界,但會在整個32色儲存區的末端停止。
語法
void cgb_obj_colors(u8 palette_index, u8 start_color_index, const u16* colors, u8 color_count);參數
palette_index調色盤編號0~7,只使用低3位元(
& 7)。start_color_index所選調色盤內的顏色編號0~3,只使用低2位元(
& 3)。colors指向所需色彩字組的可讀
const u16*。呼叫期間立即讀取,不加入佇列。來源陣列及其ROM bank須保持可存取;不會自動切換bank。空指標不產生寫入。color_count色彩字組數量,不是位元組數,以
u8(0~255)傳入。0表示不操作。實際數量最多為32 - 正規化後的起始槽位,來源陣列也只讀取這些字組。
回傳值
無(void)。
使用條件與限制
調色盤操作與具模式保護的暫存器寫入,在DMG模式下不寫入任何內容。此處safe指CGB模式檢查,不代表等待PPU可存取或禁止中斷。請在LCD關閉時設定,或在可存取的PPU階段內完成夠短的更新。函式不等待VBlank,也不保護多位元組更新免受中斷影響。
背景/視窗與OBJ調色盤屬於獨立儲存區。函式庫的色彩寫入會啟用索引自動遞增,並保留修改後的索引暫存器。OBJ顏色編號0雖可儲存及讀取,繪製精靈時仍為透明。
使用範例
cgb_obj_colors(3,2,tail_red,2); // Sprite color 3 becomes red.
expect_color(1,14,0); expect_color(1,15,31);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本程式示範相同圖塊圖樣如何分別使用BG與OBJ的調色盤。每個三角形為8×8像素,從頂列左側1個像素逐列擴展到底列8個像素。在x=16、32、48、64、80、96、112處,y=24的BG行依序為紅、藍、綠、紅、藍、綠、紅;y=64的OBJ行依序為藍、綠、紅、藍、綠、紅、藍。各欄依序使用單色、RGB分量、索引範圍、整組調色盤、絕對範圍、標準暫存器名稱及暫存器別名寫入。
y=88處的7個8×8格依序顯示:紅色三角形(x=16)、bank 1中線寬1像素的藍色方框(32)、水平翻轉的綠色三角形(48)、垂直翻轉的紅色三角形(64)、雙向翻轉的藍色三角形(80)、位於紅色精靈前方且顏色0區域透出紅色的綠色三角形(96),以及關閉BG優先權後覆蓋三角形的實心紅色精靈(112)。座標以螢幕左上角為原點,單位為像素。空白處為白色,文字為黑色。
FAILED CHECKS 000表示RGB遮罩、含輸入2的布林旗標、調色盤索引回繞、跨調色盤寫入、在槽位31截斷、null/零長度不寫入,以及LCD關閉時的色彩讀回檢查均通過。測試4種組合:雙模式ROM分別在DMG與CGB執行、DMG專用ROM在DMG執行、CGB專用ROM在CGB執行。DMG下CGB MODE為0,三角形皆為黑色,bank與翻轉屬性不影響顯示,最下行最後兩格為黑色方塊。CGB測試中CGB MODE為1。未測試實機及LCD顯示期間的調色盤存取衝突。




建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/cgb_palette.h:34
Write object colors from the indexed slot, potentially crossing into later palettes.
kitaqgb/lib/cgb_palette.c:141
void cgb_obj_colors(u8 palette_index, u8 start_color_index, const u16* colors, u8 color_count)
{
cgb__write_colors_obj_raw(cgb__palette_color_slot(palette_index, start_color_index), colors, color_count);
}cgb_obj_colors_raw
使用絕對色彩槽位編號,向精靈(OBJ)調色盤連續寫入RGB15值。起點是0~31的單一編號,而非調色盤編號與顏色編號的組合。輸入為色彩字組陣列,不是原始圖塊位元組。
語法
void cgb_obj_colors_raw(u8 start_color_slot, const u16* colors, u8 color_count);參數
start_color_slot絕對色彩槽位0~31,先以
& 31正規化,再限制寫入數量。槽位=調色盤編號×4+顏色編號,不是位元組偏移。colors指向所需色彩字組的可讀
const u16*。呼叫期間立即讀取,不加入佇列。來源陣列及其ROM bank須保持可存取;不會自動切換bank。空指標不產生寫入。color_count色彩字組數量,不是位元組數,以
u8(0~255)傳入。0表示不操作。實際數量最多為32 - 正規化後的起始槽位,來源陣列也只讀取這些字組。
回傳值
無(void)。
使用條件與限制
調色盤操作與具模式保護的暫存器寫入,在DMG模式下不寫入任何內容。此處safe指CGB模式檢查,不代表等待PPU可存取或禁止中斷。請在LCD關閉時設定,或在可存取的PPU階段內完成夠短的更新。函式不等待VBlank,也不保護多位元組更新免受中斷影響。
背景/視窗與OBJ調色盤屬於獨立儲存區。函式庫的色彩寫入會啟用索引自動遞增,並保留修改後的索引暫存器。OBJ顏色編號0雖可儲存及讀取,繪製精靈時仍為透明。
使用範例
cgb_obj_colors_raw(23,green_word,1); // Same absolute slot in the separate OBJ store.
expect_color(1,23,992);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本程式示範相同圖塊圖樣如何分別使用BG與OBJ的調色盤。每個三角形為8×8像素,從頂列左側1個像素逐列擴展到底列8個像素。在x=16、32、48、64、80、96、112處,y=24的BG行依序為紅、藍、綠、紅、藍、綠、紅;y=64的OBJ行依序為藍、綠、紅、藍、綠、紅、藍。各欄依序使用單色、RGB分量、索引範圍、整組調色盤、絕對範圍、標準暫存器名稱及暫存器別名寫入。
y=88處的7個8×8格依序顯示:紅色三角形(x=16)、bank 1中線寬1像素的藍色方框(32)、水平翻轉的綠色三角形(48)、垂直翻轉的紅色三角形(64)、雙向翻轉的藍色三角形(80)、位於紅色精靈前方且顏色0區域透出紅色的綠色三角形(96),以及關閉BG優先權後覆蓋三角形的實心紅色精靈(112)。座標以螢幕左上角為原點,單位為像素。空白處為白色,文字為黑色。
FAILED CHECKS 000表示RGB遮罩、含輸入2的布林旗標、調色盤索引回繞、跨調色盤寫入、在槽位31截斷、null/零長度不寫入,以及LCD關閉時的色彩讀回檢查均通過。測試4種組合:雙模式ROM分別在DMG與CGB執行、DMG專用ROM在DMG執行、CGB專用ROM在CGB執行。DMG下CGB MODE為0,三角形皆為黑色,bank與翻轉屬性不影響顯示,最下行最後兩格為黑色方塊。CGB測試中CGB MODE為1。未測試實機及LCD顯示期間的調色盤存取衝突。




建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/cgb_palette.h:44
Expose sequential object writes using an absolute color-slot index.
kitaqgb/lib/cgb_palette.c:165
void cgb_obj_colors_raw(u8 start_color_slot, const u16* colors, u8 color_count)
{
cgb__write_colors_obj_raw(start_color_slot, colors, color_count);
}cgb_obj_palette
以4個RGB15值設定一組精靈(OBJ)調色盤的全部4色。相當於從顏色0開始寫入4色;不會替圖塊或精靈選取此調色盤。
語法
void cgb_obj_palette(u8 palette_index, const u16* colors);參數
palette_index調色盤編號0~7,只使用低3位元(
& 7)。colors指向所需色彩字組的可讀
const u16*。呼叫期間立即讀取,不加入佇列。來源陣列及其ROM bank須保持可存取;不會自動切換bank。空指標不產生寫入。
回傳值
無(void)。
使用條件與限制
調色盤操作與具模式保護的暫存器寫入,在DMG模式下不寫入任何內容。此處safe指CGB模式檢查,不代表等待PPU可存取或禁止中斷。請在LCD關閉時設定,或在可存取的PPU階段內完成夠短的更新。函式不等待VBlank,也不保護多位元組更新免受中斷影響。
背景/視窗與OBJ調色盤屬於獨立儲存區。函式庫的色彩寫入會啟用索引自動遞增,並保留修改後的索引暫存器。OBJ顏色編號0雖可儲存及讀取,繪製精靈時仍為透明。
使用範例
cgb_obj_palette(4,blue_palette); // Exactly four words; OBJ color zero is transparent on screen.
expect_color(1,16,32767); expect_color(1,19,31744);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本程式示範相同圖塊圖樣如何分別使用BG與OBJ的調色盤。每個三角形為8×8像素,從頂列左側1個像素逐列擴展到底列8個像素。在x=16、32、48、64、80、96、112處,y=24的BG行依序為紅、藍、綠、紅、藍、綠、紅;y=64的OBJ行依序為藍、綠、紅、藍、綠、紅、藍。各欄依序使用單色、RGB分量、索引範圍、整組調色盤、絕對範圍、標準暫存器名稱及暫存器別名寫入。
y=88處的7個8×8格依序顯示:紅色三角形(x=16)、bank 1中線寬1像素的藍色方框(32)、水平翻轉的綠色三角形(48)、垂直翻轉的紅色三角形(64)、雙向翻轉的藍色三角形(80)、位於紅色精靈前方且顏色0區域透出紅色的綠色三角形(96),以及關閉BG優先權後覆蓋三角形的實心紅色精靈(112)。座標以螢幕左上角為原點,單位為像素。空白處為白色,文字為黑色。
FAILED CHECKS 000表示RGB遮罩、含輸入2的布林旗標、調色盤索引回繞、跨調色盤寫入、在槽位31截斷、null/零長度不寫入,以及LCD關閉時的色彩讀回檢查均通過。測試4種組合:雙模式ROM分別在DMG與CGB執行、DMG專用ROM在DMG執行、CGB專用ROM在CGB執行。DMG下CGB MODE為0,三角形皆為黑色,bank與翻轉屬性不影響顯示,最下行最後兩格為黑色方塊。CGB測試中CGB MODE為1。未測試實機及LCD顯示期間的調色盤存取衝突。




建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/cgb_palette.h:39
Write four consecutive colors for one object palette.
kitaqgb/lib/cgb_palette.c:153
void cgb_obj_palette(u8 palette_index, const u16* colors)
{
cgb_obj_colors(palette_index, 0, colors, 4);
}cgb_obj_rgb
此 API 在本機版中的差異,請參閱 2026-10-03 差異與驗證。
以cgb_rgb15封裝紅、綠、藍分量,再向精靈(OBJ)調色盤寫入一個顏色。適合分別提供三個分量,而非封裝色彩值的情況。
語法
void cgb_obj_rgb(u8 palette_index, u8 color_index, u8 r5, u8 g5, u8 b5);參數
palette_index調色盤編號0~7,只使用低3位元(
& 7)。color_index所選調色盤內的顏色編號0~3,只使用低2位元(
& 3)。r5, g5, b5依序為紅、綠、藍分量,通常各為0~31。使用遮罩,不做飽和處理;巨集展開中每個引數出現一次。
回傳值
無(void)。
使用條件與限制
調色盤操作與具模式保護的暫存器寫入,在DMG模式下不寫入任何內容。此處safe指CGB模式檢查,不代表等待PPU可存取或禁止中斷。請在LCD關閉時設定,或在可存取的PPU階段內完成夠短的更新。函式不等待VBlank,也不保護多位元組更新免受中斷影響。
背景/視窗與OBJ調色盤屬於獨立儲存區。函式庫的色彩寫入會啟用索引自動遞增,並保留修改後的索引暫存器。OBJ顏色編號0雖可儲存及讀取,繪製精靈時仍為透明。
使用範例
cgb_obj_rgb(2,3,0,31,0); // Green sprite color.
expect_color(1,11,992);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本程式示範相同圖塊圖樣如何分別使用BG與OBJ的調色盤。每個三角形為8×8像素,從頂列左側1個像素逐列擴展到底列8個像素。在x=16、32、48、64、80、96、112處,y=24的BG行依序為紅、藍、綠、紅、藍、綠、紅;y=64的OBJ行依序為藍、綠、紅、藍、綠、紅、藍。各欄依序使用單色、RGB分量、索引範圍、整組調色盤、絕對範圍、標準暫存器名稱及暫存器別名寫入。
y=88處的7個8×8格依序顯示:紅色三角形(x=16)、bank 1中線寬1像素的藍色方框(32)、水平翻轉的綠色三角形(48)、垂直翻轉的紅色三角形(64)、雙向翻轉的藍色三角形(80)、位於紅色精靈前方且顏色0區域透出紅色的綠色三角形(96),以及關閉BG優先權後覆蓋三角形的實心紅色精靈(112)。座標以螢幕左上角為原點,單位為像素。空白處為白色,文字為黑色。
FAILED CHECKS 000表示RGB遮罩、含輸入2的布林旗標、調色盤索引回繞、跨調色盤寫入、在槽位31截斷、null/零長度不寫入,以及LCD關閉時的色彩讀回檢查均通過。測試4種組合:雙模式ROM分別在DMG與CGB執行、DMG專用ROM在DMG執行、CGB專用ROM在CGB執行。DMG下CGB MODE為0,三角形皆為黑色,bank與翻轉屬性不影響顯示,最下行最後兩格為黑色方塊。CGB測試中CGB MODE為1。未測試實機及LCD顯示期間的調色盤存取衝突。




建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/cgb_palette.h:28
Pack component values and write one object color.
kitaqgb/lib/cgb_palette.c:128
void cgb_obj_rgb(u8 palette_index, u8 color_index, u8 r5, u8 g5, u8 b5)
{
cgb_obj_color(palette_index, color_index, cgb_rgb15(r5, g5, b5));
}CGB_RGB15
將RGB分量封裝為u16:紅色佔位元0~4,綠色佔5~9,藍色佔10~14,位元15為0。各分量以31遮罩保留低5位,超出範圍時不會限制在上限。只計算數值,不寫入硬體;DMG與CGB皆可使用。
語法
#define CGB_RGB15(r5, g5, b5) ((u16)((u16)((r5) & 31) | ((u16)((g5) & 31) << 5) | ((u16)((b5) & 31) << 10)))參數
r5, g5, b5依序為紅、綠、藍分量,通常各為0~31。使用遮罩,不做飽和處理;巨集展開中每個引數出現一次。
回傳值
封裝的RGB15值,型別為u16,範圍0~32767。
使用範例
if (CGB_RGB15(component,64,95)!=31775) failures++; // (31,0,31), not saturation.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本程式示範相同圖塊圖樣如何分別使用BG與OBJ的調色盤。每個三角形為8×8像素,從頂列左側1個像素逐列擴展到底列8個像素。在x=16、32、48、64、80、96、112處,y=24的BG行依序為紅、藍、綠、紅、藍、綠、紅;y=64的OBJ行依序為藍、綠、紅、藍、綠、紅、藍。各欄依序使用單色、RGB分量、索引範圍、整組調色盤、絕對範圍、標準暫存器名稱及暫存器別名寫入。
y=88處的7個8×8格依序顯示:紅色三角形(x=16)、bank 1中線寬1像素的藍色方框(32)、水平翻轉的綠色三角形(48)、垂直翻轉的紅色三角形(64)、雙向翻轉的藍色三角形(80)、位於紅色精靈前方且顏色0區域透出紅色的綠色三角形(96),以及關閉BG優先權後覆蓋三角形的實心紅色精靈(112)。座標以螢幕左上角為原點,單位為像素。空白處為白色,文字為黑色。
FAILED CHECKS 000表示RGB遮罩、含輸入2的布林旗標、調色盤索引回繞、跨調色盤寫入、在槽位31截斷、null/零長度不寫入,以及LCD關閉時的色彩讀回檢查均通過。測試4種組合:雙模式ROM分別在DMG與CGB執行、DMG專用ROM在DMG執行、CGB專用ROM在CGB執行。DMG下CGB MODE為0,三角形皆為黑色,bank與翻轉屬性不影響顯示,最下行最後兩格為黑色方塊。CGB測試中CGB MODE為1。未測試實機及LCD顯示期間的調色盤存取衝突。




建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/cgb_palette.h:16
cgb_rgb15
將RGB分量封裝為u16:紅色佔位元0~4,綠色佔5~9,藍色佔10~14,位元15為0。各分量以31遮罩保留低5位,超出範圍時不會限制在上限。只計算數值,不寫入硬體;DMG與CGB皆可使用。
語法
u16 cgb_rgb15(u8 r5, u8 g5, u8 b5);參數
r5, g5, b5依序為紅、綠、藍分量,通常各為0~31。使用遮罩,不做飽和處理;巨集展開中每個引數出現一次。
回傳值
封裝的RGB15值,型別為u16,範圍0~32767。
使用範例
if (cgb_rgb15(component,64,95)!=31775) failures++; // Same packed value through a function.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本程式示範相同圖塊圖樣如何分別使用BG與OBJ的調色盤。每個三角形為8×8像素,從頂列左側1個像素逐列擴展到底列8個像素。在x=16、32、48、64、80、96、112處,y=24的BG行依序為紅、藍、綠、紅、藍、綠、紅;y=64的OBJ行依序為藍、綠、紅、藍、綠、紅、藍。各欄依序使用單色、RGB分量、索引範圍、整組調色盤、絕對範圍、標準暫存器名稱及暫存器別名寫入。
y=88處的7個8×8格依序顯示:紅色三角形(x=16)、bank 1中線寬1像素的藍色方框(32)、水平翻轉的綠色三角形(48)、垂直翻轉的紅色三角形(64)、雙向翻轉的藍色三角形(80)、位於紅色精靈前方且顏色0區域透出紅色的綠色三角形(96),以及關閉BG優先權後覆蓋三角形的實心紅色精靈(112)。座標以螢幕左上角為原點,單位為像素。空白處為白色,文字為黑色。
FAILED CHECKS 000表示RGB遮罩、含輸入2的布林旗標、調色盤索引回繞、跨調色盤寫入、在槽位31截斷、null/零長度不寫入,以及LCD關閉時的色彩讀回檢查均通過。測試4種組合:雙模式ROM分別在DMG與CGB執行、DMG專用ROM在DMG執行、CGB專用ROM在CGB執行。DMG下CGB MODE為0,三角形皆為黑色,bank與翻轉屬性不影響顯示,最下行最後兩格為黑色方塊。CGB測試中CGB MODE為1。未測試實機及LCD顯示期間的調色盤存取衝突。




建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/cgb_palette.h:19
Pack the red, green and blue components using the public RGB15 macro.
kitaqgb/lib/cgb_palette.c:104
u16 cgb_rgb15(u8 r5, u8 g5, u8 b5)
{
return CGB_RGB15(r5, g5, b5);
}cgb_tile.h — CGB 圖塊編號與屬性
cgb_tile.h 收錄圖塊映射內建函式宣告,以及組合 CGB 圖塊屬性的巨集。圖塊編號選擇圖樣;屬性選擇調色盤、圖樣 VRAM 記憶體庫、翻轉與背景優先權。設定屬性不會改變圖樣像素。
__settile 系列使用映射表 0x9800;__settileat 使用明確指定的基底位址;__settilebg 使用 LCDC 選定的背景映射表;__settilewin 使用其視窗映射表。attr 形式只寫屬性,cgb 形式同時寫圖塊編號與屬性。bulk 形式在指定位置傳輸連續位元組。請依目的地及寫入資料選擇入口函式。
個別屬性位元可用 KQ_CGB_ATTR_PAL 等巨集,合併欄位則用 KQ_CGB_ATTR。bank 欄位選擇存放圖樣的 VRAM 記憶體庫,不是 ROM 記憶體庫。一般圖塊編號寫入使用目前 VRAM 記憶體庫,因此執行圖塊/屬性合併操作前請選取記憶體庫零。DMG 上只寫屬性的操作不做任何事;合併操作仍會寫入圖塊編號。
__ 內建函式由編譯器產生實作,不必連結 cgb_tile.c。一般寫入路徑會等待 VRAM 可存取,但部分也會改變中斷啟用狀態。_unsafe 與 _fast 形式省略等待,只能在呼叫端保證 VRAM 可寫入時使用,例如 LCD 關閉時。請檢查各項的中斷、記憶體庫及傳輸長度條件。
KQ_CGB_ATTR
以調色盤、圖塊資料bank、水平翻轉、垂直翻轉與BG優先權建立完整的CGB地圖屬性位元組。調色盤佔位元0~2,四個布林欄位依序設定位元3、5、6、7,位元4保持0。
語法
#define KQ_CGB_ATTR(palette, bank, xflip, yflip, priority) ((u8)(((palette) & KQ_CGB_ATTR_PAL_MASK) | ((bank) ? KQ_CGB_ATTR_BANK1 : 0) | ((xflip) ? KQ_CGB_ATTR_XFLIP : 0) | ((yflip) ? KQ_CGB_ATTR_YFLIP : 0) | ((priority) ? KQ_CGB_ATTR_PRIORITY : 0)))參數
palette調色盤編號0~7,只使用低3位元(
& 7)。bank, xflip, yflip, priority0表示停用,任意非零值表示啟用。特別是2也會啟用:這些巨集判斷是否非零,而非只檢查最低位元。
回傳值
依上述位元配置產生的屬性欄位或組合屬性位元組,型別為u8。
使用條件與限制
這些巨集只計算u8值,不寫VRAM或暫存器。各引數出現一次。透過CGB屬性寫入API,或明確寫入bank 1的地圖來套用結果。DMG顯示不使用CGB地圖屬性。
建立CGB地圖屬性的位元3:bank非零時回傳0x08,否則為0。選擇顯示圖塊圖樣所用的VRAM bank,不寫VBK,也不改變CPU存取的bank。
建立水平翻轉旗標:enabled非零時為0x20,否則為0。用於CGB地圖屬性時,圖塊每列的8個像素反向顯示,不修改儲存的圖樣。
建立垂直翻轉旗標:enabled非零時為0x40,否則為0。用於CGB地圖屬性時,將圖塊的8列反向顯示,不改變儲存的圖樣。
建立BG優先於OBJ的旗標:enabled非零時為0x80,否則為0。CGB總優先權控制(LCDC位元0)啟用時,BG非零顏色編號的像素覆蓋精靈。BG顏色編號0仍可顯示精靈,不會讓整個圖塊變成不透明。
使用範例
attr=KQ_CGB_ATTR(10,0,2,2,0); // Palette 2, bank 0, both reflections: 0x62.
if (attr!=98 || KQ_CGB_ATTR(10,2,3,4,5)!=234) failures++;
cell(10,11,1,attr);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本程式示範相同圖塊圖樣如何分別使用BG與OBJ的調色盤。每個三角形為8×8像素,從頂列左側1個像素逐列擴展到底列8個像素。在x=16、32、48、64、80、96、112處,y=24的BG行依序為紅、藍、綠、紅、藍、綠、紅;y=64的OBJ行依序為藍、綠、紅、藍、綠、紅、藍。各欄依序使用單色、RGB分量、索引範圍、整組調色盤、絕對範圍、標準暫存器名稱及暫存器別名寫入。
y=88處的7個8×8格依序顯示:紅色三角形(x=16)、bank 1中線寬1像素的藍色方框(32)、水平翻轉的綠色三角形(48)、垂直翻轉的紅色三角形(64)、雙向翻轉的藍色三角形(80)、位於紅色精靈前方且顏色0區域透出紅色的綠色三角形(96),以及關閉BG優先權後覆蓋三角形的實心紅色精靈(112)。座標以螢幕左上角為原點,單位為像素。空白處為白色,文字為黑色。
FAILED CHECKS 000表示RGB遮罩、含輸入2的布林旗標、調色盤索引回繞、跨調色盤寫入、在槽位31截斷、null/零長度不寫入,以及LCD關閉時的色彩讀回檢查均通過。測試4種組合:雙模式ROM分別在DMG與CGB執行、DMG專用ROM在DMG執行、CGB專用ROM在CGB執行。DMG下CGB MODE為0,三角形皆為黑色,bank與翻轉屬性不影響顯示,最下行最後兩格為黑色方塊。CGB測試中CGB MODE為1。未測試實機及LCD顯示期間的調色盤存取衝突。




建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/cgb_tile.h:23
KQ_CGB_ATTR_BANK
建立CGB地圖屬性的位元3:bank非零時回傳0x08,否則為0。選擇顯示圖塊圖樣所用的VRAM bank,不寫VBK,也不改變CPU存取的bank。
語法
#define KQ_CGB_ATTR_BANK(bank) ((u8)((bank) ? KQ_CGB_ATTR_BANK1 : 0))參數
bank0表示停用,任意非零值表示啟用。特別是2也會啟用:這些巨集判斷是否非零,而非只檢查最低位元。
回傳值
依上述位元配置產生的屬性欄位或組合屬性位元組,型別為u8。
使用條件與限制
這些巨集只計算u8值,不寫VRAM或暫存器。各引數出現一次。透過CGB屬性寫入API,或明確寫入bank 1的地圖來套用結果。DMG顯示不使用CGB地圖屬性。
使用範例
attr=(u8)(2|KQ_CGB_ATTR_BANK(enabled)); // Any nonzero value selects tile-data bank 1.
if (attr!=10) failures++;
cell(4,11,1,attr); // Blue hollow square, unlike the bank-0 triangle.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本程式示範相同圖塊圖樣如何分別使用BG與OBJ的調色盤。每個三角形為8×8像素,從頂列左側1個像素逐列擴展到底列8個像素。在x=16、32、48、64、80、96、112處,y=24的BG行依序為紅、藍、綠、紅、藍、綠、紅;y=64的OBJ行依序為藍、綠、紅、藍、綠、紅、藍。各欄依序使用單色、RGB分量、索引範圍、整組調色盤、絕對範圍、標準暫存器名稱及暫存器別名寫入。
y=88處的7個8×8格依序顯示:紅色三角形(x=16)、bank 1中線寬1像素的藍色方框(32)、水平翻轉的綠色三角形(48)、垂直翻轉的紅色三角形(64)、雙向翻轉的藍色三角形(80)、位於紅色精靈前方且顏色0區域透出紅色的綠色三角形(96),以及關閉BG優先權後覆蓋三角形的實心紅色精靈(112)。座標以螢幕左上角為原點,單位為像素。空白處為白色,文字為黑色。
FAILED CHECKS 000表示RGB遮罩、含輸入2的布林旗標、調色盤索引回繞、跨調色盤寫入、在槽位31截斷、null/零長度不寫入,以及LCD關閉時的色彩讀回檢查均通過。測試4種組合:雙模式ROM分別在DMG與CGB執行、DMG專用ROM在DMG執行、CGB專用ROM在CGB執行。DMG下CGB MODE為0,三角形皆為黑色,bank與翻轉屬性不影響顯示,最下行最後兩格為黑色方塊。CGB測試中CGB MODE為1。未測試實機及LCD顯示期間的調色盤存取衝突。




建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/cgb_tile.h:19
KQ_CGB_ATTR_PAL
以n & 7建立CGB地圖屬性的調色盤編號欄位,結果為u8。可用位元OR與其他屬性旗標組合。
語法
#define KQ_CGB_ATTR_PAL(n) ((u8)((n) & KQ_CGB_ATTR_PAL_MASK))參數
n調色盤編號0~7,只使用低3位元(
& 7)。
回傳值
依上述位元配置產生的屬性欄位或組合屬性位元組,型別為u8。
使用條件與限制
這些巨集只計算u8值,不寫VRAM或暫存器。各引數出現一次。透過CGB屬性寫入API,或明確寫入bank 1的地圖來套用結果。DMG顯示不使用CGB地圖屬性。
使用範例
attr=KQ_CGB_ATTR_PAL(9); // 9 & 7 = palette 1, red in this BG example.
if (attr!=1) failures++;
cell(2,11,1,attr);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本程式示範相同圖塊圖樣如何分別使用BG與OBJ的調色盤。每個三角形為8×8像素,從頂列左側1個像素逐列擴展到底列8個像素。在x=16、32、48、64、80、96、112處,y=24的BG行依序為紅、藍、綠、紅、藍、綠、紅;y=64的OBJ行依序為藍、綠、紅、藍、綠、紅、藍。各欄依序使用單色、RGB分量、索引範圍、整組調色盤、絕對範圍、標準暫存器名稱及暫存器別名寫入。
y=88處的7個8×8格依序顯示:紅色三角形(x=16)、bank 1中線寬1像素的藍色方框(32)、水平翻轉的綠色三角形(48)、垂直翻轉的紅色三角形(64)、雙向翻轉的藍色三角形(80)、位於紅色精靈前方且顏色0區域透出紅色的綠色三角形(96),以及關閉BG優先權後覆蓋三角形的實心紅色精靈(112)。座標以螢幕左上角為原點,單位為像素。空白處為白色,文字為黑色。
FAILED CHECKS 000表示RGB遮罩、含輸入2的布林旗標、調色盤索引回繞、跨調色盤寫入、在槽位31截斷、null/零長度不寫入,以及LCD關閉時的色彩讀回檢查均通過。測試4種組合:雙模式ROM分別在DMG與CGB執行、DMG專用ROM在DMG執行、CGB專用ROM在CGB執行。DMG下CGB MODE為0,三角形皆為黑色,bank與翻轉屬性不影響顯示,最下行最後兩格為黑色方塊。CGB測試中CGB MODE為1。未測試實機及LCD顯示期間的調色盤存取衝突。




建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/cgb_tile.h:18
KQ_CGB_ATTR_PRIORITY_IF
建立BG優先於OBJ的旗標:enabled非零時為0x80,否則為0。CGB總優先權控制(LCDC位元0)啟用時,BG非零顏色編號的像素覆蓋精靈。BG顏色編號0仍可顯示精靈,不會讓整個圖塊變成不透明。
語法
#define KQ_CGB_ATTR_PRIORITY_IF(enabled) ((u8)((enabled) ? KQ_CGB_ATTR_PRIORITY : 0))參數
enabled0表示停用,任意非零值表示啟用。特別是2也會啟用:這些巨集判斷是否非零,而非只檢查最低位元。
回傳值
依上述位元配置產生的屬性欄位或組合屬性位元組,型別為u8。
使用條件與限制
這些巨集只計算u8值,不寫VRAM或暫存器。各引數出現一次。透過CGB屬性寫入API,或明確寫入bank 1的地圖來套用結果。DMG顯示不使用CGB地圖屬性。
使用範例
attr=(u8)(3|KQ_CGB_ATTR_PRIORITY_IF(enabled)); // Keep nonzero BG pixels in front of sprites.
if (attr!=131) failures++;
cell(12,11,1,attr);
sprite(7,96,88,2,3); // Red full tile behind the green priority triangle.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本程式示範相同圖塊圖樣如何分別使用BG與OBJ的調色盤。每個三角形為8×8像素,從頂列左側1個像素逐列擴展到底列8個像素。在x=16、32、48、64、80、96、112處,y=24的BG行依序為紅、藍、綠、紅、藍、綠、紅;y=64的OBJ行依序為藍、綠、紅、藍、綠、紅、藍。各欄依序使用單色、RGB分量、索引範圍、整組調色盤、絕對範圍、標準暫存器名稱及暫存器別名寫入。
y=88處的7個8×8格依序顯示:紅色三角形(x=16)、bank 1中線寬1像素的藍色方框(32)、水平翻轉的綠色三角形(48)、垂直翻轉的紅色三角形(64)、雙向翻轉的藍色三角形(80)、位於紅色精靈前方且顏色0區域透出紅色的綠色三角形(96),以及關閉BG優先權後覆蓋三角形的實心紅色精靈(112)。座標以螢幕左上角為原點,單位為像素。空白處為白色,文字為黑色。
FAILED CHECKS 000表示RGB遮罩、含輸入2的布林旗標、調色盤索引回繞、跨調色盤寫入、在槽位31截斷、null/零長度不寫入,以及LCD關閉時的色彩讀回檢查均通過。測試4種組合:雙模式ROM分別在DMG與CGB執行、DMG專用ROM在DMG執行、CGB專用ROM在CGB執行。DMG下CGB MODE為0,三角形皆為黑色,bank與翻轉屬性不影響顯示,最下行最後兩格為黑色方塊。CGB測試中CGB MODE為1。未測試實機及LCD顯示期間的調色盤存取衝突。




建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/cgb_tile.h:22
KQ_CGB_ATTR_XFLIP_IF
建立水平翻轉旗標:enabled非零時為0x20,否則為0。用於CGB地圖屬性時,圖塊每列的8個像素反向顯示,不修改儲存的圖樣。
語法
#define KQ_CGB_ATTR_XFLIP_IF(enabled) ((u8)((enabled) ? KQ_CGB_ATTR_XFLIP : 0))參數
enabled0表示停用,任意非零值表示啟用。特別是2也會啟用:這些巨集判斷是否非零,而非只檢查最低位元。
回傳值
依上述位元配置產生的屬性欄位或組合屬性位元組,型別為u8。
使用條件與限制
這些巨集只計算u8值,不寫VRAM或暫存器。各引數出現一次。透過CGB屬性寫入API,或明確寫入bank 1的地圖來套用結果。DMG顯示不使用CGB地圖屬性。
使用範例
attr=(u8)(3|KQ_CGB_ATTR_XFLIP_IF(enabled));
if (attr!=35) failures++;
cell(6,11,1,attr); // Green triangle reflected horizontally.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本程式示範相同圖塊圖樣如何分別使用BG與OBJ的調色盤。每個三角形為8×8像素,從頂列左側1個像素逐列擴展到底列8個像素。在x=16、32、48、64、80、96、112處,y=24的BG行依序為紅、藍、綠、紅、藍、綠、紅;y=64的OBJ行依序為藍、綠、紅、藍、綠、紅、藍。各欄依序使用單色、RGB分量、索引範圍、整組調色盤、絕對範圍、標準暫存器名稱及暫存器別名寫入。
y=88處的7個8×8格依序顯示:紅色三角形(x=16)、bank 1中線寬1像素的藍色方框(32)、水平翻轉的綠色三角形(48)、垂直翻轉的紅色三角形(64)、雙向翻轉的藍色三角形(80)、位於紅色精靈前方且顏色0區域透出紅色的綠色三角形(96),以及關閉BG優先權後覆蓋三角形的實心紅色精靈(112)。座標以螢幕左上角為原點,單位為像素。空白處為白色,文字為黑色。
FAILED CHECKS 000表示RGB遮罩、含輸入2的布林旗標、調色盤索引回繞、跨調色盤寫入、在槽位31截斷、null/零長度不寫入,以及LCD關閉時的色彩讀回檢查均通過。測試4種組合:雙模式ROM分別在DMG與CGB執行、DMG專用ROM在DMG執行、CGB專用ROM在CGB執行。DMG下CGB MODE為0,三角形皆為黑色,bank與翻轉屬性不影響顯示,最下行最後兩格為黑色方塊。CGB測試中CGB MODE為1。未測試實機及LCD顯示期間的調色盤存取衝突。




建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/cgb_tile.h:20
KQ_CGB_ATTR_YFLIP_IF
建立垂直翻轉旗標:enabled非零時為0x40,否則為0。用於CGB地圖屬性時,將圖塊的8列反向顯示,不改變儲存的圖樣。
語法
#define KQ_CGB_ATTR_YFLIP_IF(enabled) ((u8)((enabled) ? KQ_CGB_ATTR_YFLIP : 0))參數
enabled0表示停用,任意非零值表示啟用。特別是2也會啟用:這些巨集判斷是否非零,而非只檢查最低位元。
回傳值
依上述位元配置產生的屬性欄位或組合屬性位元組,型別為u8。
使用條件與限制
這些巨集只計算u8值,不寫VRAM或暫存器。各引數出現一次。透過CGB屬性寫入API,或明確寫入bank 1的地圖來套用結果。DMG顯示不使用CGB地圖屬性。
使用範例
attr=(u8)(1|KQ_CGB_ATTR_YFLIP_IF(enabled));
if (attr!=65) failures++;
cell(8,11,1,attr); // Red triangle reflected vertically.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本程式示範相同圖塊圖樣如何分別使用BG與OBJ的調色盤。每個三角形為8×8像素,從頂列左側1個像素逐列擴展到底列8個像素。在x=16、32、48、64、80、96、112處,y=24的BG行依序為紅、藍、綠、紅、藍、綠、紅;y=64的OBJ行依序為藍、綠、紅、藍、綠、紅、藍。各欄依序使用單色、RGB分量、索引範圍、整組調色盤、絕對範圍、標準暫存器名稱及暫存器別名寫入。
y=88處的7個8×8格依序顯示:紅色三角形(x=16)、bank 1中線寬1像素的藍色方框(32)、水平翻轉的綠色三角形(48)、垂直翻轉的紅色三角形(64)、雙向翻轉的藍色三角形(80)、位於紅色精靈前方且顏色0區域透出紅色的綠色三角形(96),以及關閉BG優先權後覆蓋三角形的實心紅色精靈(112)。座標以螢幕左上角為原點,單位為像素。空白處為白色,文字為黑色。
FAILED CHECKS 000表示RGB遮罩、含輸入2的布林旗標、調色盤索引回繞、跨調色盤寫入、在槽位31截斷、null/零長度不寫入,以及LCD關閉時的色彩讀回檢查均通過。測試4種組合:雙模式ROM分別在DMG與CGB執行、DMG專用ROM在DMG執行、CGB專用ROM在CGB執行。DMG下CGB MODE為0,三角形皆為黑色,bank與翻轉屬性不影響顯示,最下行最後兩格為黑色方塊。CGB測試中CGB MODE為1。未測試實機及LCD顯示期間的調色盤存取衝突。




建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/cgb_tile.h:21
chain.h — 位置歷史環狀緩衝區
關節相連的蛇身或繩索請使用 ChainBody,記錄位置歷程則使用 Chain。每個身體關節保存目前位置及 16 種方向之一;彎折每次更新向後傳遞一個關節。身體操作支援場地邊界回捲、複製尾端以增加長度,以及各軸最多兩個像素的修正。
chain_wrap_delta
在兩端相接的軸上,計算目前位置到目標的最短帶正負號位移。可用於跨場地邊界的跟隨或距離比較。
語法
s16 chain_wrap_delta(u8 target, u8 current, u16 size);參數
target目標座標,範圍為 0..size−1。
current目前座標,範圍為 0..size−1。
size循環軸長度為 1..256:X 使用寬度,Y 使用高度。此引數為 16 位元,以便表示 256。
回傳值
以 s16 傳回最短位移:朝座標增加方向為正、減少方向為負、相同位置為零。有效輸入產生 −128..+128。畫面座標向右與向下的位移為正。
使用條件與限制
包含 chain.h 並且只編譯一次 chain.c。不需要初始化 Chain 或 ChainBody。此函式只計算位移,不改變座標陣列、關節數或畫面。
不驗證或正規化輸入。不可傳入 size=0、size>256,或大於等於 size 的座標。來自較大座標系的座標須先回捲至 0..size−1,再呼叫。
兩條路徑等長時,保留直接位移 target−current 的符號。size=160 時,0→80 傳回 +80,80→0 傳回 −80。size=1 時,唯一有效座標為零,結果也為零。
使用範例
distances[0]=chain_wrap_delta(1,159,160); // +2: cross the right edge.
distances[1]=chain_wrap_delta(159,1,160); // -2: cross the left edge.
distances[2]=chain_wrap_delta(80,0,160); // +80: keep the direct sign.
distances[3]=chain_wrap_delta(0,80,160); // -80: same-length routes.
distances[4]=chain_wrap_delta(0,0,1); // 0: the only valid position.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例示範循環座標。每支箭頭由目前位置指向目標。跨越寬度 160 邊界的結果為 +02/−02,半個場地為 +80/−80,寬度 1 為 +00。前置零只是十進位補位。此範例不繪製或移動物件。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\chain_wrap.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\chain_wrap.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/chain.h:35
Return target minus current along the shortest wrapped route. Supply size 1..256 and coordinates in 0..size-1; inputs are not normalized. Exactly half a field retains the direct displacement sign.
kitaqgb/lib/chain.c:98
s16 chain_wrap_delta(u8 target, u8 current, u16 size)
{
s16 delta;
s16 half;
delta = (s16)((s16)target - (s16)current);
half = (s16)(size >> 1);
// At exactly half a field, retain the sign of the direct displacement.
if (delta > half) delta = (s16)(delta - (s16)size);
else if (delta < (s16)(0 - half)) delta = (s16)(delta + (s16)size);
return delta;
}chain_body_init
連結呼叫端持有的三個關節陣列,將關節數設為零,不配置記憶體。
語法
u8 chain_body_init(ChainBody* body, u8* x, u8* y, u8* heading, u8 capacity, u16 width, u16 height);參數
body目標
ChainBody;null 會被忽略。除初始化外,須傳入已初始化狀態。x關節 X 座標陣列。
y關節 Y 座標陣列。
heading關節朝向陣列。
capacity已配置陣列長度,1..255。
width循環場地寬度,1..256。
height循環場地高度,1..256。
回傳值
成功傳回 1,引數無效傳回 0。body 非 null 時若失敗,會將 capacity 與 count 設為零,以停用更新。
使用條件與限制
包含 chain.h,並且只編譯一次 chain.c。ChainBody 保存各關節的目前位置與朝向;它是獨立狀態型別,與 Chain 位置歷程環形緩衝區不同。
提供三個獨立的可寫入陣列 x、y、heading,各含 capacity 位元組,並在使用身體期間保持有效。索引零是頭部,包含在 count 中。初始化後不可修改儲存指標、容量或場地尺寸。
朝向分成順時針 16 區:0=右、4=下、8=左、12=上。只使用輸入最低四位元。畫面座標向右、向下增加;各軸尺寸為 1..256 像素。
使用範例
chain_body_init(&body,joint_x,joint_y,joint_heading,8,160,144);
// Eight caller-owned slots, including the head, on a wrapped 160x144 field.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
圖上方為筆直身體,中間為向下轉彎後更新一次,下方為更新四次。座標以邏輯大小的兩倍繪製。彎折從右側頭部向後傳遞。CGB 與 FC 用紅色表示頭、藍色表示身體、綠色表示尾;DMG 使用黑色。成長後經四次穩定更新,重疊尾部會分離。這是相同八個關節的三個狀態,不是單一 24 關節身體。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\chain_body.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\chain_body.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/chain.h:53
Attach three non-overlapping capacity-byte arrays. Return 1 on success. Invalid storage, zero capacity or dimensions outside 1..256 disable the body.
kitaqgb/lib/chain.c:119
u8 chain_body_init(ChainBody* body, u8* x, u8* y, u8* heading, u8 capacity, u16 width, u16 height)
{
if (body == 0) return 0;
body->x = x;
body->y = y;
body->heading = heading;
body->count = 0;
body->capacity = 0;
body->width = width;
body->height = height;
if (x == 0 || y == 0 || heading == 0 || capacity == 0) return 0;
if (width == 0 || width > 256 || height == 0 || height > 256) return 0;
body->capacity = capacity;
return 1;
}chain_body_reset
在指定頭部後方排列關節,建立筆直的初始姿態。
語法
u8 chain_body_reset(ChainBody* body, u8 count, u8 head_x, u8 head_y, u8 heading);參數
body目標
ChainBody;null 會被忽略。除初始化外,須傳入已初始化狀態。count包含頭部的關節數,1..capacity。
head_x頭部 X 座標,依場地寬度回捲。
head_y頭部 Y 座標,依場地高度回捲。
heading16 區方向系統中的頭部朝向。
回傳值
成功傳回 1;數量為零、超出容量或 body 為 null 時,傳回 0 且不改變姿態。
使用條件與限制
包含 chain.h,並且只編譯一次 chain.c。ChainBody 保存各關節的目前位置與朝向;它是獨立狀態型別,與 Chain 位置歷程環形緩衝區不同。
提供三個獨立的可寫入陣列 x、y、heading,各含 capacity 位元組,並在使用身體期間保持有效。索引零是頭部,包含在 count 中。初始化後不可修改儲存指標、容量或場地尺寸。
朝向分成順時針 16 區:0=右、4=下、8=左、12=上。只使用輸入最低四位元。畫面座標向右、向下增加;各軸尺寸為 1..256 像素。
上下左右的間距為四像素。中間方向使用 (4,1)、(3,3)、(1,4) 等整數向量,因此歐氏距離不會恰為四像素。初始姿態可能跨越場地邊界。
使用範例
chain_body_reset(&body,7,48,16,0); // Seven joints, facing right.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
圖上方為筆直身體,中間為向下轉彎後更新一次,下方為更新四次。座標以邏輯大小的兩倍繪製。彎折從右側頭部向後傳遞。CGB 與 FC 用紅色表示頭、藍色表示身體、綠色表示尾;DMG 使用黑色。成長後經四次穩定更新,重疊尾部會分離。這是相同八個關節的三個狀態,不是單一 24 關節身體。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\chain_body.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\chain_body.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/chain.h:57
Seed count joints in a straight pose behind the head; count includes the head. Return 0 without changing the pose if count is zero or exceeds capacity. Coordinates wrap to the playfield and headings are masked to 0..15.
kitaqgb/lib/chain.c:135
u8 chain_body_reset(ChainBody* body, u8 count, u8 head_x, u8 head_y, u8 heading)
{
u8 i;
u8 x;
u8 y;
s16 ox;
s16 oy;
if (body == 0) return 0;
if (count == 0 || count > body->capacity) return 0;
heading = (u8)(heading & 15);
x = chain_body_wrap((s16)head_x, body->width);
y = chain_body_wrap((s16)head_y, body->height);
ox = chain_body_offset_x(heading);
oy = chain_body_offset_y(heading);
i = 0;
while (i < count) {
body->x[(__safe_index u8)i] = x;
body->y[(__safe_index u8)i] = y;
body->heading[(__safe_index u8)i] = heading;
x = chain_body_wrap((s16)((s16)x - ox), body->width);
y = chain_body_wrap((s16)((s16)y - oy), body->height);
i = (u8)(i + 1);
}
body->count = count;
return 1;
}chain_body_step
設定頭部姿態,逐步將各關節拉向前一關節後方的連接點。方向變化每次更新傳遞一個關節。
語法
void chain_body_step(ChainBody* body, u8 head_x, u8 head_y, u8 heading);參數
body目標
ChainBody;null 會被忽略。除初始化外,須傳入已初始化狀態。head_x頭部 X 座標,依場地寬度回捲。
head_y頭部 Y 座標,依場地高度回捲。
heading16 區方向系統中的頭部朝向。
回傳值
無傳回值。
使用條件與限制
包含 chain.h,並且只編譯一次 chain.c。ChainBody 保存各關節的目前位置與朝向;它是獨立狀態型別,與 Chain 位置歷程環形緩衝區不同。
提供三個獨立的可寫入陣列 x、y、heading,各含 capacity 位元組,並在使用身體期間保持有效。索引零是頭部,包含在 count 中。初始化後不可修改儲存指標、容量或場地尺寸。
朝向分成順時針 16 區:0=右、4=下、8=左、12=上。只使用輸入最低四位元。畫面座標向右、向下增加;各軸尺寸為 1..256 像素。
用前一關節更新後的位置找出目標連接點,再計算各軸跨邊界的最短位移。位移為零時不移動;大小 1..4 時移動一像素,5 以上時移動兩像素。距離恰為場地一半時保留原位移符號。
將各關節更新前保存的朝向傳給下一關節,讓彎折沿身體傳遞。空身體不變。
頭部速度、加速度、碰撞、繪圖與等待由呼叫端處理。通常先更新頭部,再於每個模擬步驟呼叫一次 chain_body_step。此功能是關節跟隨,不是剛體或精確長度約束求解器。
使用範例
chain_body_step(&body,48,20,4); // The head turns down; only joint 1 receives 4.
show_pose(8,34);
for(step=1;step<4;step++) {
chain_body_step(&body,48,(u8)(20+step),4);
}
// After four ticks, the new heading has reached joints 1 through 4.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
圖上方為筆直身體,中間為向下轉彎後更新一次,下方為更新四次。座標以邏輯大小的兩倍繪製。彎折從右側頭部向後傳遞。CGB 與 FC 用紅色表示頭、藍色表示身體、綠色表示尾;DMG 使用黑色。成長後經四次穩定更新,重疊尾部會分離。這是相同八個關節的三個狀態,不是單一 24 關節身體。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\chain_body.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\chain_body.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/chain.h:62
Install the caller's head pose, then pull joints from front to rear. Each joint aims four pixels behind its updated predecessor and receives that predecessor's OLD heading. Each axis moves 1 pixel, or 2 when error exceeds 4. Call once per simulation tick; this does not advance head physics or render.
kitaqgb/lib/chain.c:162
void chain_body_step(ChainBody* body, u8 head_x, u8 head_y, u8 heading)
{
u8 i;
u8 previous;
u8 pull;
u8 old;
u8 x;
u8 y;
u8 tx;
u8 ty;
s16 sx;
s16 sy;
if (body == 0) return;
if (body->count == 0) return;
heading = (u8)(heading & 15);
body->x[0] = chain_body_wrap((s16)head_x, body->width);
body->y[0] = chain_body_wrap((s16)head_y, body->height);
body->heading[0] = heading;
pull = heading;
i = 1;
while (i < body->count) {
previous = (u8)(i - 1);
old = body->heading[(__safe_index u8)i];
x = body->x[(__safe_index u8)i];
y = body->y[(__safe_index u8)i];
tx = chain_body_wrap((s16)((s16)body->x[(__safe_index u8)previous] - chain_body_offset_x(pull)), body->width);
ty = chain_body_wrap((s16)((s16)body->y[(__safe_index u8)previous] - chain_body_offset_y(pull)), body->height);
sx = chain_body_correction(chain_wrap_delta(tx, x, body->width));
sy = chain_body_correction(chain_wrap_delta(ty, y, body->height));
body->heading[(__safe_index u8)i] = pull;
body->x[(__safe_index u8)i] = chain_body_wrap((s16)((s16)x + sx), body->width);
body->y[(__safe_index u8)i] = chain_body_wrap((s16)((s16)y + sy), body->height);
// Save before overwriting: a bend advances by one joint per update.
pull = old;
i = (u8)(i + 1);
}
}chain_body_grow
將尾部目前位置與朝向複製到下一個空槽,數量增加一。
語法
u8 chain_body_grow(ChainBody* body);參數
body目標
ChainBody;null 會被忽略。除初始化外,須傳入已初始化狀態。
回傳值
新增關節成功時傳回 1;身體為空、已滿、停用或 null 時傳回 0。
使用條件與限制
包含 chain.h,並且只編譯一次 chain.c。ChainBody 保存各關節的目前位置與朝向;它是獨立狀態型別,與 Chain 位置歷程環形緩衝區不同。
提供三個獨立的可寫入陣列 x、y、heading,各含 capacity 位元組,並在使用身體期間保持有效。索引零是頭部,包含在 count 中。初始化後不可修改儲存指標、容量或場地尺寸。
朝向分成順時針 16 區:0=右、4=下、8=左、12=上。只使用輸入最低四位元。畫面座標向右、向下增加;各軸尺寸為 1..256 像素。
新尾部起初與原尾部重疊,之後透過 chain_body_step 呼叫分離。成長本身不會移動頭部或其他關節。
使用範例
chain_body_grow(&body); // Copy the tail pose into the eighth slot.
chain_body_step(&body,48,16,0);
chain_body_step(&body,48,16,0);
chain_body_step(&body,48,16,0);
chain_body_step(&body,48,16,0); // Allow the duplicated tail to separate.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
圖上方為筆直身體,中間為向下轉彎後更新一次,下方為更新四次。座標以邏輯大小的兩倍繪製。彎折從右側頭部向後傳遞。CGB 與 FC 用紅色表示頭、藍色表示身體、綠色表示尾;DMG 使用黑色。成長後經四次穩定更新,重疊尾部會分離。這是相同八個關節的三個狀態,不是單一 24 關節身體。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\chain_body.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\chain_body.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/chain.h:65
Append a copy of the current tail; later steps separate the new joint. Return 1 on growth, or 0 for an empty, disabled or full body.
kitaqgb/lib/chain.c:200
u8 chain_body_grow(ChainBody* body)
{
u8 tail;
u8 next;
if (body == 0) return 0;
next = body->count;
if (next == 0 || next >= body->capacity) return 0;
tail = (u8)(next - 1);
body->x[(__safe_index u8)next] = body->x[(__safe_index u8)tail];
body->y[(__safe_index u8)next] = body->y[(__safe_index u8)tail];
body->heading[(__safe_index u8)next] = body->heading[(__safe_index u8)tail];
body->count = (u8)(next + 1);
return 1;
}chain_body_clear
保留陣列與場地設定,將關節數設為零。
語法
void chain_body_clear(ChainBody* body);參數
body目標
ChainBody;null 會被忽略。除初始化外,須傳入已初始化狀態。
回傳值
無傳回值。
使用條件與限制
包含 chain.h,並且只編譯一次 chain.c。ChainBody 保存各關節的目前位置與朝向;它是獨立狀態型別,與 Chain 位置歷程環形緩衝區不同。
提供三個獨立的可寫入陣列 x、y、heading,各含 capacity 位元組,並在使用身體期間保持有效。索引零是頭部,包含在 count 中。初始化後不可修改儲存指標、容量或場地尺寸。
朝向分成順時針 16 區:0=右、4=下、8=左、12=上。只使用輸入最低四位元。畫面座標向右、向下增加;各軸尺寸為 1..256 像素。
不清除陣列位元組。請使用 chain_body_reset 重新開始;清空後立即呼叫 chain_body_grow 不會新增關節。
使用範例
chain_body_clear(&body); // Forget the pose; the three arrays remain owned by us.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
圖上方為筆直身體,中間為向下轉彎後更新一次,下方為更新四次。座標以邏輯大小的兩倍繪製。彎折從右側頭部向後傳遞。CGB 與 FC 用紅色表示頭、藍色表示身體、綠色表示尾;DMG 使用黑色。成長後經四次穩定更新,重疊尾部會分離。這是相同八個關節的三個狀態,不是單一 24 關節身體。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\chain_body.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\chain_body.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/chain.h:67
Remove all joints while retaining caller-owned storage and playfield settings.
kitaqgb/lib/chain.c:215
void chain_body_clear(ChainBody* body)
{
if (body == 0) return;
body->count = 0;
}chain_clear
清除已記錄的歷史,讓同一個底層陣列可再次使用。
語法
void chain_clear(Chain* chain);參數
chain指向已初始化
Chain的指標。
回傳值
無傳回值。
使用條件與限制
將筆數與 head 歸零,不清除或釋放底層陣列。Chain 與點陣列都由呼叫端持有,使用期間必須有效。容量不可大於 128,以免讀取端的八位元索引加法溢位。
GB 版本需要有效的 chain 指標。
使用範例
chain_clear(&trail);result[11]=chain_get_count(&trail);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例清除四個點的歷史,並確認筆數變為零。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_chain.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_chain.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/chain.h:21
Forget the recorded points without clearing or freeing the backing storage.
kitaqgb/lib/chain.c:14
void chain_clear(Chain* chain)
{
chain->count = 0;
chain->head = 0;
}chain_get_count
讀取目前歷史中可用的位置筆數。
語法
u8 chain_get_count(const Chain* chain);參數
chain指向已初始化
Chain的指標。
回傳值
傳回零至容量之間的筆數;chain 為空指標時傳回零。
使用條件與限制
Chain 與點陣列都由呼叫端持有,使用期間必須保持有效。容量不可大於 128,以免讀取端的八位元索引加法溢位。
使用範例
result[4]=chain_get_count(&trail);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
四個槽位加入五次資料後,筆數仍為四。清除後變為零;容量為零的歷史也會保持零。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_chain.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_chain.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/chain.h:30
Return the number of stored points, or zero for a null chain.
kitaqgb/lib/chain.c:63
u8 chain_get_count(const Chain* chain)
{
if (chain == 0) return 0;
return chain->count;
}chain_get_segment
依記錄的新舊順序讀取儲存的位置。
語法
u8 chain_get_segment(const Chain* chain, u8 index, ChainPoint* out);參數
chain指向已初始化
Chain的指標。index點的新舊索引:0 為最新,
count - 1為保留的最舊點。out用來接收結果的獨立、可寫入
ChainPoint;空指標會導致失敗。
回傳值
成功時傳回 1,要求無效時傳回 0。若 out 不是空指標,會在驗證前先設為 (0,0)。
使用條件與限制
out 不可與底層陣列或 Chain 共用記憶體,否則清除輸出時會破壞來源資料。Chain 與點陣列由呼叫端持有,使用期間必須有效。容量不可大於 128,以免讀取端的八位元索引加法溢位。
使用範例
result[1]=chain_get_segment(&trail,0,&point);result[2]=point.x;result[3]=point.y;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
索引 0 讀取最新點 (40,24),索引 3 讀取最舊點 (16,8);無效索引 4 傳回失敗,輸出為 (0,0)。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_chain.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_chain.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/chain.h:28
Read a point by age, with index zero denoting the newest point. Return zero for an invalid request and clear a non-null output first. Keep head + index within the 8-bit range: addition is narrowed before the capacity wrap.
kitaqgb/lib/chain.c:40
u8 chain_get_segment(const Chain* chain, u8 index, ChainPoint* out)
{
u8 pos;
if (out != 0) {
out->x = 0;
out->y = 0;
}
if (out == 0) return 0;
if (chain == 0) return 0;
if (chain->capacity == 0) return 0;
if (index >= chain->count) return 0;
pos = (u8)(chain->head + index);
while (pos >= chain->capacity) {
pos = (u8)(pos - chain->capacity);
}
out->x = chain->points[pos].x;
out->y = chain->points[pos].y;
return 1;
}chain_init
將儲存空間接到位置歷史的環狀緩衝區,並從沒有任何記錄點的狀態開始。
語法
void chain_init(Chain* chain, ChainPoint* storage, u8 capacity);參數
chain要初始化且可寫入的
Chain。storage可容納
capacity個ChainPoint項目的陣列。capacity點槽位數。可用範圍為 1~128;零會停用記錄。
回傳值
無傳回值。
使用條件與限制
Chain 與點陣列都由呼叫端持有,使用期間必須保持有效。容量不可大於 128,以免讀取端的八位元索引加法溢位。
GB 版本需要有效的 chain 指標。
使用範例
chain_init(&trail,storage,4);result[0]=chain_get_count(&trail);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例連接四個點槽位,並確認初始筆數為零。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_chain.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_chain.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/chain.h:19
Attach caller-owned ring storage and start with no recorded points. The storage must remain valid for the lifetime of the chain. Use a valid chain pointer and capacity entries of caller-owned storage. Capacity at most 128 keeps every head+age sum in the byte range used by the reader.
kitaqgb/lib/chain.c:5
void chain_init(Chain* chain, ChainPoint* storage, u8 capacity)
{
chain->points = storage;
chain->capacity = capacity;
chain->count = 0;
chain->head = 0;
}chain_push_head
將最新位置加入歷史的頭端;已滿時取代最舊的點。
語法
void chain_push_head(Chain* chain, s16 x, s16 y);參數
chain指向已初始化
Chain的指標。x新點的帶正負號 X 座標。
y新點的帶正負號 Y 座標。
回傳值
無傳回值。
使用條件與限制
chain 為空指標或容量為零時不執行操作。Chain 與點陣列都由呼叫端持有,使用期間必須有效。容量不可大於 128,以免讀取端的八位元索引加法溢位。
使用範例
chain_push_head(&trail,8,8);chain_push_head(&trail,16,8);chain_push_head(&trail,24,16);chain_push_head(&trail,32,16);chain_push_head(&trail,40,24);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
向四個槽位加入五次資料後,最新點為 (40,24),保留的最舊點為 (16,8);原本的 (8,8) 已被取代。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_chain.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_chain.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/chain.h:24
Move the ring head backward and store the newest point. Once full, each push replaces the oldest point; zero capacity is a no-op.
kitaqgb/lib/chain.c:22
void chain_push_head(Chain* chain, s16 x, s16 y)
{
if (chain == 0) return;
if (chain->capacity == 0) return;
if (chain->head == 0) chain->head = (u8)(chain->capacity - 1);
else chain->head--;
chain->points[chain->head].x = x;
chain->points[chain->head].y = y;
if (chain->count < chain->capacity) chain->count++;
}danmaku.h — 彈池、扇形發射、命中與擦彈
在 160×128 像素內處理最多 96 發子彈,不使用動態配置。提供十六分之一像素移動、32 方向扇形、命中/擦彈事件及四象限圖塊合成。模擬可在 GB 執行;present_now 上傳僅限 CGB。
danmaku_clear
停用所有子彈,清除存活數、目前命中/擦彈事件及配置游標。
語法
void danmaku_clear();回傳值
無傳回值。
使用條件與限制
保留峰值與累計計數器。若要從畫面移除子彈,請清除並上傳 RAM 映射表。
使用範例
danmaku_clear();result[6]=dm_count;result[7]=dm_spawned;result[8]=dm_peak;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
CGB 專用繪圖範例。在 (80,64) 向八個方向生成子彈,更新八次後顯示放射狀排列的八個紅色 3×3 點。上下左右子彈移動 32 像素,斜向使用整數近似。另檢查清空物件池及保留累計生成數。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_danmaku.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_danmaku.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/danmaku.h:35
Deactivate the pool while retaining peak/spawn/rejection counters and the RAM map.
kitaqgb/lib/danmaku.c:28
void danmaku_clear() {
u8 i;
for (i=0; i<DANMAKU_MAX; i++) dm_bullets[i].active=0;
dm_count=0; dm_hit=0; dm_graze=0; dm_cursor=0;
}danmaku_clear_map
清除 32×18 RAM 圖塊映射表的全部 576 位元組。
語法
void danmaku_clear_map();回傳值
無傳回值。
使用條件與限制
不改變子彈狀態或 VRAM。每影格依序執行 clear_map、寫入裝飾、step,再上傳。
使用範例
danmaku_clear_map();result[11]=dm_map[0];這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
CGB 專用繪圖範例。在 (80,64) 向八個方向生成子彈,更新八次後顯示放射狀排列的八個紅色 3×3 點。上下左右子彈移動 32 像素,斜向使用整數近似。另檢查清空物件池及保留累計生成數。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_danmaku.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_danmaku.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/danmaku.h:42
32 directions, 0=right, 8=down, 16=left, 24=up. speed in 1/16 px. Clear the 32x18 RAM map before drawing the next frame; no transfer is performed.
kitaqgb/lib/danmaku.c:78
void danmaku_clear_map() {
__asm {
LD_HL_IMM dm_map
LD_B_IMM 72
XOR_A
dm_clm_loop:
LDI_HL_A
LDI_HL_A
LDI_HL_A
LDI_HL_A
LDI_HL_A
LDI_HL_A
LDI_HL_A
LDI_HL_A
DEC_B
JR_NZ dm_clm_loop
RET
}
}danmaku_fan
使用 32 方向速度表及固定角度間隔產生扇形彈幕。
語法
void danmaku_fan(u8 x, u8 y, u8 direction, u8 step, u8 count, u8 speed);參數
x初始像素 X,範圍為 0..159。
y初始像素 Y,範圍為 0..127。
direction起始角度,僅保留五個位元:0=右、8=下、16=左、24=上。
step每發子彈的角度增量,在 32 個方向中循環。
count嘗試次數,上限為 96。
speed以十六分之一像素表示的速度,上限為 64,即每次更新四個像素。
回傳值
無傳回值。
使用條件與限制
即使池已滿,仍會繼續嘗試其餘生成要求。整數 sin/cos 表會使斜向移動產生取整誤差。
使用範例
danmaku_fan(80,64,0,4,8,64);result[9]=dm_count;result[10]=dm_spawned;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
CGB 專用繪圖範例。在 (80,64) 向八個方向生成子彈,更新八次後顯示放射狀排列的八個紅色 3×3 點。上下左右子彈移動 32 像素,斜向使用整數近似。另檢查清空物件池及保留累計生成數。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_danmaku.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_danmaku.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/danmaku.h:39
Attempt a fan using wrapping 32-step angles; count is capped at 96 and speed at 64.
kitaqgb/lib/danmaku.c:62
void danmaku_fan(u8 x,u8 y,u8 direction,u8 step,u8 count,u8 speed) {
u8 n;
u8 a;
s8 vx;
s8 vy;
if(count>DANMAKU_MAX) count=DANMAKU_MAX;
if(speed>64) speed=64;
a=direction&31;
for(n=0;n<count;n++) {
vx=(s8)(((s16)dm_cos[a]*(s16)speed)>>6);
vy=(s8)(((s16)dm_sin[a]*(s16)speed)>>6);
danmaku_spawn(x,y,vx,vy);
a=(u8)((a+step)&31);
}
}danmaku_present_now
使用 CGB GDMA,將 dm_map 的全部 576 位元組同步傳送至背景映射表 $9800。
語法
void danmaku_present_now();回傳值
無傳回值。
使用條件與限制
僅限 CGB,不可在 DMG 呼叫。請在 LCD 關閉時或 VBlank 起始時使用。會選取 VRAM 記憶體庫零,不還原先前的 VBK。應用程式須在圖塊 0..15 提供子彈圖形。
使用範例
// CGB general DMA; the LCD is stopped for this complete-map upload.
danmaku_present_now();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
CGB 專用繪圖範例。在 (80,64) 向八個方向生成子彈,更新八次後顯示放射狀排列的八個紅色 3×3 點。上下左右子彈移動 32 像素,斜向使用整數近似。另檢查清空物件池及保留累計生成數。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_danmaku.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_danmaku.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/danmaku.h:48
Requires CGB and LCD off or the beginning of VBlank. VBK restored to 0. Transfers 18 rows (32-byte stride) to BG map 9800 with 36-block GDMA.
kitaqgb/lib/danmaku.c:301
void danmaku_present_now() {
__asm {
XOR_A
LDH_MEM_A 0x4F
LD_HL_IMM dm_map
LD_A_H
LDH_MEM_A 0x51
LD_A_L
LDH_MEM_A 0x52
LD_A_IMM 0x18
LDH_MEM_A 0x53
XOR_A
LDH_MEM_A 0x54
LD_A_IMM 35
LDH_MEM_A 0x55
RET
}
}danmaku_reset
清空 96 發子彈的物件池,重設同時存在峰值、累計生成次數及物件池已滿的拒絕次數。
語法
void danmaku_reset();回傳值
無傳回值。
使用條件與限制
不改變玩家座標、無敵狀態或 RAM 圖塊映射表;請在遊戲開始時另行設定。
使用範例
danmaku_reset();result[0]=dm_count;result[1]=dm_peak;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
CGB 專用繪圖範例。在 (80,64) 向八個方向生成子彈,更新八次後顯示放射狀排列的八個紅色 3×3 點。上下左右子彈移動 32 像素,斜向使用整數近似。另檢查清空物件池及保留累計生成數。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_danmaku.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_danmaku.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/danmaku.h:33
Reset pool, peak and lifetime counters; player fields and map contents remain caller-owned state.
kitaqgb/lib/danmaku.c:34
void danmaku_reset() {
danmaku_clear(); dm_peak=0; dm_spawned=0; dm_rejected=0;
}danmaku_spawn
循環搜尋空槽,建立一發具有指定位置與速度的子彈。
語法
u8 danmaku_spawn(u8 x, u8 y, s8 vx, s8 vy);參數
x初始像素 X,範圍為 0..159。
y初始像素 Y,範圍為 0..127。
vx帶正負號的 Q4.4 速度,範圍為 −128..127;16 表示每次更新向右移動一個像素。
vy帶正負號的 Q4.4 速度;正值向下移動。
回傳值
配置成功時傳回 1,座標位於範圍外或池已滿時傳回 0。範圍外的要求不會遞增 dm_rejected。
使用條件與限制
位置以十六分之一像素儲存。u16 生成/拒絕累計值超過 65535 後回捲。不使用動態配置。
使用範例
result[2]=danmaku_spawn(40,40,16,0);result[3]=danmaku_spawn(160,40,0,0);result[4]=dm_count;result[5]=dm_rejected;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
CGB 專用繪圖範例。在 (80,64) 向八個方向生成子彈,更新八次後顯示放射狀排列的八個紅色 3×3 點。上下左右子彈移動 32 像素,斜向使用整數近似。另檢查清空物件池及保留累計生成數。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_danmaku.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_danmaku.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/danmaku.h:37
Use pixel origins inside 160x128 and signed sixteenth-pixel velocities; return one if a slot was allocated.
kitaqgb/lib/danmaku.c:39
u8 danmaku_spawn(u8 x, u8 y, s8 vx, s8 vy) {
u8 n;
u8 i;
if (x>=160 || y>=128) return 0;
for(n=0;n<DANMAKU_MAX;n++) {
i=dm_cursor;
dm_cursor++;
if(dm_cursor>=DANMAKU_MAX) dm_cursor=0;
if(dm_bullets[i].active==0) {
dm_bullets[i].x=(s16)((u16)x<<4);
dm_bullets[i].y=(s16)((u16)y<<4);
dm_bullets[i].vx=vx; dm_bullets[i].vy=vy;
dm_bullets[i].active=1; dm_bullets[i].grazed=0;
dm_count++; dm_spawned++;
if(dm_count>dm_peak) dm_peak=dm_count;
return 1;
}
}
dm_rejected++;
return 0;
}danmaku_step
推進每發子彈一次、移除範圍外子彈、合成子彈圖塊,並偵測命中與擦彈。
語法
void danmaku_step();回傳值
無傳回值。
使用條件與限制
繪製中心會對齊四像素格線。各軸距離皆不超過八時產生首次擦彈,不超過三時產生命中。無敵只抑制命中。dm_hit/dm_graze 每次呼叫都重設,每發子彈只會擦彈一次。圖塊 ID 0..15 編碼四個象限位元;已佔用位置上 ID 為 16 以上的裝飾圖塊會被替換。
使用範例
dm_player_x=0;dm_player_y=0;dm_invulnerable=0;for(i=0;i<8;i++){danmaku_clear_map();danmaku_step();}result[12]=dm_count;result[13]=dm_hit;result[14]=dm_graze;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
CGB 專用繪圖範例。在 (80,64) 向八個方向生成子彈,更新八次後顯示放射狀排列的八個紅色 3×3 點。上下左右子彈移動 32 像素,斜向使用整數近似。另檢查清空物件池及保留累計生成數。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_danmaku.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_danmaku.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/danmaku.h:45
Caller fills decoration after clear_map, then calls step to overlay bullets. hit and graze are events for this step. Collision uses rendered centers.
kitaqgb/lib/danmaku.c:99
void danmaku_step() {
// One linear pass. No per-bullet bank calls, multiplication or division.
// The 8-byte packed public layout is x16,y16,vx8,vy8,active,graze.
__asm {
XOR_A
LD_MEM_A dm_hit
LD_MEM_A dm_graze
LD_A_IMM 96
LD_MEM_A dm_remaining
LD_HL_IMM dm_bullets
dm_tick_loop:
PUSH_HL
LD_BC_IMM 6
ADD_HL_BC
LD_A_HL
OR_A
JP_Z dm_tick_next
DEC_HL
LD_A_HL
LD_MEM_A dm_vy
DEC_HL
LD_A_HL
LD_C_A
LD_B_IMM 0
AND_IMM 128
JR_Z dm_tick_xsign
DEC_B
// B:C is the sign-extended X velocity. Add to Q12.4 position; high byte >=10 also rejects negative X.
dm_tick_xsign:
POP_HL
PUSH_HL
LD_A_HL
ADD_C
LDI_HL_A
LD_E_A
LD_A_HL
ADC_B
LDI_HL_A
CP_IMM 10
JP_NC dm_tick_kill
RRCA
RRCA
RRCA
RRCA
LD_D_A
LD_A_E
RRCA
RRCA
RRCA
RRCA
AND_IMM 15
OR_D
LD_MEM_A dm_px
LD_A_MEM dm_vy
LD_C_A
LD_B_IMM 0
AND_IMM 128
JR_Z dm_tick_ysign
DEC_B
// Apply signed Y velocity similarly; high byte >=8 rejects negative Y and positions at or below 128 pixels.
dm_tick_ysign:
LD_A_HL
ADD_C
LDI_HL_A
LD_E_A
LD_A_HL
ADC_B
LDI_HL_A
CP_IMM 8
JP_NC dm_tick_kill
RRCA
RRCA
RRCA
RRCA
LD_D_A
LD_A_E
RRCA
RRCA
RRCA
RRCA
AND_IMM 15
OR_D
LD_MEM_A dm_py
// Signed differences shifted into 0..16 for a wrap-safe range test.
// Rendered centers are (pixel & FC)+2. Test a square of radius eight around the player for graze eligibility.
LD_A_MEM dm_player_x
LD_C_A
LD_A_MEM dm_px
AND_IMM 252
ADD_A_IMM 10
SUB_C
CP_IMM 17
JR_NC dm_tick_plot
LD_B_A
LD_A_MEM dm_player_y
LD_C_A
LD_A_MEM dm_py
AND_IMM 252
ADD_A_IMM 10
SUB_C
CP_IMM 17
JR_NC dm_tick_plot
LD_C_A
INC_HL
INC_HL
INC_HL
LD_A_HL
OR_A
JR_NZ dm_tick_check_hit
LD_A_IMM 1
LD_HL_A
LD_A_MEM dm_graze
INC_A
LD_MEM_A dm_graze
// A bullet grazes at most once during its lifetime. Invulnerability suppresses hits, but not first-graze events.
// The inner hit test uses a square of radius three around the same quantized center.
dm_tick_check_hit:
LD_A_MEM dm_invulnerable
OR_A
JR_NZ dm_tick_plot
LD_A_B
SUB_IMM 5
CP_IMM 7
JR_NC dm_tick_plot
LD_A_C
SUB_IMM 5
CP_IMM 7
JR_NC dm_tick_plot
LD_A_IMM 1
LD_MEM_A dm_hit
// Select one of four quadrant bits from pixel bit 2, then address map[(y>>3)*32+(x>>3)].
// Decoration IDs >=16 are replaced at occupied cells; bullet IDs 0..15 merge with OR.
dm_tick_plot:
LD_A_MEM dm_py
AND_IMM 4
AND_IMM 254
RRCA
LD_B_A
LD_A_MEM dm_px
AND_IMM 4
AND_IMM 254
RRCA
AND_IMM 254
RRCA
OR_B
LD_E_A
LD_D_IMM 0
LD_HL_IMM dm_bits
ADD_HL_DE
LD_A_HL
LD_C_A
LD_A_MEM dm_py
AND_IMM 120
LD_L_A
LD_H_IMM 0
ADD_HL_HL
ADD_HL_HL
LD_A_MEM dm_px
AND_IMM 254
RRCA
AND_IMM 254
RRCA
AND_IMM 254
RRCA
LD_E_A
LD_D_IMM 0
ADD_HL_DE
LD_DE_IMM dm_map
ADD_HL_DE
LD_A_HL
CP_IMM 16
JR_C dm_tick_merge
XOR_A
dm_tick_merge:
OR_C
LD_HL_A
JR dm_tick_next
// Restore the saved record base, clear active at offset six and decrement the live count exactly once.
dm_tick_kill:
POP_HL
PUSH_HL
LD_BC_IMM 6
ADD_HL_BC
XOR_A
LD_HL_A
LD_A_MEM dm_count
DEC_A
LD_MEM_A dm_count
// Restore the saved base even for inactive or culled bullets, then advance by the fixed eight-byte record size.
dm_tick_next:
POP_HL
LD_BC_IMM 8
ADD_HL_BC
LD_A_MEM dm_remaining
DEC_A
LD_MEM_A dm_remaining
JP_NZ dm_tick_loop
RET
}
}debug.h — RAM 紀錄與斷言
將名稱、數值及影格標記寫入固定容量的 RAM 記錄。斷言會保留診斷資訊,並讓程式繼續執行。
debug_assert_fail
保留斷言失敗代碼,並嘗試加入一筆 ASSERT 記錄。
語法
void debug_assert_fail(u16 code);參數
code要保留的 16 位元錯誤識別碼。
回傳值
無傳回值。
使用條件與限制
執行會繼續。即使記錄已滿,最後一次斷言代碼仍會更新。 記錄預設可容納 32 筆,滿時會丟棄新項目。若重新定義 DEBUG_TRACE_MAX,所有編譯單元都須使用相同的 1~255 值。名稱僅保留指標,不複製字串,因此檢視完成前其儲存空間都必須可讀取。中斷與主程式的寫入次序須自行協調,避免重疊。
使用範例
debug_assert_fail(42);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例先記錄代碼 42,填滿記錄後再記錄代碼 999。筆數維持 32,但最後代碼變為 999。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/debug.h:33
Record the assertion code and attempt to append an ASSERT entry. This helper does not halt execution, and the code is retained even if the log is full.
kitaqgb/lib/debug.c:56
void debug_assert_fail(u16 code)
{
kq_debug_last_assert = code;
debug_push((const u8*)"ASSERT", code);
}debug_get_last_assert
讀取最近的斷言代碼,不受記錄剩餘空間影響。
語法
u16 debug_get_last_assert();回傳值
傳回最近的 16 位元代碼,初始化後的初值為零。
使用條件與限制
零也是初始值,因此無法區分「尚未失敗」與「以代碼零記錄的失敗」。讀取不會清除代碼。
使用範例
result[22]=debug_get_last_assert();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例確認斷言巨集產生的 77、記錄填滿後的 999,以及重新初始化後的零。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/debug.h:39
Read the last recorded assertion code, or the zero value installed by initialization.
kitaqgb/lib/debug.c:75
u16 debug_get_last_assert()
{
return kq_debug_last_assert;
}debug_get_trace_count
讀取追蹤陣列中有效的項目筆數。
語法
u8 debug_get_trace_count();回傳值
傳回零至 DEBUG_TRACE_MAX 之間的筆數。
使用條件與限制
記錄預設可容納 32 筆,滿時會丟棄新項目。若重新定義 DEBUG_TRACE_MAX,所有編譯單元都須使用相同的 1~255 值。名稱僅保留指標,不複製字串,因此檢視完成前其儲存空間都必須可讀取。中斷與主程式的寫入次序須自行協調,避免重疊。
使用範例
result[1]=debug_get_trace_count();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例確認最初十筆記錄,以及繼續寫入後的上限 32;滿時筆數不會溢位回繞。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/debug.h:35
Return the number of valid entries in the fixed trace buffer.
kitaqgb/lib/debug.c:63
u8 debug_get_trace_count()
{
return kq_debug_trace_count;
}debug_get_trace_log
取得內部陣列的參照,以檢視已記錄的名稱、數值與影格標記。
語法
const DebugTraceEntry* debug_get_trace_log();回傳值
傳回指向內部 DebugTraceEntry 陣列的唯讀指標。
使用條件與限制
這不是複本。只可讀取 debug_get_trace_count() 回報的筆數;初始化後殘留的舊位元組不是有效記錄。 記錄預設可容納 32 筆,滿時會丟棄新項目。若重新定義 DEBUG_TRACE_MAX,所有編譯單元都須使用相同的 1~255 值。名稱僅保留指標,不複製字串,因此檢視完成前其儲存空間都必須可讀取。中斷與主程式的寫入次序須自行協調,避免重疊。
使用範例
entries=debug_get_trace_log();for(i=0;i<10;i++){result[2+i]=entries[i].value;result[12+i]=entries[i].frame;}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例讀取全部十筆的數值與影格欄位,並確認 BEGIN 標籤的首字元為 B。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/debug.h:37
Expose the internal trace array for inspection; use the count to bound reads.
kitaqgb/lib/debug.c:69
const DebugTraceEntry* debug_get_trace_log()
{
return kq_debug_trace_log;
}debug_init
初始化有效記錄長度、影格標記與最後一次斷言代碼。
語法
void debug_init();回傳值
無傳回值。
使用條件與限制
不會清除既有項目的位元組。請在寫入第一筆記錄前呼叫。 記錄預設可容納 32 筆,滿時會丟棄新項目。若重新定義 DEBUG_TRACE_MAX,所有編譯單元都須使用相同的 1~255 值。名稱僅保留指標,不複製字串,因此檢視完成前其儲存空間都必須可讀取。中斷與主程式的寫入次序須自行協調,避免重疊。
使用範例
debug_init();result[0]=debug_get_trace_count();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例先確認初始筆數為零,再重設已有內容的記錄,確認筆數與斷言代碼歸零,而陣列中的舊值仍保留。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/debug.h:22
Reset log length, frame tag and last assertion code; existing entry bytes are not erased.
kitaqgb/lib/debug.c:10
void debug_init()
{
kq_debug_trace_count = 0;
kq_debug_frame = 0;
kq_debug_last_assert = 0;
}debug_mark_frame
記錄具名的影格標記,用來辨識流程中的特定位置。
語法
void debug_mark_frame(const u8* label);參數
label以零結尾的標籤字串;存放它的記憶體必須保持可讀取,直到檢視時為止。
回傳值
無傳回值。
使用條件與限制
記錄預設可容納 32 筆,滿時會丟棄新項目。若重新定義 DEBUG_TRACE_MAX,所有編譯單元都須使用相同的 1~255 值。名稱僅保留指標,不複製字串,因此檢視完成前其儲存空間都必須可讀取。中斷與主程式的寫入次序須自行協調,避免重疊。
使用範例
debug_mark_frame("BEGIN");這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
加入 BEGIN 標記時,會記錄數值 65535(0xFFFF)與影格標記 513。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/debug.h:26
Append a named frame marker using 0xFFFF as its value.
kitaqgb/lib/debug.c:37
void debug_mark_frame(const u8* label)
{
debug_push(label, 0xFFFF);
}debug_set_frame
設定之後各筆記錄要使用的影格標記。
語法
void debug_set_frame(u16 frame);參數
frame後續記錄使用的 16 位元影格編號。
回傳值
無傳回值。
使用條件與限制
不會等待影格,也不會自動遞增標記。請明確傳入遊戲的影格計數器。 記錄預設可容納 32 筆,滿時會丟棄新項目。若重新定義 DEBUG_TRACE_MAX,所有編譯單元都須使用相同的 1~255 值。名稱僅保留指標,不複製字串,因此檢視完成前其儲存空間都必須可讀取。中斷與主程式的寫入次序須自行協調,避免重疊。
使用範例
debug_set_frame(513);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例將標記設為 513、寫入十筆記錄,再讀回全部十個影格欄位確認標記。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/debug.h:24
Set the frame tag copied into subsequently recorded entries.
kitaqgb/lib/debug.c:18
void debug_set_frame(u16 frame)
{
kq_debug_frame = frame;
}debug_trace_u16
記錄具名的 16 位元分數或計數器。
語法
void debug_trace_u16(const u8* name, u16 value);參數
name以零結尾的標籤字串;存放它的記憶體必須保持可讀取,直到檢視時為止。
value要記錄的值,範圍為 0~65535。
回傳值
無傳回值。
使用條件與限制
記錄預設可容納 32 筆,滿時會丟棄新項目。若重新定義 DEBUG_TRACE_MAX,所有編譯單元都須使用相同的 1~255 值。名稱僅保留指標,不複製字串,因此檢視完成前其儲存空間都必須可讀取。中斷與主程式的寫入次序須自行協調,避免重疊。
使用範例
debug_trace_u16("WORD",4660);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
WORD 項目儲存 4660(0x1234),範例再讀回以確認兩個位元組。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/debug.h:30
Append a 16-bit value with the current frame tag.
kitaqgb/lib/debug.c:49
void debug_trace_u16(const u8* name, u16 value)
{
debug_push(name, value);
}debug_trace_u8
將八位元狀態值連同名稱與目前影格標記一起記錄。
語法
void debug_trace_u8(const u8* name, u8 value);參數
name以零結尾的標籤字串;存放它的記憶體必須保持可讀取,直到檢視時為止。
value範圍為 0~255 的值,以零擴展後存入記錄的 16 位元欄位。
回傳值
無傳回值。
使用條件與限制
記錄預設可容納 32 筆,滿時會丟棄新項目。若重新定義 DEBUG_TRACE_MAX,所有編譯單元都須使用相同的 1~255 值。名稱僅保留指標,不複製字串,因此檢視完成前其儲存空間都必須可讀取。中斷與主程式的寫入次序須自行協調,避免重疊。
使用範例
debug_trace_u8("BYTE",255);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
BYTE 項目記錄 255,並確認記錄中的 16 位元數值欄位也包含 255。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/debug.h:28
Append an unsigned byte value, widened to the log's 16-bit value field.
kitaqgb/lib/debug.c:43
void debug_trace_u8(const u8* name, u8 value)
{
debug_push(name, (u16)value);
}KITAQGB_ASSERT
可作為陳述式使用的巨集,條件為假時記錄斷言代碼 1。
語法
#define KITAQGB_ASSERT(cond) do { if (!(cond)) debug_assert_fail((u16)1); } while (0)參數
cond預期應成立的條件;零表示失敗。
回傳值
無傳回值。
使用條件與限制
條件只計算一次。為真時不記錄,為假時記錄失敗但不中止執行。採用 do…while (0) 形式,因此可在 if…else 中當作單一陳述式使用。
使用範例
KITAQGB_ASSERT(1);KITAQGB_ASSERT(0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
一個成立與一個不成立的斷言,合計只產生一筆代碼為 1 的記錄。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/debug.h:45
#define KITAQGB_ASSERT(cond) do { if (!(cond)) debug_assert_fail((u16)1); } while (0)KITAQGB_ASSERT_CODE
僅在條件為假時記錄指定的斷言代碼。
語法
#define KITAQGB_ASSERT_CODE(cond, code) do { if (!(cond)) debug_assert_fail((u16)(code)); } while (0)參數
cond預期應成立的條件。
code失敗時才計算、並轉換為 16 位元的代碼運算式。
回傳值
無傳回值。
使用條件與限制
條件只計算一次;代碼運算式只在失敗時才計算。記錄後仍繼續執行。
使用範例
KITAQGB_ASSERT_CODE(1,++side_effect);KITAQGB_ASSERT_CODE(0,77);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
條件為真時不計算代碼運算式 ++side_effect,變數維持零。條件為假時記錄代碼 77。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/debug.h:46
#define KITAQGB_ASSERT_CODE(cond, code) do { if (!(cond)) debug_assert_fail((u16)(code)); } while (0)KITAQGB_MARK_FRAME
將標籤轉型為字串指標,並加入數值為 0xFFFF 的影格標記。
語法
#define KITAQGB_MARK_FRAME(label) debug_mark_frame((const u8*)(label))參數
label以零結尾的標籤字串;存放它的記憶體必須保持可讀取,直到檢視時為止。
回傳值
無傳回值。
使用條件與限制
記錄預設可容納 32 筆,滿時會丟棄新項目。若重新定義 DEBUG_TRACE_MAX,所有編譯單元都須使用相同的 1~255 值。名稱僅保留指標,不複製字串,因此檢視完成前其儲存空間都必須可讀取。中斷與主程式的寫入次序須自行協調,避免重疊。
使用範例
KITAQGB_MARK_FRAME("END");這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
確認 END 標記的數值為 65535,影格標記為 513。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/debug.h:44
#define KITAQGB_MARK_FRAME(label) debug_mark_frame((const u8*)(label))KITAQGB_TRACE
將值明確轉換為 16 位元後,連同名稱一起記錄。
語法
#define KITAQGB_TRACE(name, value) debug_trace_u16((const u8*)(name), (u16)(value))參數
name以零結尾的標籤字串;存放它的記憶體必須保持可讀取,直到檢視時為止。
value記錄前會轉換為 16 位元的運算式。
回傳值
無傳回值。
使用條件與限制
巨集始終啟用,不會因建置設定而自動停用。其 16 位元記錄行為與 KITAQGB_TRACE_U16 相同。 記錄預設可容納 32 筆,滿時會丟棄新項目。若重新定義 DEBUG_TRACE_MAX,所有編譯單元都須使用相同的 1~255 值。名稱僅保留指標,不複製字串,因此檢視完成前其儲存空間都必須可讀取。中斷與主程式的寫入次序須自行協調,避免重疊。
使用範例
KITAQGB_TRACE("SCORE",600);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例記錄 600,再從記錄中讀回以驗證。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/debug.h:43
#define KITAQGB_TRACE(name, value) debug_trace_u16((const u8*)(name), (u16)(value))KITAQGB_TRACE_U16
將值明確轉換為 16 位元後,連同名稱一起記錄。
語法
#define KITAQGB_TRACE_U16(name, value) debug_trace_u16((const u8*)(name), (u16)(value))參數
name以零結尾的標籤字串;存放它的記憶體必須保持可讀取,直到檢視時為止。
value記錄前會轉換為 16 位元的運算式。
回傳值
無傳回值。
使用條件與限制
巨集始終啟用,不會因建置設定而自動停用。 記錄預設可容納 32 筆,滿時會丟棄新項目。若重新定義 DEBUG_TRACE_MAX,所有編譯單元都須使用相同的 1~255 值。名稱僅保留指標,不複製字串,因此檢視完成前其儲存空間都必須可讀取。中斷與主程式的寫入次序須自行協調,避免重疊。
使用範例
KITAQGB_TRACE_U16("WORD2",500);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例記錄 500,再從記錄中讀回以驗證。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/debug.h:42
#define KITAQGB_TRACE_U16(name, value) debug_trace_u16((const u8*)(name), (u16)(value))KITAQGB_TRACE_U8
將值明確轉換為八位元後,連同名稱一起記錄。
語法
#define KITAQGB_TRACE_U8(name, value) debug_trace_u8((const u8*)(name), (u8)(value))參數
name以零結尾的標籤字串;存放它的記憶體必須保持可讀取,直到檢視時為止。
value記錄前會轉換為八位元的運算式。
回傳值
無傳回值。
使用條件與限制
巨集始終啟用,不會因建置設定而自動停用。 記錄預設可容納 32 筆,滿時會丟棄新項目。若重新定義 DEBUG_TRACE_MAX,所有編譯單元都須使用相同的 1~255 值。名稱僅保留指標,不複製字串,因此檢視完成前其儲存空間都必須可讀取。中斷與主程式的寫入次序須自行協調,避免重疊。
使用範例
KITAQGB_TRACE_U8("CAST",0x1234);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例記錄 52,僅保留 0x1234 的低位元組 0x34。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/debug.h:41
#define KITAQGB_TRACE_U8(name, value) debug_trace_u8((const u8*)(name), (u8)(value))dmg3d.h — DMG 的 128×120 單色線框
單色 3D 線段繪製。須提供模型頂點、邊、面,以及物件位置、旋轉與倍率。依初始化、影格開始、繪製、上傳的順序使用。物理另行處理。角度每圈 16 步;模型倍率 256 為一倍。
Vec3 儲存 x/y/z,Edge 儲存頂點索引 a/b,Face 儲存三角形索引 a/b/c。Model 的 vertices、edges、faces 指向這些陣列,各計數表示其長度。edge_faces 包含相鄰面索引 f0/f1,缺少的面以 FACE_NONE 表示。flags 中的 MODEL_HIDDEN_LINES 要求依面選擇邊。投影後的有號面積決定面朝向,因此頂點順序很重要。
Object 儲存模型參照、位置 x/y/z、角度 rx/ry/rz、scale_q8 與 visible。物件可共用模型,但繪製不會複製表或自動切換其 ROM 記憶體庫。整個繪製期間須保持參照資料可讀。CGB 的 Object 另有色彩索引。
DMG3D_BeginFrame
開始繪製影格並停用遮蔽檢查。
語法
void DMG3D_BeginFrame();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120. 僅停用遮蔽篩選。暫存區通常在傳輸期間清空,首次空白暫存區由 Init 提供。不丟棄尚未提交的影格,不清除遮罩,也不重設待處理 BG 寫入或 dirty 旗標。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
DMG3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
DMG3D_SetCamera(8,0,0,0,0,0);
result[1]=DMG3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=DMG3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
DMG3D_SetCamera(0,0,0,0,0,0);
DMG3D_BeginFrame();
DMG3D_DrawLine2D(8,8,56,8);
DMG3D_DrawLine2D(56,8,56,40);
DMG3D_DrawLine2D(56,40,8,40);
DMG3D_DrawLine2D(8,40,8,8);
DMG3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
DMG3D_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
DMG3D_PutBgTile(1,1,160);
DMG3D_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_raster.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/dmg3d.h:17
WIRE3D_DMG_HEIGHT = 120. Disable occlusion filtering only. Stage clearing normally happens during transfer, and Init supplies the first clean stage. This does not discard an unsubmitted frame, clear the mask, or reset pending BG writes/dirty flags.
kitaqgb/lib/wire3d_dmg.c:2641
void Wire3DDMG_BeginFrame()
{
/* The consuming stage transfer clears D000 as it uploads, so BeginFrame only
resets draw state. Wire3DDMG_Init supplies the first clean buffer. */
w3ddmg_occlusion_active = 0;
}DMG3D_DrawIndexedEdges
依頂點與兩位元組邊索引配對,以整數倍率繪製線段模型。
語法
void DMG3D_DrawIndexedEdges(const Wire3DDMG_Vec3* vertices, w3ddmg_u8 vertex_count, const w3ddmg_u8* edges, w3ddmg_u8 edge_count, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 scale);參數
vertices3D 頂點陣列。
vertex_count頂點陣列的項目數。
edges每條邊的頂點索引,採用所宣告的結構或位元組配對格式。
edge_count邊的數量。
x點或物件原點的世界座標 X 分量。
y點或物件原點的世界座標 Y 分量。
z點或物件原點的世界座標 Z 分量。
scale整數倍率;零視為一。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120. 整數縮放與平移後繪製位元組配對的邊索引;倍率零表示一,沒有物件旋轉或面篩選。最多投影 24 個頂點。位元組偏移超過 255 後會回繞,因此最多提供 128 對邊。略過無效頂點 ID 或深度遭拒的端點,忽略 null 陣列。座標乘積與加總須可由 s16 表示。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Upload a main line and an auxiliary block separately; verify source consumption.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom DMG3D_Vec3 vertices[2]={{-32,0,0},{32,0,0}};
__prg_rom u8 edge_pairs[2]={0,1};
u8* stage_byte;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
DMG3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
DMG3D_BeginFrame();
DMG3D_DrawIndexedEdges(vertices,2,edge_pairs,1,-64,104,96,1);
DMG3D_TransferMainNow();
// Direct auxiliary transfer writes a separate tile after the main upload.
for(i=24;i<=31;i++) DMG3D_DrawLine2D(40,i,47,i);
stage_byte=(u8*)0xD518;result[1]=*stage_byte;
DMG3D_TransferAuxNow();result[2]=*stage_byte;
// Do not upload the consumed stage again.
result[7]=0xA55A; while(1) {}
}預期結果
以投影水平線與輔助 8×8 區塊示範直接傳輸;來源位元組被消耗時由 255 變為 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_direct.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_direct.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/dmg3d.h:20
WIRE3D_DMG_HEIGHT = 120. Draw byte-pair edge indices after integer scaling and translation; scale zero means one, and there is no object rotation or face filtering. Project at most 24 vertices. Supply at most 128 edge pairs because byte offsets wrap after 255. Invalid vertex IDs/depth-rejected endpoints are skipped; null arrays are ignored. Keep coordinate products/sums representable as s16.
kitaqgb/lib/wire3d_dmg.c:3824
void Wire3DDMG_DrawIndexedEdges(const Wire3DDMG_Vec3* vertices, w3ddmg_u8 vertex_count, const w3ddmg_u8* edges, w3ddmg_u8 edge_count, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 scale)
{
w3ddmg_u8 i;
w3ddmg_u8 count;
if (vertices == 0) return;
if (edges == 0) return;
count = vertex_count;
if (count > WIRE3D_DMG_MODEL_VERTEX_LIMIT) count = WIRE3D_DMG_MODEL_VERTEX_LIMIT;
if (scale == 0) scale = 1;
i = 0;
while (i < count)
{
const Wire3DDMG_Vec3* v;
w3ddmg_i16 vx;
w3ddmg_i16 vy;
w3ddmg_i16 vz;
w3ddmg_u8 sx;
w3ddmg_u8 sy;
v = &vertices[(__safe_index w3ddmg_u8)i];
vx = (w3ddmg_i16)(x + (w3ddmg_i16)(v->x * scale));
vy = (w3ddmg_i16)(y + (w3ddmg_i16)(v->y * scale));
vz = (w3ddmg_i16)(z + (w3ddmg_i16)(v->z * scale));
if (w3ddmg_project_world(vx, vy, vz, &sx, &sy))
{
w3ddmg_screen_x[(__safe_index w3ddmg_u8)i] = sx;
w3ddmg_screen_y[(__safe_index w3ddmg_u8)i] = sy;
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 1;
}
else
{
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 0;
}
i = (w3ddmg_u8)(i + 1);
}
i = 0;
while (i < edge_count)
{
w3ddmg_u8 a;
w3ddmg_u8 b;
a = edges[(__safe_index w3ddmg_u8)((w3ddmg_u8)(i << 1))];
b = edges[(__safe_index w3ddmg_u8)((w3ddmg_u8)((i << 1) + 1))];
if ((a < count) && (b < count) &&
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)a] &&
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)b])
{
Wire3DDMG_DrawLine2D(
w3ddmg_screen_x[(__safe_index w3ddmg_u8)a],
w3ddmg_screen_y[(__safe_index w3ddmg_u8)a],
w3ddmg_screen_x[(__safe_index w3ddmg_u8)b],
w3ddmg_screen_y[(__safe_index w3ddmg_u8)b]);
}
i = (w3ddmg_u8)(i + 1);
}
}DMG3D_DrawLine2D
在暫存區繪製包含兩端點、四連通的畫面空間線段。
語法
void DMG3D_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by);參數
ax頂點 A 的 X 座標,以視埠像素為單位。
ay頂點 A 的 Y 座標,以視埠像素為單位。
bx頂點 B 的 X 座標,以視埠像素為單位。
by頂點 B 的 Y 座標,以視埠像素為單位。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120. 啟用 dirty 傳輸時先標記圖塊外接矩形,再繪製暫存連通線。場景繪製可能利用五個遮罩取樣點剔除該線。須提供 128×120 視埠端點;低階像素邊界檢查不會對線段做幾何裁切。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
DMG3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
DMG3D_SetCamera(8,0,0,0,0,0);
result[1]=DMG3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=DMG3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
DMG3D_SetCamera(0,0,0,0,0,0);
DMG3D_BeginFrame();
DMG3D_DrawLine2D(8,8,56,8);
DMG3D_DrawLine2D(56,8,56,40);
DMG3D_DrawLine2D(56,40,8,40);
DMG3D_DrawLine2D(8,40,8,8);
DMG3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
DMG3D_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
DMG3D_PutBgTile(1,1,160);
DMG3D_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_raster.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/dmg3d.h:21
WIRE3D_DMG_HEIGHT = 120. Mark the bounding tile rectangle when dirty transfer is enabled, then draw a connected staged line. Scene drawing may reject it using five mask samples. Supply 128x120 viewport endpoints; low-level pixel bounds checks do not clip the segment geometrically.
kitaqgb/lib/wire3d_dmg.c:2685
void Wire3DDMG_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by)
{
w3ddmg_mark_line_dirty(ax, ay, bx, by);
if (w3ddmg_occlusion_active)
{
w3ddmg_line_stage_masked_c(ax, ay, bx, by);
return;
}
w3ddmg_line_x0 = ax;
w3ddmg_line_y0 = ay;
w3ddmg_line_x1 = bx;
w3ddmg_line_y1 = by;
if (ax < 128 && bx < 128 && ay < WIRE3D_DMG_SCREEN_H && by < WIRE3D_DMG_SCREEN_H)
w3ddmg_line_inside_asm();
else
w3ddmg_line_stage_asm();
}DMG3D_DrawLine3D
投影兩個世界座標端點,並在其間繪製線段。
語法
void DMG3D_DrawLine3D(w3ddmg_i16 ax, w3ddmg_i16 ay, w3ddmg_i16 az, w3ddmg_i16 bx, w3ddmg_i16 by, w3ddmg_i16 bz);參數
ax起點的世界座標 X 分量。
ay起點的世界座標 Y 分量。
az起點的世界座標 Z 分量。
bx終點的世界座標 X 分量。
by終點的世界座標 Y 分量。
bz終點的世界座標 Z 分量。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120. 投影兩個世界座標端點,僅在兩者均通過深度範圍時繪製。不求跨界線段與近/遠平面的交點;投影後端點各自限制於畫面邊緣。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
DMG3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
DMG3D_SetCamera(8,0,0,0,0,0);
result[1]=DMG3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=DMG3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
DMG3D_SetCamera(0,0,0,0,0,0);
DMG3D_BeginFrame();
DMG3D_DrawLine2D(8,8,56,8);
DMG3D_DrawLine2D(56,8,56,40);
DMG3D_DrawLine2D(56,40,8,40);
DMG3D_DrawLine2D(8,40,8,8);
DMG3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
DMG3D_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
DMG3D_PutBgTile(1,1,160);
DMG3D_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_raster.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/dmg3d.h:22
WIRE3D_DMG_HEIGHT = 120. Project both world endpoints and draw only when both pass the depth range. Do not intersect a crossing segment with near/far planes; projected endpoints are independently clamped to the screen edges.
kitaqgb/lib/wire3d_dmg.c:2808
void Wire3DDMG_DrawLine3D(w3ddmg_i16 ax, w3ddmg_i16 ay, w3ddmg_i16 az, w3ddmg_i16 bx, w3ddmg_i16 by, w3ddmg_i16 bz)
{
w3ddmg_u8 sx0;
w3ddmg_u8 sy0;
w3ddmg_u8 sx1;
w3ddmg_u8 sy1;
if (w3ddmg_project_world(ax, ay, az, &sx0, &sy0) == 0) return;
if (w3ddmg_project_world(bx, by, bz, &sx1, &sy1) == 0) return;
Wire3DDMG_DrawLine2D(sx0, sy0, sx1, sy1);
}DMG3D_DrawModel
以指定位置與旋轉,按原倍率繪製頂點與邊組成的模型。
語法
void DMG3D_DrawModel(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz);參數
model包含頂點、邊、面陣列及數量的模型;呼叫期間須保持各表可讀。
x點或物件原點的世界座標 X 分量。
y點或物件原點的世界座標 Y 分量。
z點或物件原點的世界座標 Z 分量。
rx繞 X 軸旋轉;十六步為一整圈。
ry繞 Y 軸旋轉;十六步為一整圈。
rz繞 Z 軸旋轉;十六步為一整圈。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120. 以倍率 256 委派給 DrawModelScaled,按原大小繪製模型。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom DMG3D_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom DMG3D_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
DMG3D_Model cube;
DMG3D_Object objects[2];
s16 px; s16 py; s16 pz;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
DMG3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;
DMG3D_BeginFrame();
// Upper pair: direct model calls at unity and half scale.
DMG3D_DrawModel(&cube,-32,32,96,0,0,0);
DMG3D_DrawModelScaled(&cube,32,32,96,0,0,0,128);
// Lower pair: the caller owns both object records and the model tables.
for(i=0;i<2;i++) {
objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
objects[i].y=-32;objects[i].z=96;
objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
}
DMG3D_DrawScene(objects,2);
// Numeric checks cover the operation supplied by this viewport profile.
px=16;py=0;pz=0;DMG3D_RotatePoint(&px,&py,&pz,0,4,0);
result[1]=px; result[2]=py; result[3]=pz;
DMG3D_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
原倍率與半倍率模型顯示在相同倍率的物件陣列場景上方,用以示範投影與縮放。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_models.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/dmg3d.h:23
WIRE3D_DMG_HEIGHT = 120. Draw an unscaled model by delegating to DrawModelScaled with scale 256.
kitaqgb/lib/wire3d_dmg.c:2827
void Wire3DDMG_DrawModel(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz)
{
Wire3DDMG_DrawModelScaled(model, x, y, z, rx, ry, rz, 256);
}DMG3D_DrawModelScaled
縮放模型,依 Y/X/Z 順序旋轉,平移並投影頂點,再繪製邊。
語法
void DMG3D_DrawModelScaled(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz, w3ddmg_i16 scale_q8);參數
model包含頂點、邊、面陣列及數量的模型;呼叫期間須保持各表可讀。
x點或物件原點的世界座標 X 分量。
y點或物件原點的世界座標 Y 分量。
z點或物件原點的世界座標 Z 分量。
rx繞 X 軸旋轉;十六步為一整圈。
ry繞 Y 軸旋轉;十六步為一整圈。
rz繞 Z 軸旋轉;十六步為一整圈。
scale_q8倍率,以 256 表示一倍;非正值也視為一倍。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120. 縮放最多 24 個頂點,旋轉 Y/X/Z、平移並投影,再遍歷 edge_count(位元組型別的計數)的全部項目,可選擇依相鄰面篩選。面暫存最多 16 個;邊表須包含所有宣告項目。非正倍率視為 256。忽略 null 模型/頂點/邊指標。乘積與平移結果須保持在有號 16 位元範圍內;跨越深度邊界的邊會捨棄。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom DMG3D_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom DMG3D_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
DMG3D_Model cube;
DMG3D_Object objects[2];
s16 px; s16 py; s16 pz;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
DMG3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;
DMG3D_BeginFrame();
// Upper pair: direct model calls at unity and half scale.
DMG3D_DrawModel(&cube,-32,32,96,0,0,0);
DMG3D_DrawModelScaled(&cube,32,32,96,0,0,0,128);
// Lower pair: the caller owns both object records and the model tables.
for(i=0;i<2;i++) {
objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
objects[i].y=-32;objects[i].z=96;
objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
}
DMG3D_DrawScene(objects,2);
// Numeric checks cover the operation supplied by this viewport profile.
px=16;py=0;pz=0;DMG3D_RotatePoint(&px,&py,&pz,0,4,0);
result[1]=px; result[2]=py; result[3]=pz;
DMG3D_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
原倍率與半倍率模型顯示在相同倍率的物件陣列場景上方,用以示範投影與縮放。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_models.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/dmg3d.h:24
WIRE3D_DMG_HEIGHT = 120. Scale up to 24 vertices, rotate Y/X/Z, translate and project, then traverse all edge_count entries (a byte count) with optional adjacent-face filtering. Face scratch is capped at 16; edge tables must contain all declared entries. Nonpositive scale means 256. Null model/vertex/edge pointers are ignored. Keep products/translations in signed 16-bit range; depth-crossing edges are dropped.
kitaqgb/lib/wire3d_dmg.c:2972
void Wire3DDMG_DrawModelScaled(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz, w3ddmg_i16 scale_q8)
{
w3ddmg_u8 i;
w3ddmg_u8 count;
w3ddmg_u8 edge_count;
w3ddmg_u8 face_count;
if (model == 0) return;
if (model->vertices == 0) return;
if (model->edges == 0) return;
if (scale_q8 <= 0) scale_q8 = 256;
count = model->vertex_count;
if (count > WIRE3D_DMG_MODEL_VERTEX_LIMIT) count = WIRE3D_DMG_MODEL_VERTEX_LIMIT;
i = 0;
while (i < count)
{
const Wire3DDMG_Vec3* v;
w3ddmg_i16 vx;
w3ddmg_i16 vy;
w3ddmg_i16 vz;
w3ddmg_u8 sx;
w3ddmg_u8 sy;
v = &model->vertices[(__safe_index w3ddmg_u8)i];
vx = (w3ddmg_i16)((v->x * scale_q8) >> 8);
vy = (w3ddmg_i16)((v->y * scale_q8) >> 8);
vz = (w3ddmg_i16)((v->z * scale_q8) >> 8);
w3ddmg_rotate_y(&vx, &vz, ry);
w3ddmg_rotate_x(&vy, &vz, rx);
w3ddmg_rotate_z(&vx, &vy, rz);
vx = (w3ddmg_i16)(vx + x);
vy = (w3ddmg_i16)(vy + y);
vz = (w3ddmg_i16)(vz + z);
if (w3ddmg_project_world(vx, vy, vz, &sx, &sy))
{
w3ddmg_screen_x[(__safe_index w3ddmg_u8)i] = sx;
w3ddmg_screen_y[(__safe_index w3ddmg_u8)i] = sy;
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 1;
}
else
{
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 0;
}
i = (w3ddmg_u8)(i + 1);
}
face_count = model->face_count;
if (face_count > WIRE3D_DMG_MODEL_FACE_LIMIT) face_count = WIRE3D_DMG_MODEL_FACE_LIMIT;
if ((model->flags & WIRE3D_DMG_MODEL_HIDDEN_LINES) && (model->faces != 0) && (model->edge_faces != 0))
{
w3ddmg_build_face_visibility(model, count, face_count);
}
edge_count = model->edge_count;
i = 0;
while (i < edge_count)
{
const Wire3DDMG_Edge* e;
e = &model->edges[(__safe_index w3ddmg_u8)i];
if ((e->a < count) && (e->b < count))
{
if (w3ddmg_screen_visible[(__safe_index w3ddmg_u8)e->a] &&
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)e->b] &&
w3ddmg_is_edge_visible(model, i, face_count))
{
Wire3DDMG_DrawLine2D(
w3ddmg_screen_x[(__safe_index w3ddmg_u8)e->a],
w3ddmg_screen_y[(__safe_index w3ddmg_u8)e->a],
w3ddmg_screen_x[(__safe_index w3ddmg_u8)e->b],
w3ddmg_screen_y[(__safe_index w3ddmg_u8)e->b]);
}
}
i = (w3ddmg_u8)(i + 1);
}
}DMG3D_DrawScene
由近至遠繪製最多八個物件,以較近的面遮住後續邊。
語法
void DMG3D_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count);參數
objects包含位置、旋轉、倍率與可見旗標的物件陣列。
count提供的陣列項目數;處理上限請參閱各操作的說明。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120. 依相機深度將最多八個物件原點由近至遠排序。繪製可見且有效的模型,並為後續物件標記正面外接矩形。排序後第一個槽略過遮罩檢查,最後一個則不需要新遮蔽物。這是粗略的線段剔除,不是深度緩衝區。忽略 null/空輸入;遍歷時呼叫端資料與目前投影快取須維持有效。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom DMG3D_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom DMG3D_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
DMG3D_Model cube;
DMG3D_Object objects[2];
s16 px; s16 py; s16 pz;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
DMG3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;
DMG3D_BeginFrame();
// Upper pair: direct model calls at unity and half scale.
DMG3D_DrawModel(&cube,-32,32,96,0,0,0);
DMG3D_DrawModelScaled(&cube,32,32,96,0,0,0,128);
// Lower pair: the caller owns both object records and the model tables.
for(i=0;i<2;i++) {
objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
objects[i].y=-32;objects[i].z=96;
objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
}
DMG3D_DrawScene(objects,2);
// Numeric checks cover the operation supplied by this viewport profile.
px=16;py=0;pz=0;DMG3D_RotatePoint(&px,&py,&pz,0,4,0);
result[1]=px; result[2]=py; result[3]=pz;
DMG3D_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
原倍率與半倍率模型顯示在相同倍率的物件陣列場景上方,用以示範投影與縮放。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_models.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/dmg3d.h:25
WIRE3D_DMG_HEIGHT = 120. Sort at most eight object origins by camera depth, near to far. Draw visible valid models and mark front-face bounding rectangles for later objects. The first sorted slot bypasses mask tests and the last needs no new occluder. This is coarse line rejection, not a depth buffer. Null/empty input is ignored; caller data and the current projection cache must remain valid during traversal.
kitaqgb/lib/wire3d_dmg.c:2723
void Wire3DDMG_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count)
{
w3ddmg_u8 scene_count;
w3ddmg_u8 i;
if (objects == 0) return;
scene_count = count;
if (scene_count > WIRE3D_DMG_SCENE_OBJECT_LIMIT) scene_count = WIRE3D_DMG_SCENE_OBJECT_LIMIT;
if (scene_count == 0) return;
i = 0;
while (i < scene_count)
{
w3ddmg_scene_order[(__safe_index w3ddmg_u8)i] = i;
w3ddmg_scene_depth[(__safe_index w3ddmg_u8)i] = w3ddmg_scene_object_depth(&objects[(__safe_index w3ddmg_u8)i]);
i = (w3ddmg_u8)(i + 1);
}
i = 0;
while (i < scene_count)
{
w3ddmg_u8 j;
j = (w3ddmg_u8)(i + 1);
while (j < scene_count)
{
w3ddmg_u8 oi;
w3ddmg_u8 oj;
oi = w3ddmg_scene_order[(__safe_index w3ddmg_u8)i];
oj = w3ddmg_scene_order[(__safe_index w3ddmg_u8)j];
if (w3ddmg_scene_depth[(__safe_index w3ddmg_u8)oj] < w3ddmg_scene_depth[(__safe_index w3ddmg_u8)oi])
{
w3ddmg_scene_order[(__safe_index w3ddmg_u8)i] = oj;
w3ddmg_scene_order[(__safe_index w3ddmg_u8)j] = oi;
}
j = (w3ddmg_u8)(j + 1);
}
i = (w3ddmg_u8)(i + 1);
}
w3ddmg_clear_occlusion_mask();
w3ddmg_occlusion_active = 0;
i = 0;
while (i < scene_count)
{
Wire3DDMG_Object* obj;
obj = &objects[(__safe_index w3ddmg_u8)w3ddmg_scene_order[(__safe_index w3ddmg_u8)i]];
if ((obj->visible != 0) && (obj->model != 0))
{
w3ddmg_occlusion_active = i == 0 ? 0 : 1;
Wire3DDMG_DrawModelScaled(obj->model, obj->x, obj->y, obj->z, obj->rx, obj->ry, obj->rz, obj->scale_q8);
if ((w3ddmg_u8)(i + 1) < scene_count)
{
w3ddmg_mark_model_occluder(obj->model);
}
}
i = (w3ddmg_u8)(i + 1);
}
w3ddmg_occlusion_active = 0;
}DMG3D_EndFrame
將待處理背景寫入與暫存繪圖提交至 VRAM。
語法
void DMG3D_EndFrame();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120. 等待下一次 VBlank 並送出 BG 寫入,再依設定先消耗輔助條帶,然後上傳 dirty 圖塊或整個主暫存區。輔助/主來源重疊,因此順序很重要。STAT 輪詢會跨越可存取時段持續進行;更新不一定能在一次 VBlank 內完成。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
DMG3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
DMG3D_SetCamera(8,0,0,0,0,0);
result[1]=DMG3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=DMG3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
DMG3D_SetCamera(0,0,0,0,0,0);
DMG3D_BeginFrame();
DMG3D_DrawLine2D(8,8,56,8);
DMG3D_DrawLine2D(56,8,56,40);
DMG3D_DrawLine2D(56,40,8,40);
DMG3D_DrawLine2D(8,40,8,8);
DMG3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
DMG3D_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
DMG3D_PutBgTile(1,1,160);
DMG3D_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_raster.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/dmg3d.h:28
WIRE3D_DMG_HEIGHT = 120. Wait for the next VBlank and flush BG writes, then optionally consume the auxiliary strips before uploading either dirty tiles or the entire main stage. Auxiliary/main source overlap makes that ordering significant. STAT polling continues across access windows; the update need not fit one VBlank.
kitaqgb/lib/wire3d_dmg.c:3081
void Wire3DDMG_EndFrame()
{
w3ddmg_wait_vblank_start();
w3ddmg_flush_bg_queue();
if (w3ddmg_aux_transfer_enabled)
{
w3ddmg_transfer_stage_aux_asm();
}
if (w3ddmg_dirty_transfer_enabled)
{
w3ddmg_transfer_dirty_stage();
}
else
{
w3ddmg_transfer_stage_asm();
}
}DMG3D_EraseModelFaces
投影模型朝前的三角形,並擦除其內部暫存像素。
語法
void DMG3D_EraseModelFaces(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz, w3ddmg_i16 scale_q8);參數
model包含頂點、邊、面陣列及數量的模型;呼叫期間須保持各表可讀。
x點或物件原點的世界座標 X 分量。
y點或物件原點的世界座標 Y 分量。
z點或物件原點的世界座標 Z 分量。
rx繞 X 軸旋轉;十六步為一整圈。
ry繞 Y 軸旋轉;十六步為一整圈。
rz繞 Z 軸旋轉;十六步為一整圈。
scale_q8倍率,以 256 表示一倍;非正值也視為一倍。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120. 對具有隱線旗標與面資料的模型,投影最多 24 個頂點,並從暫存區擦除朝前三角形的內部。非正倍率表示 256(一倍)。最多考慮 16 個面,跨越深度邊界的面會略過。亦會替換共用投影快取,但不更新 VRAM。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Erase a screen triangle and a projected model face from separate filled panels.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom DMG3D_Vec3 vertices[4]={{-24,-24,0},{24,-24,0},{24,24,0},{-24,24,0}};
__prg_rom DMG3D_Edge edges[4]={{0,1},{1,2},{2,3},{3,0}};
__prg_rom DMG3D_Face faces[2]={{0,2,1},{0,3,2}};
DMG3D_Model plane;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
DMG3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
plane.vertices=vertices;plane.edges=edges;plane.faces=faces;plane.edge_faces=0;
plane.vertex_count=4;plane.edge_count=4;plane.face_count=2;plane.flags=1;
DMG3D_BeginFrame();
// Separate panels show a direct screen triangle and a projected square face.
for(i=8;i<=32;i++) DMG3D_DrawLine2D(8,i,32,i);
for(i=36;i<=84;i++) DMG3D_DrawLine2D(40,i,88,i);
DMG3D_EraseTriangle2D(12,12,28,12,12,28);
DMG3D_EraseModelFaces(&plane,0,0,64,0,0,0,256);
DMG3D_EndFrame(); result[7]=0xA55A; while(1) {}
}預期結果
投影後的面會擦除填滿區域,可看出保留與清除的部分。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_faces.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_faces.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/dmg3d.h:29
WIRE3D_DMG_HEIGHT = 120. Project up to 24 vertices and erase front-facing triangle interiors from the stage for a model with hidden-line flags and face data. Nonpositive scale means 256 (unity). Up to 16 faces are considered; depth-crossing faces are skipped. This also replaces shared projection caches, but does not update VRAM.
kitaqgb/lib/wire3d_dmg.c:2843
void Wire3DDMG_EraseModelFaces(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz, w3ddmg_i16 scale_q8)
{
w3ddmg_u8 i;
w3ddmg_u8 count;
w3ddmg_u8 face_count;
if (model == 0) return;
if (model->vertices == 0) return;
if (model->faces == 0) return;
if ((model->flags & WIRE3D_DMG_MODEL_HIDDEN_LINES) == 0) return;
if (scale_q8 <= 0) scale_q8 = 256;
count = model->vertex_count;
if (count > WIRE3D_DMG_MODEL_VERTEX_LIMIT) count = WIRE3D_DMG_MODEL_VERTEX_LIMIT;
i = 0;
while (i < count)
{
const Wire3DDMG_Vec3* v;
w3ddmg_i16 vx;
w3ddmg_i16 vy;
w3ddmg_i16 vz;
w3ddmg_u8 sx;
w3ddmg_u8 sy;
v = &model->vertices[(__safe_index w3ddmg_u8)i];
vx = (w3ddmg_i16)((v->x * scale_q8) >> 8);
vy = (w3ddmg_i16)((v->y * scale_q8) >> 8);
vz = (w3ddmg_i16)((v->z * scale_q8) >> 8);
w3ddmg_rotate_y(&vx, &vz, ry);
w3ddmg_rotate_x(&vy, &vz, rx);
w3ddmg_rotate_z(&vx, &vy, rz);
vx = (w3ddmg_i16)(vx + x);
vy = (w3ddmg_i16)(vy + y);
vz = (w3ddmg_i16)(vz + z);
if (w3ddmg_project_world(vx, vy, vz, &sx, &sy))
{
w3ddmg_screen_x[(__safe_index w3ddmg_u8)i] = sx;
w3ddmg_screen_y[(__safe_index w3ddmg_u8)i] = sy;
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 1;
}
else
{
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 0;
}
i = (w3ddmg_u8)(i + 1);
}
face_count = model->face_count;
if (face_count > WIRE3D_DMG_MODEL_FACE_LIMIT) face_count = WIRE3D_DMG_MODEL_FACE_LIMIT;
w3ddmg_build_face_visibility(model, count, face_count);
i = 0;
while (i < face_count)
{
const Wire3DDMG_Face* f;
f = &model->faces[(__safe_index w3ddmg_u8)i];
if (w3ddmg_face_visible[(__safe_index w3ddmg_u8)i] &&
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)f->a] &&
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)f->b] &&
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)f->c])
{
w3ddmg_clear_triangle(
w3ddmg_screen_x[(__safe_index w3ddmg_u8)f->a],
w3ddmg_screen_y[(__safe_index w3ddmg_u8)f->a],
w3ddmg_screen_x[(__safe_index w3ddmg_u8)f->b],
w3ddmg_screen_y[(__safe_index w3ddmg_u8)f->b],
w3ddmg_screen_x[(__safe_index w3ddmg_u8)f->c],
w3ddmg_screen_y[(__safe_index w3ddmg_u8)f->c]);
}
i = (w3ddmg_u8)(i + 1);
}
}DMG3D_EraseSpan2D
在暫存區的一列中擦除包含兩端點的水平跨度。
語法
void DMG3D_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1);參數
y要擦除之列的像素 Y 座標。
x0較小的 X 端點,以視埠像素為單位;排序與裁切依此操作的注意事項。
x1較大的 X 端點,以視埠像素為單位;排序與裁切依此操作的注意事項。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120. 排序 X 端點並擦除包含端點的暫存跨度。兩端點皆須在 0..127;無效 Y 會被忽略。此常式不代為裁切 X。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
DMG3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
DMG3D_SetCamera(8,0,0,0,0,0);
result[1]=DMG3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=DMG3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
DMG3D_SetCamera(0,0,0,0,0,0);
DMG3D_BeginFrame();
DMG3D_DrawLine2D(8,8,56,8);
DMG3D_DrawLine2D(56,8,56,40);
DMG3D_DrawLine2D(56,40,8,40);
DMG3D_DrawLine2D(8,40,8,8);
DMG3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
DMG3D_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
DMG3D_PutBgTile(1,1,160);
DMG3D_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_raster.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/dmg3d.h:30
WIRE3D_DMG_HEIGHT = 120. Order the X endpoints and erase the inclusive staged span. Both endpoints must be in 0..127; invalid Y is ignored. The routine does not clip X for you.
kitaqgb/lib/wire3d_dmg.c:2943
void Wire3DDMG_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1)
{
w3ddmg_u8 tx;
if (x0 > x1)
{
tx = x0;
x0 = x1;
x1 = tx;
}
w3ddmg_stage_clear_span(y, x0, x1);
}DMG3D_EraseTriangle2D
使用水平掃描線跨度,從暫存區擦除畫面空間三角形。
語法
void DMG3D_EraseTriangle2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by, w3ddmg_u8 cx, w3ddmg_u8 cy);參數
ax頂點 A 的 X 座標,以視埠像素為單位。
ay頂點 A 的 Y 座標,以視埠像素為單位。
bx頂點 B 的 X 座標,以視埠像素為單位。
by頂點 B 的 Y 座標,以視埠像素為單位。
cx頂點 C 的 X 座標,以視埠像素為單位。
cy頂點 C 的 Y 座標,以視埠像素為單位。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120. 利用整數掃描線交點,從暫存像素擦除三角形。須提供視埠座標。忽略退化三角形;遮蔽遮罩與 VRAM 不變。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Erase a screen triangle and a projected model face from separate filled panels.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom DMG3D_Vec3 vertices[4]={{-24,-24,0},{24,-24,0},{24,24,0},{-24,24,0}};
__prg_rom DMG3D_Edge edges[4]={{0,1},{1,2},{2,3},{3,0}};
__prg_rom DMG3D_Face faces[2]={{0,2,1},{0,3,2}};
DMG3D_Model plane;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
DMG3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
plane.vertices=vertices;plane.edges=edges;plane.faces=faces;plane.edge_faces=0;
plane.vertex_count=4;plane.edge_count=4;plane.face_count=2;plane.flags=1;
DMG3D_BeginFrame();
// Separate panels show a direct screen triangle and a projected square face.
for(i=8;i<=32;i++) DMG3D_DrawLine2D(8,i,32,i);
for(i=36;i<=84;i++) DMG3D_DrawLine2D(40,i,88,i);
DMG3D_EraseTriangle2D(12,12,28,12,12,28);
DMG3D_EraseModelFaces(&plane,0,0,64,0,0,0,256);
DMG3D_EndFrame(); result[7]=0xA55A; while(1) {}
}預期結果
投影後的面會擦除填滿區域,可看出保留與清除的部分。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_faces.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_faces.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/dmg3d.h:31
WIRE3D_DMG_HEIGHT = 120. Erase a triangle from staged pixels using integer scanline intersections. Supply viewport coordinates. Degenerate triangles are ignored; the occlusion mask and VRAM are unchanged.
kitaqgb/lib/wire3d_dmg.c:2933
void Wire3DDMG_EraseTriangle2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by, w3ddmg_u8 cx, w3ddmg_u8 cy)
{
w3ddmg_clear_triangle(ax, ay, bx, by, cx, cy);
}DMG3D_Init
為單色線框視埠初始化 LCD、圖塊及背景地圖。
語法
void DMG3D_Init();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120. 接管 LCD 狀態,清空圖塊 VRAM 與 BG 地圖,從地圖圖塊 (3,1) 開始建立 16×15 視埠。設定捲動 (8,0)、BGP=0xB4 與 BG 顯示。重設相機、佇列、傳輸模式、兩份 dirty 表及暫存區。須保留 0xD000..0xDFFF 並維持 WRAM 映射;輔助儲存區與此區域共用位址。繪製前呼叫 BeginFrame 建立遮蔽狀態。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
DMG3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
DMG3D_SetCamera(8,0,0,0,0,0);
result[1]=DMG3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=DMG3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
DMG3D_SetCamera(0,0,0,0,0,0);
DMG3D_BeginFrame();
DMG3D_DrawLine2D(8,8,56,8);
DMG3D_DrawLine2D(56,8,56,40);
DMG3D_DrawLine2D(56,40,8,40);
DMG3D_DrawLine2D(8,40,8,8);
DMG3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
DMG3D_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
DMG3D_PutBgTile(1,1,160);
DMG3D_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_raster.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/dmg3d.h:35
WIRE3D_DMG_HEIGHT = 120. Take over LCD state, clear tile VRAM and the BG map, and install a 16x15 viewport beginning at map tile (3,1). Set scroll (8,0), BGP=0xB4 and BG display. Reset camera, queues, transfer modes, both dirty tables and stage. Reserve 0xD000..0xDFFF and retain its WRAM mapping; auxiliary storage aliases it. Call BeginFrame before drawing to establish occlusion state.
kitaqgb/lib/wire3d_dmg.c:2572
void Wire3DDMG_Init()
{
w3ddmg_u8 row;
w3ddmg_u8 col;
w3ddmg_u8 tid;
w3ddmg_u16 off;
w3ddmg_wait_vblank_start();
w3ddmg_reg_lcdc = 0;
w3ddmg_clear_vram_asm();
w3ddmg_fill_bg_map_asm();
row = 0;
tid = 0x90;
while (row < WIRE3D_DMG_TILE_H)
{
off = (w3ddmg_u16)(0x23 + ((w3ddmg_u16)row << 5));
col = 0;
while (col < WIRE3D_DMG_TILE_W)
{
w3ddmg_bg_map_9800[(w3ddmg_u16)(off + (w3ddmg_u16)col)] = tid;
tid = (w3ddmg_u8)(tid + WIRE3D_DMG_TILE_H);
col = (w3ddmg_u8)(col + 1);
}
row = (w3ddmg_u8)(row + 1);
tid = (w3ddmg_u8)(0x90 + row);
}
w3ddmg_reg_scx = 8;
w3ddmg_reg_scy = 0;
w3ddmg_reg_bgp = 0xB4;
w3ddmg_reg_lcdc = 0x81;
w3ddmg_bgq_count = 0;
w3ddmg_aux_transfer_enabled = 0;
w3ddmg_dirty_transfer_enabled = 0;
Wire3DDMG_SetCamera(0, 0, 0, 0, 0, 0);
w3ddmg_clear_stage_asm();
w3ddmg_clear_stage_aux_asm();
w3ddmg_clear_dirty_tables();
}DMG3D_ProjectPoint
將世界座標點透過相機投影至視埠座標。
語法
w3ddmg_u8 DMG3D_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy);參數
x點或物件原點的世界座標 X 分量。
y點或物件原點的世界座標 Y 分量。
z點或物件原點的世界座標 Z 分量。
sx接收投影 X 座標的有效可寫入 u8 指標。
sy接收投影 Y 座標的有效可寫入 u8 指標。
回傳值
投影成功傳回 1,深度遭拒傳回 0。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120. 以目前相機投影世界座標點。深度無效時傳回零且不改變輸出;成功時寫入限制於 128×120 的座標。兩個輸出指標皆須有效;座標差須容納於 s16。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
DMG3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
DMG3D_SetCamera(8,0,0,0,0,0);
result[1]=DMG3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=DMG3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
DMG3D_SetCamera(0,0,0,0,0,0);
DMG3D_BeginFrame();
DMG3D_DrawLine2D(8,8,56,8);
DMG3D_DrawLine2D(56,8,56,40);
DMG3D_DrawLine2D(56,40,8,40);
DMG3D_DrawLine2D(8,40,8,8);
DMG3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
DMG3D_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
DMG3D_PutBgTile(1,1,160);
DMG3D_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_raster.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/dmg3d.h:43
WIRE3D_DMG_HEIGHT = 120. Project a world point with the current camera. Return zero for invalid depth without changing outputs; success writes clamped 128x120 coordinates. Both output pointers must be valid. Coordinate differences must fit s16.
kitaqgb/lib/wire3d_dmg.c:549
w3ddmg_u8 Wire3DDMG_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy)
{
return w3ddmg_project_world(x, y, z, sx, sy);
}DMG3D_PutBgTile
將背景地圖一格的圖塊編號寫入排入佇列。
語法
void DMG3D_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile);參數
x32×32 背景地圖中的 X 圖塊座標。
y32×32 背景地圖中的 Y 圖塊座標。
tile背景格的八位元圖塊編號。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120. 將 0x9800 的 32×32 地圖圖塊寫入排入佇列,交由 EndFrame 處理。無效地圖座標及超過 48 筆待處理寫入的要求會直接忽略,不另行回報。此佇列與一般 vram 函式庫佇列分開。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
DMG3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
DMG3D_SetCamera(8,0,0,0,0,0);
result[1]=DMG3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=DMG3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
DMG3D_SetCamera(0,0,0,0,0,0);
DMG3D_BeginFrame();
DMG3D_DrawLine2D(8,8,56,8);
DMG3D_DrawLine2D(56,8,56,40);
DMG3D_DrawLine2D(56,40,8,40);
DMG3D_DrawLine2D(8,40,8,8);
DMG3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
DMG3D_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
DMG3D_PutBgTile(1,1,160);
DMG3D_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_raster.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/dmg3d.h:44
WIRE3D_DMG_HEIGHT = 120. Queue a tile write to the 32x32 map at 0x9800 for EndFrame. Invalid map coordinates and submissions beyond 48 pending writes are silently ignored. This queue is separate from the general vram library queue.
kitaqgb/lib/wire3d_dmg.c:582
void Wire3DDMG_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile)
{
if (x >= 32) return;
if (y >= 32) return;
if (w3ddmg_bgq_count >= WIRE3D_DMG_BG_QUEUE_LIMIT) return;
w3ddmg_bgq_x[(__safe_index w3ddmg_u8)w3ddmg_bgq_count] = x;
w3ddmg_bgq_y[(__safe_index w3ddmg_u8)w3ddmg_bgq_count] = y;
w3ddmg_bgq_tile[(__safe_index w3ddmg_u8)w3ddmg_bgq_count] = tile;
w3ddmg_bgq_count = (w3ddmg_u8)(w3ddmg_bgq_count + 1);
}DMG3D_RotatePoint
依指定角度就地旋轉一個點。
語法
void DMG3D_RotatePoint(w3ddmg_i16* x, w3ddmg_i16* y, w3ddmg_i16* z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz);參數
xX 分量的可寫入 s16 指標,須與其他分量指向不同位置。
yY 分量的可寫入 s16 指標,須與其他分量指向不同位置。
zZ 分量的可寫入 s16 指標,須與其他分量指向不同位置。
rx繞 X 軸旋轉;十六步為一整圈。
ry繞 Y 軸旋轉;十六步為一整圈。
rz繞 Z 軸旋轉;十六步為一整圈。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120. 以每圈 16 步依 Y/X/Z 順序就地旋轉。任一分量指標為 null 時,整個呼叫不動作;各指標須指向不同位置。每個軸旋轉會將輸入限制於 ±220。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom DMG3D_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom DMG3D_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
DMG3D_Model cube;
DMG3D_Object objects[2];
s16 px; s16 py; s16 pz;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
DMG3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;
DMG3D_BeginFrame();
// Upper pair: direct model calls at unity and half scale.
DMG3D_DrawModel(&cube,-32,32,96,0,0,0);
DMG3D_DrawModelScaled(&cube,32,32,96,0,0,0,128);
// Lower pair: the caller owns both object records and the model tables.
for(i=0;i<2;i++) {
objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
objects[i].y=-32;objects[i].z=96;
objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
}
DMG3D_DrawScene(objects,2);
// Numeric checks cover the operation supplied by this viewport profile.
px=16;py=0;pz=0;DMG3D_RotatePoint(&px,&py,&pz,0,4,0);
result[1]=px; result[2]=py; result[3]=pz;
DMG3D_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
原倍率與半倍率模型顯示在相同倍率的物件陣列場景上方,用以示範投影與縮放。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_models.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/dmg3d.h:46
WIRE3D_DMG_HEIGHT = 120. Rotate in place in Y/X/Z order using 16 steps per full turn. A null component pointer makes the whole call a no-op; use distinct pointers. Each axis rotation clamps its inputs to +/-220.
kitaqgb/lib/wire3d_dmg.c:3121
void Wire3DDMG_RotatePoint(w3ddmg_i16* x, w3ddmg_i16* y, w3ddmg_i16* z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz)
{
if (x == 0) return;
if (y == 0) return;
if (z == 0) return;
w3ddmg_rotate_y(x, z, ry);
w3ddmg_rotate_x(y, z, rx);
w3ddmg_rotate_z(x, y, rz);
}DMG3D_SetAuxTransfer
選擇 EndFrame 是否一併傳輸輔助條帶。
語法
void DMG3D_SetAuxTransfer(w3ddmg_u8 flag);參數
flag零停用此傳輸功能,其他值均啟用。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120. 儲存 EndFrame 的輔助傳輸開關;任何非零值均啟用。此處不複製或清除資料。輔助來源位元組與主暫存區共用位址。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Use the auxiliary-transfer gate to consume an overlapping stage strip.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
DMG3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
DMG3D_SetDirtyTransfer(1); DMG3D_SetAuxTransfer(1);
DMG3D_BeginFrame();
for(i=24;i<=31;i++) DMG3D_DrawLine2D(40,i,47,i);
// Auxiliary upload consumes this source before the dirty main tile is sent.
DMG3D_EndFrame(); result[7]=0xA55A; while(1) {}
}預期結果
主暫存區的一部分由輔助傳輸消耗,在畫面座標 (80,24) 產生黑色 8×8 區塊。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_aux_gate.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_aux_gate.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/dmg3d.h:50
WIRE3D_DMG_HEIGHT = 120. Store the EndFrame auxiliary-transfer gate; any nonzero value enables it. No data is copied or cleared here. Auxiliary source bytes alias the main stage.
kitaqgb/lib/wire3d_dmg.c:3895
void Wire3DDMG_SetAuxTransfer(w3ddmg_u8 flag)
{
w3ddmg_aux_transfer_enabled = flag;
}DMG3D_SetCamera
儲存後續投影使用的相機位置與朝向。
語法
void DMG3D_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 pitch, w3ddmg_u8 yaw, w3ddmg_u8 roll);參數
x相機的世界座標 X 分量。
y相機的世界座標 Y 分量。
z相機的世界座標 Z 分量。
pitch繞 X 軸旋轉;十六步為一整圈。
yaw繞 Y 軸旋轉;十六步為一整圈。
roll繞 Z 軸旋轉;十六步為一整圈。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120. 儲存後續繪製使用的相機位置與角度;每圈 16 個角度步階。不重新投影既有繪圖,也不驗證輸入範圍。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
DMG3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
DMG3D_SetCamera(8,0,0,0,0,0);
result[1]=DMG3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=DMG3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
DMG3D_SetCamera(0,0,0,0,0,0);
DMG3D_BeginFrame();
DMG3D_DrawLine2D(8,8,56,8);
DMG3D_DrawLine2D(56,8,56,40);
DMG3D_DrawLine2D(56,40,8,40);
DMG3D_DrawLine2D(8,40,8,8);
DMG3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
DMG3D_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
DMG3D_PutBgTile(1,1,160);
DMG3D_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_raster.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/dmg3d.h:51
WIRE3D_DMG_HEIGHT = 120. Store camera position and angles for later draws; a full turn is 16 angle steps. No existing drawing is reprojected and no input range validation occurs.
kitaqgb/lib/wire3d_dmg.c:2661
void Wire3DDMG_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 pitch, w3ddmg_u8 yaw, w3ddmg_u8 roll)
{
w3ddmg_cam_x = x;
w3ddmg_cam_y = y;
w3ddmg_cam_z = z;
w3ddmg_cam_pitch = pitch;
w3ddmg_cam_yaw = yaw;
w3ddmg_cam_roll = roll;
}DMG3D_SetDirtyTransfer
為高度 120 的主視埠選擇 dirty 圖塊傳輸。
語法
void DMG3D_SetDirtyTransfer(w3ddmg_u8 flag);參數
flag零停用此傳輸功能,其他值均啟用。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120. 儲存 dirty 傳輸開關,並清除兩份 dirty 歷史與主暫存區,即使設定值未變也會清除。保留 VRAM;若在舊畫面上啟用,可能留下未標記的舊圖塊,因此須先準備乾淨的顯示基準。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Remove the previous frame and upload only the tracked current/previous tiles.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
DMG3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
DMG3D_SetDirtyTransfer(1); DMG3D_SetAuxTransfer(0);
DMG3D_BeginFrame();
DMG3D_DrawLine2D(8,8,24,8); DMG3D_DrawLine2D(24,8,24,24);
DMG3D_DrawLine2D(24,24,8,24); DMG3D_DrawLine2D(8,24,8,8);
DMG3D_EndFrame();
DMG3D_BeginFrame();
DMG3D_DrawLine2D(80,80,104,80); DMG3D_DrawLine2D(104,80,104,104);
DMG3D_DrawLine2D(104,104,80,104); DMG3D_DrawLine2D(80,104,80,80);
DMG3D_EndFrame(); result[7]=0xA55A; while(1) {}
}預期結果
原先左上角的框消失,只留下畫面座標 (96,88)..(120,112) 的新框。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_dirty.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_dirty.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/dmg3d.h:52
WIRE3D_DMG_HEIGHT = 120. Store the dirty-transfer gate and clear both dirty histories and the main stage, even if the value is unchanged. VRAM is retained; enabling this over an old image can leave unmarked old tiles, so arrange a clean displayed baseline.
kitaqgb/lib/wire3d_dmg.c:3955
void Wire3DDMG_SetDirtyTransfer(w3ddmg_u8 flag)
{
w3ddmg_dirty_transfer_enabled = flag;
w3ddmg_clear_dirty_tables();
w3ddmg_clear_stage_asm();
}DMG3D_SetPalette
寫入單色背景調色盤暫存器 BGP 的四階明暗對應。
語法
void DMG3D_SetPalette(w3ddmg_u8 bgp);參數
bgp包含四個兩位元明暗指定的 BGP 暫存器值。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120. 立即寫入原始 DMG BGP 調色盤編碼,不進行影格同步。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
DMG3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
DMG3D_SetCamera(8,0,0,0,0,0);
result[1]=DMG3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=DMG3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
DMG3D_SetCamera(0,0,0,0,0,0);
DMG3D_BeginFrame();
DMG3D_DrawLine2D(8,8,56,8);
DMG3D_DrawLine2D(56,8,56,40);
DMG3D_DrawLine2D(56,40,8,40);
DMG3D_DrawLine2D(8,40,8,8);
DMG3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
DMG3D_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
DMG3D_PutBgTile(1,1,160);
DMG3D_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_raster.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/dmg3d.h:53
WIRE3D_DMG_HEIGHT = 120. Write the raw DMG BGP palette encoding immediately; no frame synchronization occurs.
kitaqgb/lib/wire3d_dmg.c:597
void Wire3DDMG_SetPalette(w3ddmg_u8 bgp)
{
w3ddmg_reg_bgp = bgp;
}DMG3D_TransferAuxNow
立即上傳六個輔助條帶,並清除其來源位元組。
語法
void DMG3D_TransferAuxNow();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120. 不受輔助傳輸開關影響,立即上傳並消耗輔助來源條帶。不等待 VBlank 開始,也不更新 dirty 歷史或 BG 佇列。來源與主暫存區重疊,須協調與主區上傳的順序。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Upload a main line and an auxiliary block separately; verify source consumption.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom DMG3D_Vec3 vertices[2]={{-32,0,0},{32,0,0}};
__prg_rom u8 edge_pairs[2]={0,1};
u8* stage_byte;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
DMG3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
DMG3D_BeginFrame();
DMG3D_DrawIndexedEdges(vertices,2,edge_pairs,1,-64,104,96,1);
DMG3D_TransferMainNow();
// Direct auxiliary transfer writes a separate tile after the main upload.
for(i=24;i<=31;i++) DMG3D_DrawLine2D(40,i,47,i);
stage_byte=(u8*)0xD518;result[1]=*stage_byte;
DMG3D_TransferAuxNow();result[2]=*stage_byte;
// Do not upload the consumed stage again.
result[7]=0xA55A; while(1) {}
}預期結果
以投影水平線與輔助 8×8 區塊示範直接傳輸;來源位元組被消耗時由 255 變為 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_direct.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_direct.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/dmg3d.h:57
WIRE3D_DMG_HEIGHT = 120. Upload and consume auxiliary source strips immediately, independent of the auxiliary gate. No VBlank-start wait or dirty-history/BG-queue update occurs. The source overlaps the main stage and must be coordinated with its upload.
kitaqgb/lib/wire3d_dmg.c:3983
void Wire3DDMG_TransferAuxNow()
{
w3ddmg_transfer_stage_aux_asm();
}DMG3D_TransferMainNow
立即上傳整個主暫存區,並清除已消耗的來源像素。
語法
void DMG3D_TransferMainNow();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120. 立即上傳並消耗整個主暫存區,輪詢 STAT 但不等待下一次 VBlank。忽略傳輸開關,不改變 dirty 歷史或 BG 圖塊佇列;呼叫端須協調影格生命週期。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Upload a main line and an auxiliary block separately; verify source consumption.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom DMG3D_Vec3 vertices[2]={{-32,0,0},{32,0,0}};
__prg_rom u8 edge_pairs[2]={0,1};
u8* stage_byte;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
DMG3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
DMG3D_BeginFrame();
DMG3D_DrawIndexedEdges(vertices,2,edge_pairs,1,-64,104,96,1);
DMG3D_TransferMainNow();
// Direct auxiliary transfer writes a separate tile after the main upload.
for(i=24;i<=31;i++) DMG3D_DrawLine2D(40,i,47,i);
stage_byte=(u8*)0xD518;result[1]=*stage_byte;
DMG3D_TransferAuxNow();result[2]=*stage_byte;
// Do not upload the consumed stage again.
result[7]=0xA55A; while(1) {}
}預期結果
以投影水平線與輔助 8×8 區塊示範直接傳輸;來源位元組被消耗時由 255 變為 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_direct.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_direct.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/dmg3d.h:58
WIRE3D_DMG_HEIGHT = 120. Upload and consume the full main stage immediately, polling STAT but not waiting for the next VBlank. Ignore transfer gates and leave dirty histories and BG tile queue unchanged; the caller coordinates the frame lifecycle.
kitaqgb/lib/wire3d_dmg.c:3970
void Wire3DDMG_TransferMainNow()
{
w3ddmg_transfer_stage_asm();
}entity.h — 固定陣列物件池
entity 是以固定陣列管理敵人、子彈、道具等狀態的物件池。配置空閒槽位後,以 ID 存取;物件不再需要時,便可重複使用該槽位。它不會配置堆積記憶體。座標與速度的單位、移動、碰撞處理及計時器更新均由遊戲定義。
請包含 entity.h,並將 entity.c 編譯一次。先呼叫 entity_init,再確認 entity_create 未傳回 0xFF。ENTITY_MAX 預設為 16。ID 可支援 1~255 個槽位,但實際可配置數量取決於可用 RAM。所有編譯單元必須使用相同的容量定義。
entity_get 傳回的指標指向可重複使用的物件池儲存空間。釋放後,相同 ID 可能代表另一個物件,因此 ID 和指標都不是永久身分識別。entity_destroy 只會停用槽位。呼叫端必須自行隱藏或釋放精靈,並清理其他資源。sprite 欄位只記錄管理資訊,不會自動更新 OAM。
entity_update_all 與 entity_draw_all 依 ID 遞增順序巡訪啟用的槽位,並呼叫 fn(id)。實際更新或繪製工作請放在回呼中。回呼為 null 時不執行任何工作。在回呼內建立或釋放後面的槽位,會影響本次巡訪。先更新再繪製,可將兩項職責分開。
entity_clear_all
釋放所有實體,重設各欄位,包括未配置精靈的標記。
語法
void entity_clear_all();回傳值
無(void)。
使用條件與限制
池使用固定陣列,不進行堆積動態配置。ENTITY_MAX 預設為 16,範圍為 1~255,所有編譯單元必須使用相同定義。槽位 ID 從 0 開始,0xFF 專門表示失敗。
將所有槽位的 active,type,x,y,vx,vy,state,timer 清為 0,sprite 設為 0xFF。不會隱藏或釋放硬體精靈,繪圖資源需另外清理。
使用範例
entity_clear_all();
after_clear = entity_count_active();
if (after_clear != 0 || entity_get(reused) != 0) { failures++; }這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式用於理解可重用槽位的生命週期。請搭配標籤閱讀數字:配置兩個實體後為 CREATED 002,釋放第一個後為 AFTER FREE 001,重用最小空閒 ID 時為 REUSED ID 000,清空池後為 AFTER CLEAR 000。也會檢查釋放後的查詢為 null,以及重新配置後欄位已重設。FAILED CHECKS 000 表示這些檢查符合預期。
GB 走訪會對兩個使用中實體分別呼叫回呼,顯示 UPDATE CALLS 002、DRAW CALLS 002。範例更新回呼將兩者向右移動一個圖塊,繪圖回呼將代表兩個物件的 A 放在圖塊 (3,12)、B 放在 (7,12)。這些是回呼繪製的背景字型圖塊,並非自動配置的精靈。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\entity.c .\kitaq-docs\samples\api-examples\gb\entity_pool.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\entity_pool.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm實作與原始碼
kitaqgb/lib/entity.h:43
Release every entity and restore deterministic defaults, including the no-sprite sentinel.
kitaqgb/lib/entity.c:14
void entity_clear_all()
{
u8 i = 0;
while (i < ENTITY_MAX) {
entity_pool[i].active = 0;
entity_pool[i].type = 0;
entity_pool[i].x = 0;
entity_pool[i].y = 0;
entity_pool[i].vx = 0;
entity_pool[i].vy = 0;
entity_pool[i].state = 0;
entity_pool[i].timer = 0;
entity_pool[i].sprite = 0xFF;
i++;
}
}entity_count_active
回傳使用中的實體槽位數,不改變狀態。
語法
u8 entity_count_active();回傳值
active 位元組非零的槽位數,範圍為 0~ENTITY_MAX。表示占用數量,不是最大已配置 ID 或畫面上的精靈數量。
使用條件與限制
池使用固定陣列,不進行堆積動態配置。ENTITY_MAX 預設為 16,範圍為 1~255,所有編譯單元必須使用相同定義。槽位 ID 從 0 開始,0xFF 專門表示失敗。
使用範例
created = entity_count_active();
if (created != 2) { failures++; }這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式用於理解可重用槽位的生命週期。請搭配標籤閱讀數字:配置兩個實體後為 CREATED 002,釋放第一個後為 AFTER FREE 001,重用最小空閒 ID 時為 REUSED ID 000,清空池後為 AFTER CLEAR 000。也會檢查釋放後的查詢為 null,以及重新配置後欄位已重設。FAILED CHECKS 000 表示這些檢查符合預期。
GB 走訪會對兩個使用中實體分別呼叫回呼,顯示 UPDATE CALLS 002、DRAW CALLS 002。範例更新回呼將兩者向右移動一個圖塊,繪圖回呼將代表兩個物件的 A 放在圖塊 (3,12)、B 放在 (7,12)。這些是回呼繪製的背景字型圖塊,並非自動配置的精靈。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\entity.c .\kitaq-docs\samples\api-examples\gb\entity_pool.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\entity_pool.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm實作與原始碼
kitaqgb/lib/entity.h:41
Count occupied slots without changing entity state.
kitaqgb/lib/entity.c:93
u8 entity_count_active()
{
u8 i = 0;
u8 count = 0;
while (i < ENTITY_MAX) {
if (entity_pool[i].active != 0) count++;
i++;
}
return count;
}entity_create
依指定類型與位置配置實體,回傳可重用的 ID;沒有空位時回傳 0xFF。
語法
u8 entity_create(u8 type, s16 x, s16 y);參數
type由遊戲定義的類型編號,範圍 0~255。池僅儲存此值,不會據此選擇行為或繪圖函式。
x, y帶正負號的 16 位元座標(
-32768~32767)。像素或 Q8.8 等單位由遊戲決定;池不轉換單位、裁切位置或自動套用速度。
回傳值
回傳編號最小的空閒槽位 ID(0~ENTITY_MAX-1),無空位時回傳 0xFF。成功時設 active=1,儲存類型與位置,清零速度、狀態、計時器,並設 sprite=0xFF。
使用條件與限制
池使用固定陣列,不進行堆積動態配置。ENTITY_MAX 預設為 16,範圍為 1~255,所有編譯單元必須使用相同定義。槽位 ID 從 0 開始,0xFF 專門表示失敗。
使用範例
first = entity_create(1, 2, 12);
second = entity_create(2, 6, 12);
if (first == 0xFF || second == 0xFF) { failures++; }這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式用於理解可重用槽位的生命週期。請搭配標籤閱讀數字:配置兩個實體後為 CREATED 002,釋放第一個後為 AFTER FREE 001,重用最小空閒 ID 時為 REUSED ID 000,清空池後為 AFTER CLEAR 000。也會檢查釋放後的查詢為 null,以及重新配置後欄位已重設。FAILED CHECKS 000 表示這些檢查符合預期。
GB 走訪會對兩個使用中實體分別呼叫回呼,顯示 UPDATE CALLS 002、DRAW CALLS 002。範例更新回呼將兩者向右移動一個圖塊,繪圖回呼將代表兩個物件的 A 放在圖塊 (3,12)、B 放在 (7,12)。這些是回呼繪製的背景字型圖塊,並非自動配置的精靈。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\entity.c .\kitaq-docs\samples\api-examples\gb\entity_pool.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\entity_pool.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm實作與原始碼
kitaqgb/lib/entity.h:29
Returns a reusable slot ID, or 0xFF if no slot is free.
kitaqgb/lib/entity.c:33
u8 entity_create(u8 type, s16 x, s16 y)
{
u8 i = 0;
while (i < ENTITY_MAX) {
if (entity_pool[i].active == 0) {
entity_pool[i].active = 1;
entity_pool[i].type = type;
entity_pool[i].x = x;
entity_pool[i].y = y;
entity_pool[i].vx = 0;
entity_pool[i].vy = 0;
entity_pool[i].state = 0;
entity_pool[i].timer = 0;
entity_pool[i].sprite = 0xFF;
return i;
}
i++;
}
return 0xFF;
}entity_destroy
釋放 id 對應的實體槽位;保留的資料會在重新配置時初始化。
語法
void entity_destroy(u8 id);參數
id可重用的槽位索引,範圍為 0~
ENTITY_MAX-1。範圍外 ID 無效;釋放無效 ID 不產生效果,查詢則回傳 null。
回傳值
無(void)。
使用條件與限制
池使用固定陣列,不進行堆積動態配置。ENTITY_MAX 預設為 16,範圍為 1~255,所有編譯單元必須使用相同定義。槽位 ID 從 0 開始,0xFF 專門表示失敗。
釋放操作僅將 active 清為 0,不清除其他欄位,也不釋放精靈或素材。之後可能將相同 ID 與位址重用於另一實體。關聯資源由遊戲負責清理。
使用範例
entity_destroy(first);
after_free = entity_count_active();
if (entity_get(first) != 0 || after_free != 1) { failures++; }這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式用於理解可重用槽位的生命週期。請搭配標籤閱讀數字:配置兩個實體後為 CREATED 002,釋放第一個後為 AFTER FREE 001,重用最小空閒 ID 時為 REUSED ID 000,清空池後為 AFTER CLEAR 000。也會檢查釋放後的查詢為 null,以及重新配置後欄位已重設。FAILED CHECKS 000 表示這些檢查符合預期。
GB 走訪會對兩個使用中實體分別呼叫回呼,顯示 UPDATE CALLS 002、DRAW CALLS 002。範例更新回呼將兩者向右移動一個圖塊,繪圖回呼將代表兩個物件的 A 放在圖塊 (3,12)、B 放在 (7,12)。這些是回呼繪製的背景字型圖塊,並非自動配置的精靈。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\entity.c .\kitaq-docs\samples\api-examples\gb\entity_pool.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\entity_pool.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm實作與原始碼
kitaqgb/lib/entity.h:32
Release a valid slot without clearing its payload. Reallocation resets the payload; a saved pointer or ID must not be treated as a persistent entity identity.
kitaqgb/lib/entity.c:56
void entity_destroy(u8 id)
{
if (id >= ENTITY_MAX) return;
// Deactivation only releases this pool slot; the caller handles sprite/resource cleanup.
entity_pool[id].active = 0;
}entity_draw_all
走訪使用中實體,將每個 ID 傳給繪圖回呼。走訪方式與 entity_update_all 相同;只有回呼提交繪圖資料時,才會繪製精靈或像素。
語法
void entity_draw_all(EntityFn fn);參數
fn簽章為
void fn(u8 id)的函式指標。接收槽位 ID,可用entity_get(id)存取欄位。允許 null,此時不呼叫。
回傳值
無(void)。
使用條件與限制
池使用固定陣列,不進行堆積動態配置。ENTITY_MAX 預設為 16,範圍為 1~255,所有編譯單元必須使用相同定義。槽位 ID 從 0 開始,0xFF 專門表示失敗。
走訪到槽位時才檢查其使用狀態。回呼可停用後面的槽位使其被略過,也可啟用後面的槽位使其在本輪被走訪。並非走訪開始時使用中集合的快照。
使用範例
void demo_draw(u8 id) {
Entity* entity;
entity = entity_get(id);
if (entity != 0) {
m_put((u8)entity->x, (u8)entity->y, (u8)('A' + entity->type - 1));
draw_calls++;
}
}
// From main(), after creating two entities:
draw_calls = 0;
entity_draw_all(demo_draw);
automatic_draws = draw_calls;
if (automatic_draws != 2) { failures++; }這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式用於理解可重用槽位的生命週期。請搭配標籤閱讀數字:配置兩個實體後為 CREATED 002,釋放第一個後為 AFTER FREE 001,重用最小空閒 ID 時為 REUSED ID 000,清空池後為 AFTER CLEAR 000。也會檢查釋放後的查詢為 null,以及重新配置後欄位已重設。FAILED CHECKS 000 表示這些檢查符合預期。
GB 走訪會對兩個使用中實體分別呼叫回呼,顯示 UPDATE CALLS 002、DRAW CALLS 002。範例更新回呼將兩者向右移動一個圖塊,繪圖回呼將代表兩個物件的 A 放在圖塊 (3,12)、B 放在 (7,12)。這些是回呼繪製的背景字型圖塊,並非自動配置的精靈。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\entity.c .\kitaq-docs\samples\api-examples\gb\entity_pool.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\entity_pool.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm實作與原始碼
kitaqgb/lib/entity.h:39
Use the same active-slot traversal for drawing; the callback supplies all rendering.
kitaqgb/lib/entity.c:87
void entity_draw_all(EntityFn fn)
{
entity_update_all(fn);
}entity_get
回傳有效使用中實體的指標;ID 無效或未使用時回傳 null。池內空間可能再次配置。
語法
Entity* entity_get(u8 id);參數
id可重用的槽位索引,範圍為 0~
ENTITY_MAX-1。範圍外 ID 無效;釋放無效 ID 不產生效果,查詢則回傳 null。
回傳值
回傳可寫入的使用中槽位指標;ID 無效或未使用時回傳 null。記憶體由池擁有,請勿自行釋放,也不要將指標當作跨越刪除與重新配置的永久身分。
使用條件與限制
池使用固定陣列,不進行堆積動態配置。ENTITY_MAX 預設為 16,範圍為 1~255,所有編譯單元必須使用相同定義。槽位 ID 從 0 開始,0xFF 專門表示失敗。
釋放操作僅將 active 清為 0,不清除其他欄位,也不釋放精靈或素材。之後可能將相同 ID 與位址重用於另一實體。關聯資源由遊戲負責清理。
使用範例
current_entity = entity_get(first);
if (current_entity != 0) { current_entity->vx = 5; }
else { failures++; }這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式用於理解可重用槽位的生命週期。請搭配標籤閱讀數字:配置兩個實體後為 CREATED 002,釋放第一個後為 AFTER FREE 001,重用最小空閒 ID 時為 REUSED ID 000,清空池後為 AFTER CLEAR 000。也會檢查釋放後的查詢為 null,以及重新配置後欄位已重設。FAILED CHECKS 000 表示這些檢查符合預期。
GB 走訪會對兩個使用中實體分別呼叫回呼,顯示 UPDATE CALLS 002、DRAW CALLS 002。範例更新回呼將兩者向右移動一個圖塊,繪圖回呼將代表兩個物件的 A 放在圖塊 (3,12)、B 放在 (7,12)。這些是回呼繪製的背景字型圖塊,並非自動配置的精靈。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\entity.c .\kitaq-docs\samples\api-examples\gb\entity_pool.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\entity_pool.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm實作與原始碼
kitaqgb/lib/entity.h:34
Returns null for an invalid or inactive ID; the returned pointer aliases reusable pool storage.
kitaqgb/lib/entity.c:65
Entity* entity_get(u8 id)
{
if (id >= ENTITY_MAX) return 0;
if (entity_pool[id].active == 0) return 0;
return &entity_pool[(__safe_index u8)id];
}entity_init
初始化實體池的所有槽位。
語法
void entity_init();回傳值
無(void)。
使用條件與限制
池使用固定陣列,不進行堆積動態配置。ENTITY_MAX 預設為 16,範圍為 1~255,所有編譯單元必須使用相同定義。槽位 ID 從 0 開始,0xFF 專門表示失敗。
將所有槽位的 active,type,x,y,vx,vy,state,timer 清為 0,sprite 設為 0xFF。不會隱藏或釋放硬體精靈,繪圖資源需另外清理。
使用範例
entity_init();
if (entity_count_active() != 0) { failures++; }這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式用於理解可重用槽位的生命週期。請搭配標籤閱讀數字:配置兩個實體後為 CREATED 002,釋放第一個後為 AFTER FREE 001,重用最小空閒 ID 時為 REUSED ID 000,清空池後為 AFTER CLEAR 000。也會檢查釋放後的查詢為 null,以及重新配置後欄位已重設。FAILED CHECKS 000 表示這些檢查符合預期。
GB 走訪會對兩個使用中實體分別呼叫回呼,顯示 UPDATE CALLS 002、DRAW CALLS 002。範例更新回呼將兩者向右移動一個圖塊,繪圖回呼將代表兩個物件的 A 放在圖塊 (3,12)、B 放在 (7,12)。這些是回呼繪製的背景字型圖塊,並非自動配置的精靈。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\entity.c .\kitaq-docs\samples\api-examples\gb\entity_pool.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\entity_pool.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm實作與原始碼
kitaqgb/lib/entity.h:27
Reset every slot before the game starts using the pool.
kitaqgb/lib/entity.c:8
void entity_init()
{
entity_clear_all();
}entity_update_all
依 ID 遞增順序走訪使用中槽位,對每個呼叫一次 fn(id)。移動、碰撞或計時器邏輯由回呼實作,池本身不提供這些邏輯。回呼為 null 時不執行任何操作。
語法
void entity_update_all(EntityFn fn);參數
fn簽章為
void fn(u8 id)的函式指標。接收槽位 ID,可用entity_get(id)存取欄位。允許 null,此時不呼叫。
回傳值
無(void)。
使用條件與限制
池使用固定陣列,不進行堆積動態配置。ENTITY_MAX 預設為 16,範圍為 1~255,所有編譯單元必須使用相同定義。槽位 ID 從 0 開始,0xFF 專門表示失敗。
走訪到槽位時才檢查其使用狀態。回呼可停用後面的槽位使其被略過,也可啟用後面的槽位使其在本輪被走訪。並非走訪開始時使用中集合的快照。
使用範例
void demo_update(u8 id) {
Entity* entity;
entity = entity_get(id);
if (entity != 0) { entity->x = entity->x + 1; update_calls++; }
}
// From main(), after creating two entities:
update_calls = 0;
entity_update_all(demo_update);
automatic_updates = update_calls;
if (automatic_updates != 2) { failures++; }這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式用於理解可重用槽位的生命週期。請搭配標籤閱讀數字:配置兩個實體後為 CREATED 002,釋放第一個後為 AFTER FREE 001,重用最小空閒 ID 時為 REUSED ID 000,清空池後為 AFTER CLEAR 000。也會檢查釋放後的查詢為 null,以及重新配置後欄位已重設。FAILED CHECKS 000 表示這些檢查符合預期。
GB 走訪會對兩個使用中實體分別呼叫回呼,顯示 UPDATE CALLS 002、DRAW CALLS 002。範例更新回呼將兩者向右移動一個圖塊,繪圖回呼將代表兩個物件的 A 放在圖塊 (3,12)、B 放在 (7,12)。這些是回呼繪製的背景字型圖塊,並非自動配置的精靈。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\entity.c .\kitaq-docs\samples\api-examples\gb\entity_pool.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\entity_pool.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm實作與原始碼
kitaqgb/lib/entity.h:37
Call fn for each slot that is active when the scan reaches it; null is a no-op. Callbacks may change the pool, so newly activated later slots can run in this pass.
kitaqgb/lib/entity.c:74
void entity_update_all(EntityFn fn)
{
u8 i = 0;
if (fn == 0) return;
while (i < ENTITY_MAX) {
if (entity_pool[i].active != 0) {
fn(i);
}
i++;
}
}fixed.h — Q8.8 定點運算與矩形
Q8.8 運算以整數表示含小數的座標與速度,並提供矩形及點的碰撞測試。請確認各項運算的精度與範圍限制。
fix_div
降低運算元精度後執行 Q8.8 除法。
語法
fix8 fix_div(fix8 a, fix8 b);參數
aQ8.8 格式的左運算元。
bQ8.8 格式的右運算元。
回傳值
傳回 Q8.8 商;b == 0 時傳回零。
使用條件與限制
運算式為 ((a >> 4) * 256) / (b >> 4)。非零除數在位移後仍須非零,因此不可傳入原始值 1~15 的正數。放大後的分子也必須能以 16 位元表示。
使用範例
result[3]=fix_div(768,512);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
3.0 除以 2.0 得到 1.5(原始值 384)。另有檢查確認除數恰為零時的明確傳回行為。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_math.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_math.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/fixed.h:32
Scale the reduced-precision quotient back to 8.8 and return zero for b == 0. Callers must also ensure (b >> 4) is nonzero; the explicit check only tests b. The intermediate product must fit the compiler's integer arithmetic.
kitaqgb/lib/fixed.c:26
fix8 fix_div(fix8 a, fix8 b)
{
if (b == 0) return 0;
return (fix8)(((a >> 4) * 256) / (b >> 4));
}fix_from_int
將整數座標或速度轉換為 Q8.8,讓後續運算保留小數部分。
語法
fix8 fix_from_int(s16 n);參數
n要轉換的整數,範圍為 −128~127。
回傳值
傳回原始值 n × 256。
使用條件與限制
fix8 是帶正負號的 Q8.8 格式,原始值 256 代表 1.0。中間值與結果都必須維持在 16 位元範圍內。
使用範例
result[0]=fix_from_int(-3);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例轉換 −3。畫面上的 −00768 表示 Q8.8 的原始結果 −768。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_math.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_math.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/fixed.h:23
Convert an integer to signed 8.8 fixed point by moving it into the high byte. The caller must keep the result within the representable 16-bit range.
kitaqgb/lib/fixed.c:5
fix8 fix_from_int(s16 n)
{
return (fix8)(n << 8);
}fix_lerp
使用八位元權重,從一個 Q8.8 值朝另一個值進行內插。
語法
fix8 fix_lerp(fix8 a, fix8 b, u8 t_q8);參數
aQ8.8 格式的左運算元。
bQ8.8 格式的右運算元。
t_q8內插權重,範圍為 0~255。
回傳值
傳回近似內插所得的 Q8.8 值。
使用條件與限制
差值與權重各向右移四位,因此權重只有 16 個等級,即使指定 255 也不一定能到達終點。b - a 與最終結果均須保持在 16 位元範圍內。
使用範例
result[4]=fix_lerp(0,1024,128);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
在 0 與 4.0 之間使用權重 128,得到 2.0(原始值 512)。權重 255 則得到 3.75(原始值 960),顯示結果未到達終點。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_math.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_math.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/fixed.h:35
Interpolate toward b using a quantized Q0.8 weight. Both shifts discard low bits, so small changes may vanish and a weight of 255 need not reach b.
kitaqgb/lib/fixed.c:34
fix8 fix_lerp(fix8 a, fix8 b, u8 t_q8)
{
// The endpoint difference must fit s16 before the reduced-precision multiplication.
fix8 d = (fix8)(b - a);
return (fix8)(a + (fix8)((d >> 4) * (s16)(t_q8 >> 4)));
}fix_mul
以運算成本較低的近似方法將兩個 Q8.8 值相乘。
語法
fix8 fix_mul(fix8 a, fix8 b);參數
aQ8.8 格式的左運算元。
bQ8.8 格式的右運算元。
回傳值
以 Q8.8 格式傳回乘積。
使用條件與限制
相乘前會將兩個運算元各向右移四位,捨去各自的低四位元,因此精確度低於完整的 16×16 位元乘法。fix8 是帶正負號的 Q8.8,原始值 256 代表 1.0。中間值與結果都須保持在 16 位元範圍內。
使用範例
result[2]=fix_mul(384,512);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
1.5 乘以 2.0 得到 3.0(原始值 768)。程式也檢查量化情況:原始值 271 乘以原始值 271,結果為 256。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_math.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_math.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/fixed.h:28
Approximate 8.8 multiplication by discarding four low bits from each operand before multiplying. This trades precision for a smaller intermediate product.
kitaqgb/lib/fixed.c:18
fix8 fix_mul(fix8 a, fix8 b)
{
return (fix8)((a >> 4) * (b >> 4));
}fix_to_int
捨去 Q8.8 的小數位元以取得整數座標。負數會朝負無限大方向取整。
語法
s16 fix_to_int(fix8 x);參數
x要轉換為整數的 Q8.8 值。
回傳值
傳回帶正負號的整數。
使用條件與限制
fix8 是帶正負號的 Q8.8 格式,原始值 256 代表 1.0。中間值與結果都必須維持在 16 位元範圍內。
使用範例
result[1]=fix_to_int(-384);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
傳入原始值 −384(−1.5)會得到 −2,顯示為 −00002。邊界檢查也確認原始值 −1 會轉換為 −1。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_math.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_math.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/fixed.h:25
Discard the eight fractional bits using a signed right shift.
kitaqgb/lib/fixed.c:11
s16 fix_to_int(fix8 x)
{
return (s16)(x >> 8);
}kq_abs_s16
求帶正負號之 16 位元值的絕對值。
語法
s16 kq_abs_s16(s16 v);參數
v要求絕對值的帶正負號 16 位元值。
回傳值
傳回非負的絕對值,但 −32768 的絕對值無法以此型別表示。
使用條件與限制
正值 32768 無法存入 s16。若要求結果必須非負,請排除輸入 −32768。
使用範例
result[0]=kq_abs_s16(-123);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例將 −123 轉為 123,可用於求座標差的大小。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_math_limits.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_math_limits.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/fixed.h:38
Return the magnitude in s16. The most-negative s16 has no positive s16 representation and must be excluded by callers needing a nonnegative result.
kitaqgb/lib/fixed.c:43
s16 kq_abs_s16(s16 v)
{
if (v < 0) return (s16)(0 - v);
return v;
}kq_clamp_s16
將座標或速度限制在包含兩端的區間內。
語法
s16 kq_clamp_s16(s16 v, s16 lo, s16 hi);參數
v要限制範圍的帶正負號值。
lo下限,包含此值。
hi上限,包含此值。
回傳值
低於區間時傳回 lo,高於區間時傳回 hi,位於區間內則傳回 v。
使用條件與限制
請提供符合 lo <= hi 的有效區間。
使用範例
result[3]=kq_clamp_s16(25,-10,10);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
將 25 限制在 −10~10 之間會得到 10。檢查也涵蓋下限外的 −11→−10,以及區間內的 3→3。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_math_limits.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_math_limits.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/fixed.h:44
Clamp to an inclusive interval; callers must provide lo <= hi.
kitaqgb/lib/fixed.c:64
s16 kq_clamp_s16(s16 v, s16 lo, s16 hi)
{
if (v < lo) return lo;
if (v > hi) return hi;
return v;
}kq_max_s16
選取兩個帶正負號 16 位元值中較大者。
語法
s16 kq_max_s16(s16 a, s16 b);參數
a第一個要比較的帶正負號值。
b第二個要比較的帶正負號值。
回傳值
傳回選取的運算元。
使用條件與限制
比較時會考慮正負號。兩個運算元相等時傳回該值;兩個輸入都不會被修改。
使用範例
result[2]=kq_max_s16(-7,4);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
比較 −7 與 4 得到 4。負數結果會顯示負號。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_math_limits.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_math_limits.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/fixed.h:42
Select the larger signed value.
kitaqgb/lib/fixed.c:57
s16 kq_max_s16(s16 a, s16 b)
{
if (a > b) return a;
return b;
}kq_min_s16
選取兩個帶正負號 16 位元值中較小者。
語法
s16 kq_min_s16(s16 a, s16 b);參數
a第一個要比較的帶正負號值。
b第二個要比較的帶正負號值。
回傳值
傳回選取的運算元。
使用條件與限制
比較時會考慮正負號。兩個運算元相等時傳回該值;兩個輸入都不會被修改。
使用範例
result[1]=kq_min_s16(-7,4);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
比較 −7 與 4 得到 -7。負數結果會顯示負號。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_math_limits.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_math_limits.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/fixed.h:40
Select the smaller signed value.
kitaqgb/lib/fixed.c:50
s16 kq_min_s16(s16 a, s16 b)
{
if (a < b) return a;
return b;
}kq_point_in_rect
檢查點是否位於矩形內,包含左邊界與上邊界。
語法
u8 kq_point_in_rect(s16 x, s16 y, KQRect r);參數
x點的 X 座標,使用矩形的座標系。
y點的 Y 座標。
r要檢查的矩形,以值傳遞。
回傳值
位於內部時傳回 1,外部時傳回 0。
使用條件與限制
尺寸必須為正,座標加尺寸的結果須能以 s16 表示。右邊界與下邊界不包含在內。函式不會明確拒絕面積為零的矩形。
使用範例
result[1]=kq_point_in_rect(9,1,a);
for(gy=0;gy<11;gy++){for(gx=0;gx<15;gx++){
inside_a=kq_point_in_rect(gx,gy,a);inside_b=kq_point_in_rect(gx,gy,b);
tile=0;if(inside_a){tile=65;result[3]=result[3]+1;}if(inside_b)tile=66;if(inside_a && inside_b){tile=79;result[4]=result[4]+1;}
m_put(1+gx,2+gy,tile);if(tile!=0)vram_example_color(1+gx,2+gy,1,1,tile==65?1:(tile==66?2:3));
}}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
每個座標單位佔一個圖塊。矩形 A 位於 (1,1),B 位於 (5,4),兩者大小皆為 8×6。僅屬於 A 的格子顯示 A,僅屬於 B 的格子顯示 B;4×3 的重疊區域顯示 12 個 O。A 的右邊界 x=9 不包含在內。CGB 上的 A 為紅色、B 為藍色、O 為綠色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_geometry.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_geometry.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/fixed.h:51
Test a half-open rectangle: left/top edges are included, right/bottom excluded. The coordinate-plus-size sums must remain representable as s16.
kitaqgb/lib/fixed.c:85
u8 kq_point_in_rect(s16 x, s16 y, KQRect r)
{
if (x < r.x) return 0;
if (y < r.y) return 0;
if (x >= (s16)(r.x + r.w)) return 0;
if (y >= (s16)(r.y + r.h)) return 0;
return 1;
}kq_rect_intersect
檢查兩個與座標軸對齊的矩形是否具有面積大於零的重疊區域。
語法
u8 kq_rect_intersect(KQRect a, KQRect b);參數
a以值傳遞的第一個矩形:
x, y為左上角位置,w, h為寬度與高度。b與 A 使用相同座標系的第二個矩形。
回傳值
重疊時傳回 1;分離或僅邊緣接觸時傳回 0。
使用條件與限制
尺寸必須為正,座標加尺寸的結果須能以 s16 表示。右邊界與下邊界不包含在內。函式不會明確拒絕面積為零的矩形。
使用範例
result[0]=kq_rect_intersect(a,b);result[2]=kq_rect_intersect(a,touch);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
每個座標單位佔一個圖塊。矩形 A 位於 (1,1),B 位於 (5,4),兩者大小皆為 8×6。僅屬於 A 的格子顯示 A,僅屬於 B 的格子顯示 B;4×3 的重疊區域顯示 12 個 O。A 的右邊界 x=9 不包含在內。CGB 上的 A 為紅色、B 為藍色、O 為綠色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_geometry.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_geometry.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/fixed.h:48
Test overlap using exclusive right/bottom edges; touching edges do not collide. Require positive dimensions and edge sums that fit s16; zero-sized rectangles are not explicitly rejected and may be reported as overlapping.
kitaqgb/lib/fixed.c:74
u8 kq_rect_intersect(KQRect a, KQRect b)
{
if ((s16)(a.x + a.w) <= b.x) return 0;
if ((s16)(b.x + b.w) <= a.x) return 0;
if ((s16)(a.y + a.h) <= b.y) return 0;
if ((s16)(b.y + b.h) <= a.y) return 0;
return 1;
}input.h — 按鈕狀態、按下、放開及重複
連續移動用 input_down,單次動作用 input_pressed,放開時停止用 input_released,選單重複操作用 input_repeat。初始化一次,每個輸入週期更新一次,再依需求查詢。btn_down、btn_pressed、btn_released、btn_repeat 分別是這四個查詢函式的別名。
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
重複觸發以更新次數計時,不是毫秒。新按下時立即觸發。預設 INPUT_REPEAT_DELAY=18、INPUT_REPEAT_RATE=5 時,19 次更新後再次觸發,之後每 6 次更新觸發一次。各按鈕獨立計數。修改設定時,編譯 input.c 也必須使用相同巨集值;只修改呼叫端的標頭檔不會改變函式庫設定。
btn_down
btn_down 是 input_down 的別名,檢查所選按鈕是否至少有一個目前被按住。
判斷 mask 選取的按鈕是否至少有一個正被按住。
語法
u8 btn_down(u8 mask);參數
mask一個
BTN_*遮罩,或以|組合的多個遮罩。任一選中按鈕符合條件即為真;BTN_A | BTN_B不要求同時按住兩個按鈕。遮罩 0 一律回傳 0。若要檢查全部按鈕均按住,使用(input_current() & mask) == mask。
回傳值
任一選中按鈕符合查詢條件時回傳 1,否則回傳 0。回傳值不是按鈕位元遮罩。
使用條件與限制
標頭定義會展開為實作名稱的物件式巨集。引數、傳回值與狀態存取均與目標相同;別名不增加獨立狀態或處理。請依完整範例與建置命令,輸入使用 input.h/input.c,影格服務使用 system.h/system.c。
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
查詢函式只讀取最近一次 input_update() 保存的狀態,不重新讀取控制器、不消耗事件,也不推進重複計時器。同一輸入週期內重複查詢結果相同。按鈕持續按住時若呼叫兩次 input_update(),第二次會清除新按下事件。
使用範例
if (btn_down(BTN_A)!=0) held_ticks++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範持續按住、剛按下、剛放開與自動連發的差別。按住A達40次更新後放開。FIRST DOWN、FIRST PRESS、FIRST REPEAT為1,FIRST CURRENT為16。HELD TICKS為40,PRESS COUNT為1,REPEAT COUNT為5。放開後,RELEASE為1,LAST CURRENT為0,LAST PREVIOUS為16。FAILED CHECKS應為0。改變按住的時間會改變計數;程式會根據實際觀測到的時間檢查連發間隔。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\input.c .\kitaq-docs\samples\api-examples\gb\input_aliases.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\input_aliases.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm --no-cache實作與原始碼
kitaqgb/lib/input.h:48
#define btn_down input_downkitaqgb/lib/input.c:68
u8 input_down(u8 mask)
{
return (u8)((kq_input_keys & mask) != 0);
}btn_pressed
btn_pressed 是 input_pressed 的別名,檢查最近一次輸入更新時,所選按鈕是否至少有一個剛被按下。
判斷最近一次輸入更新中,遮罩選取的按鈕是否從放開變成按下。
語法
u8 btn_pressed(u8 mask);參數
mask一個
BTN_*遮罩,或以|組合的多個遮罩。任一選中按鈕符合條件即為真;BTN_A | BTN_B不要求同時按住兩個按鈕。遮罩 0 一律回傳 0。若要檢查全部按鈕均按住,使用(input_current() & mask) == mask。
回傳值
任一選中按鈕符合查詢條件時回傳 1,否則回傳 0。回傳值不是按鈕位元遮罩。
使用條件與限制
標頭定義會展開為實作名稱的物件式巨集。引數、傳回值與狀態存取均與目標相同;別名不增加獨立狀態或處理。請依完整範例與建置命令,輸入使用 input.h/input.c,影格服務使用 system.h/system.c。
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
查詢函式只讀取最近一次 input_update() 保存的狀態,不重新讀取控制器、不消耗事件,也不推進重複計時器。同一輸入週期內重複查詢結果相同。按鈕持續按住時若呼叫兩次 input_update(),第二次會清除新按下事件。
使用範例
if (btn_pressed(BTN_A)!=0) {
press_count++; seen_press=1;
first_down=btn_down(BTN_A); first_press=btn_pressed(BTN_A);
first_repeat=btn_repeat(BTN_A);
first_current=input_current(); // Only A held: BTN_A, or decimal 16.
first_previous=input_previous(); // No buttons in the preceding sample: 0.
if (first_down!=1 || first_press!=1 || first_repeat!=1) failures++;
if (first_current!=BTN_A || first_previous!=0) failures++;
if (btn_down(BTN_A|BTN_B)!=1 || btn_down(0)!=0) failures++;
}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範持續按住、剛按下、剛放開與自動連發的差別。按住A達40次更新後放開。FIRST DOWN、FIRST PRESS、FIRST REPEAT為1,FIRST CURRENT為16。HELD TICKS為40,PRESS COUNT為1,REPEAT COUNT為5。放開後,RELEASE為1,LAST CURRENT為0,LAST PREVIOUS為16。FAILED CHECKS應為0。改變按住的時間會改變計數;程式會根據實際觀測到的時間檢查連發間隔。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\input.c .\kitaq-docs\samples\api-examples\gb\input_aliases.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\input_aliases.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm --no-cache實作與原始碼
kitaqgb/lib/input.h:49
#define btn_pressed input_pressedkitaqgb/lib/input.c:74
u8 input_pressed(u8 mask)
{
return (u8)((kq_input_press_keys & mask) != 0);
}btn_released
btn_released 是 input_released 的別名,檢查最近一次輸入更新時,所選按鈕是否至少有一個被放開。
判斷最近一次輸入更新中,遮罩選取的按鈕是否從按下變成放開。
語法
u8 btn_released(u8 mask);參數
mask一個
BTN_*遮罩,或以|組合的多個遮罩。任一選中按鈕符合條件即為真;BTN_A | BTN_B不要求同時按住兩個按鈕。遮罩 0 一律回傳 0。若要檢查全部按鈕均按住,使用(input_current() & mask) == mask。
回傳值
任一選中按鈕符合查詢條件時回傳 1,否則回傳 0。回傳值不是按鈕位元遮罩。
使用條件與限制
標頭定義會展開為實作名稱的物件式巨集。引數、傳回值與狀態存取均與目標相同;別名不增加獨立狀態或處理。請依完整範例與建置命令,輸入使用 input.h/input.c,影格服務使用 system.h/system.c。
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
查詢函式只讀取最近一次 input_update() 保存的狀態,不重新讀取控制器、不消耗事件,也不推進重複計時器。同一輸入週期內重複查詢結果相同。按鈕持續按住時若呼叫兩次 input_update(),第二次會清除新按下事件。
使用範例
if (btn_released(BTN_A)!=0) {
release_result=btn_released(BTN_A);
last_current=input_current(); last_previous=input_previous();
if (btn_down(BTN_A)!=0 || btn_pressed(BTN_A)!=0 || btn_repeat(BTN_A)!=0) failures++;
break;
}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範持續按住、剛按下、剛放開與自動連發的差別。按住A達40次更新後放開。FIRST DOWN、FIRST PRESS、FIRST REPEAT為1,FIRST CURRENT為16。HELD TICKS為40,PRESS COUNT為1,REPEAT COUNT為5。放開後,RELEASE為1,LAST CURRENT為0,LAST PREVIOUS為16。FAILED CHECKS應為0。改變按住的時間會改變計數;程式會根據實際觀測到的時間檢查連發間隔。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\input.c .\kitaq-docs\samples\api-examples\gb\input_aliases.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\input_aliases.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm --no-cache實作與原始碼
kitaqgb/lib/input.h:50
#define btn_released input_releasedkitaqgb/lib/input.c:80
u8 input_released(u8 mask)
{
return (u8)((kq_input_release_keys & mask) != 0);
}btn_repeat
btn_repeat 是 input_repeat 的別名,檢查首次按下,或持續按住期間按排程發出的重複訊號。
判斷遮罩選取的按鈕是否產生首次按下或定時重複輸入。
語法
u8 btn_repeat(u8 mask);參數
mask一個
BTN_*遮罩,或以|組合的多個遮罩。任一選中按鈕符合條件即為真;BTN_A | BTN_B不要求同時按住兩個按鈕。遮罩 0 一律回傳 0。若要檢查全部按鈕均按住,使用(input_current() & mask) == mask。
回傳值
任一選中按鈕符合查詢條件時回傳 1,否則回傳 0。回傳值不是按鈕位元遮罩。
使用條件與限制
標頭定義會展開為實作名稱的物件式巨集。引數、傳回值與狀態存取均與目標相同;別名不增加獨立狀態或處理。請依完整範例與建置命令,輸入使用 input.h/input.c,影格服務使用 system.h/system.c。
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
查詢函式只讀取最近一次 input_update() 保存的狀態,不重新讀取控制器、不消耗事件,也不推進重複計時器。同一輸入週期內重複查詢結果相同。按鈕持續按住時若呼叫兩次 input_update(),第二次會清除新按下事件。
重複觸發以更新次數計時,不是毫秒。新按下時立即觸發。預設 INPUT_REPEAT_DELAY=18、INPUT_REPEAT_RATE=5 時,19 次更新後再次觸發,之後每 6 次更新觸發一次。各按鈕獨立計數。修改設定時,編譯 input.c 也必須使用相同巨集值;只修改呼叫端的標頭檔不會改變函式庫設定。
使用範例
if (btn_repeat(BTN_A)!=0) {
// The initial press is pulse 1. Defaults then wait 19 updates, followed by 6.
if (repeat_count==1 && held_ticks-previous_pulse!=19) failures++;
if (repeat_count>1 && held_ticks-previous_pulse!=6) failures++;
previous_pulse=held_ticks; repeat_count++;
if (btn_repeat(BTN_A)!=1) failures++; // Reading again does not consume it.
}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範持續按住、剛按下、剛放開與自動連發的差別。按住A達40次更新後放開。FIRST DOWN、FIRST PRESS、FIRST REPEAT為1,FIRST CURRENT為16。HELD TICKS為40,PRESS COUNT為1,REPEAT COUNT為5。放開後,RELEASE為1,LAST CURRENT為0,LAST PREVIOUS為16。FAILED CHECKS應為0。改變按住的時間會改變計數;程式會根據實際觀測到的時間檢查連發間隔。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\input.c .\kitaq-docs\samples\api-examples\gb\input_aliases.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\input_aliases.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm --no-cache實作與原始碼
kitaqgb/lib/input.h:51
#define btn_repeat input_repeatkitaqgb/lib/input.c:86
u8 input_repeat(u8 mask)
{
return (u8)((kq_input_repeat_keys & mask) != 0);
}input_current
回傳最近一次輸入更新取得的全部按住按鈕位元遮罩。
語法
u8 input_current();回傳值
共用 BTN_* 格式的 8 位元遮罩。多個按鈕可以同時設為 1;0 表示沒有按鈕。
使用條件與限制
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
查詢函式只讀取最近一次 input_update() 保存的狀態,不重新讀取控制器、不消耗事件,也不推進重複計時器。同一輸入週期內重複查詢結果相同。按鈕持續按住時若呼叫兩次 input_update(),第二次會清除新按下事件。
使用範例
first_current=input_current(); // Only A held: BTN_A, or decimal 16.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範持續按住、剛按下、剛放開與自動連發的差別。按住A達40次更新後放開。FIRST DOWN、FIRST PRESS、FIRST REPEAT為1,FIRST CURRENT為16。HELD TICKS為40,PRESS COUNT為1,REPEAT COUNT為5。放開後,RELEASE為1,LAST CURRENT為0,LAST PREVIOUS為16。FAILED CHECKS應為0。改變按住的時間會改變計數;程式會根據實際觀測到的時間檢查連發間隔。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\input.c .\kitaq-docs\samples\api-examples\gb\input_edges.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\input_edges.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm --no-cache實作與原始碼
kitaqgb/lib/input.h:44
Return the complete held-button mask from the latest update.
kitaqgb/lib/input.c:92
u8 input_current()
{
return kq_input_keys;
}input_down
判斷 mask 選取的按鈕是否至少有一個正被按住。
語法
u8 input_down(u8 mask);參數
mask一個
BTN_*遮罩,或以|組合的多個遮罩。任一選中按鈕符合條件即為真;BTN_A | BTN_B不要求同時按住兩個按鈕。遮罩 0 一律回傳 0。若要檢查全部按鈕均按住,使用(input_current() & mask) == mask。
回傳值
任一選中按鈕符合查詢條件時回傳 1,否則回傳 0。回傳值不是按鈕位元遮罩。
使用條件與限制
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
查詢函式只讀取最近一次 input_update() 保存的狀態,不重新讀取控制器、不消耗事件,也不推進重複計時器。同一輸入週期內重複查詢結果相同。按鈕持續按住時若呼叫兩次 input_update(),第二次會清除新按下事件。
使用範例
if (input_down(BTN_A)!=0) held_ticks++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範持續按住、剛按下、剛放開與自動連發的差別。按住A達40次更新後放開。FIRST DOWN、FIRST PRESS、FIRST REPEAT為1,FIRST CURRENT為16。HELD TICKS為40,PRESS COUNT為1,REPEAT COUNT為5。放開後,RELEASE為1,LAST CURRENT為0,LAST PREVIOUS為16。FAILED CHECKS應為0。改變按住的時間會改變計數;程式會根據實際觀測到的時間檢查連發間隔。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\input.c .\kitaq-docs\samples\api-examples\gb\input_edges.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\input_edges.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm --no-cache實作與原始碼
kitaqgb/lib/input.h:36
Return whether any masked button is currently held.
kitaqgb/lib/input.c:68
u8 input_down(u8 mask)
{
return (u8)((kq_input_keys & mask) != 0);
}input_init
將目前、前次、按下、放開及重複觸發遮罩清為 0,並將八個重複計時器重設為 INPUT_REPEAT_DELAY。本函式初始化輸入函式庫,但不讀取控制器。接著第一次更新時按住的按鈕會被視為新按下。
語法
void input_init();回傳值
無(void)。
使用條件與限制
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
重複觸發以更新次數計時,不是毫秒。新按下時立即觸發。預設 INPUT_REPEAT_DELAY=18、INPUT_REPEAT_RATE=5 時,19 次更新後再次觸發,之後每 6 次更新觸發一次。各按鈕獨立計數。修改設定時,編譯 input.c 也必須使用相同巨集值;只修改呼叫端的標頭檔不會改變函式庫設定。
使用範例
input_init();
if (input_current()!=0 || input_previous()!=0) failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範持續按住、剛按下、剛放開與自動連發的差別。按住A達40次更新後放開。FIRST DOWN、FIRST PRESS、FIRST REPEAT為1,FIRST CURRENT為16。HELD TICKS為40,PRESS COUNT為1,REPEAT COUNT為5。放開後,RELEASE為1,LAST CURRENT為0,LAST PREVIOUS為16。FAILED CHECKS應為0。改變按住的時間會改變計數;程式會根據實際觀測到的時間檢查連發間隔。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\input.c .\kitaq-docs\samples\api-examples\gb\input_edges.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\input_edges.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm --no-cache實作與原始碼
kitaqgb/lib/input.h:31
Clear sampled/edge state and initialize an independent repeat timer for each button.
kitaqgb/lib/input.c:18
void input_init()
{
u8 i;
kq_input_prev_keys = 0;
kq_input_keys = 0;
kq_input_press_keys = 0;
kq_input_release_keys = 0;
kq_input_repeat_keys = 0;
i = 0;
while (i < 8) {
input_repeat_timer[i] = INPUT_REPEAT_DELAY;
i++;
}
}input_pressed
判斷最近一次輸入更新中,遮罩選取的按鈕是否從放開變成按下。
語法
u8 input_pressed(u8 mask);參數
mask一個
BTN_*遮罩,或以|組合的多個遮罩。任一選中按鈕符合條件即為真;BTN_A | BTN_B不要求同時按住兩個按鈕。遮罩 0 一律回傳 0。若要檢查全部按鈕均按住,使用(input_current() & mask) == mask。
回傳值
任一選中按鈕符合查詢條件時回傳 1,否則回傳 0。回傳值不是按鈕位元遮罩。
使用條件與限制
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
查詢函式只讀取最近一次 input_update() 保存的狀態,不重新讀取控制器、不消耗事件,也不推進重複計時器。同一輸入週期內重複查詢結果相同。按鈕持續按住時若呼叫兩次 input_update(),第二次會清除新按下事件。
使用範例
if (input_pressed(BTN_A)!=0) {
press_count++; seen_press=1;
first_down=input_down(BTN_A); first_press=input_pressed(BTN_A);
first_repeat=input_repeat(BTN_A);
first_current=input_current(); // Only A held: BTN_A, or decimal 16.
first_previous=input_previous(); // No buttons in the preceding sample: 0.
if (first_down!=1 || first_press!=1 || first_repeat!=1) failures++;
if (first_current!=BTN_A || first_previous!=0) failures++;
if (input_down(BTN_A|BTN_B)!=1 || input_down(0)!=0) failures++;
}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範持續按住、剛按下、剛放開與自動連發的差別。按住A達40次更新後放開。FIRST DOWN、FIRST PRESS、FIRST REPEAT為1,FIRST CURRENT為16。HELD TICKS為40,PRESS COUNT為1,REPEAT COUNT為5。放開後,RELEASE為1,LAST CURRENT為0,LAST PREVIOUS為16。FAILED CHECKS應為0。改變按住的時間會改變計數;程式會根據實際觀測到的時間檢查連發間隔。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\input.c .\kitaq-docs\samples\api-examples\gb\input_edges.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\input_edges.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm --no-cache實作與原始碼
kitaqgb/lib/input.h:38
Return whether any masked button became pressed in the latest sample.
kitaqgb/lib/input.c:74
u8 input_pressed(u8 mask)
{
return (u8)((kq_input_press_keys & mask) != 0);
}input_previous
回傳最近一次更新之前保存的按住按鈕位元遮罩。
語法
u8 input_previous();回傳值
共用 BTN_* 格式的 8 位元遮罩。多個按鈕可以同時設為 1;0 表示沒有按鈕。
使用條件與限制
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
查詢函式只讀取最近一次 input_update() 保存的狀態,不重新讀取控制器、不消耗事件,也不推進重複計時器。同一輸入週期內重複查詢結果相同。按鈕持續按住時若呼叫兩次 input_update(),第二次會清除新按下事件。
使用範例
first_previous=input_previous(); // No buttons in the preceding sample: 0.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範持續按住、剛按下、剛放開與自動連發的差別。按住A達40次更新後放開。FIRST DOWN、FIRST PRESS、FIRST REPEAT為1,FIRST CURRENT為16。HELD TICKS為40,PRESS COUNT為1,REPEAT COUNT為5。放開後,RELEASE為1,LAST CURRENT為0,LAST PREVIOUS為16。FAILED CHECKS應為0。改變按住的時間會改變計數;程式會根據實際觀測到的時間檢查連發間隔。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\input.c .\kitaq-docs\samples\api-examples\gb\input_edges.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\input_edges.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm --no-cache實作與原始碼
kitaqgb/lib/input.h:46
Return the held-button mask that preceded the latest update.
kitaqgb/lib/input.c:98
u8 input_previous()
{
return kq_input_prev_keys;
}input_released
判斷最近一次輸入更新中,遮罩選取的按鈕是否從按下變成放開。
語法
u8 input_released(u8 mask);參數
mask一個
BTN_*遮罩,或以|組合的多個遮罩。任一選中按鈕符合條件即為真;BTN_A | BTN_B不要求同時按住兩個按鈕。遮罩 0 一律回傳 0。若要檢查全部按鈕均按住,使用(input_current() & mask) == mask。
回傳值
任一選中按鈕符合查詢條件時回傳 1,否則回傳 0。回傳值不是按鈕位元遮罩。
使用條件與限制
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
查詢函式只讀取最近一次 input_update() 保存的狀態,不重新讀取控制器、不消耗事件,也不推進重複計時器。同一輸入週期內重複查詢結果相同。按鈕持續按住時若呼叫兩次 input_update(),第二次會清除新按下事件。
使用範例
if (input_released(BTN_A)!=0) {
release_result=input_released(BTN_A);
last_current=input_current(); last_previous=input_previous();
if (input_down(BTN_A)!=0 || input_pressed(BTN_A)!=0 || input_repeat(BTN_A)!=0) failures++;
break;
}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範持續按住、剛按下、剛放開與自動連發的差別。按住A達40次更新後放開。FIRST DOWN、FIRST PRESS、FIRST REPEAT為1,FIRST CURRENT為16。HELD TICKS為40,PRESS COUNT為1,REPEAT COUNT為5。放開後,RELEASE為1,LAST CURRENT為0,LAST PREVIOUS為16。FAILED CHECKS應為0。改變按住的時間會改變計數;程式會根據實際觀測到的時間檢查連發間隔。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\input.c .\kitaq-docs\samples\api-examples\gb\input_edges.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\input_edges.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm --no-cache實作與原始碼
kitaqgb/lib/input.h:40
Return whether any masked button became released in the latest sample.
kitaqgb/lib/input.c:80
u8 input_released(u8 mask)
{
return (u8)((kq_input_release_keys & mask) != 0);
}input_repeat
判斷遮罩選取的按鈕是否產生首次按下或定時重複輸入。
語法
u8 input_repeat(u8 mask);參數
mask一個
BTN_*遮罩,或以|組合的多個遮罩。任一選中按鈕符合條件即為真;BTN_A | BTN_B不要求同時按住兩個按鈕。遮罩 0 一律回傳 0。若要檢查全部按鈕均按住,使用(input_current() & mask) == mask。
回傳值
任一選中按鈕符合查詢條件時回傳 1,否則回傳 0。回傳值不是按鈕位元遮罩。
使用條件與限制
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
查詢函式只讀取最近一次 input_update() 保存的狀態,不重新讀取控制器、不消耗事件,也不推進重複計時器。同一輸入週期內重複查詢結果相同。按鈕持續按住時若呼叫兩次 input_update(),第二次會清除新按下事件。
重複觸發以更新次數計時,不是毫秒。新按下時立即觸發。預設 INPUT_REPEAT_DELAY=18、INPUT_REPEAT_RATE=5 時,19 次更新後再次觸發,之後每 6 次更新觸發一次。各按鈕獨立計數。修改設定時,編譯 input.c 也必須使用相同巨集值;只修改呼叫端的標頭檔不會改變函式庫設定。
使用範例
if (input_repeat(BTN_A)!=0) {
// The initial press is pulse 1. Defaults then wait 19 updates, followed by 6.
if (repeat_count==1 && held_ticks-previous_pulse!=19) failures++;
if (repeat_count>1 && held_ticks-previous_pulse!=6) failures++;
previous_pulse=held_ticks; repeat_count++;
if (input_repeat(BTN_A)!=1) failures++; // Reading again does not consume it.
}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範持續按住、剛按下、剛放開與自動連發的差別。按住A達40次更新後放開。FIRST DOWN、FIRST PRESS、FIRST REPEAT為1,FIRST CURRENT為16。HELD TICKS為40,PRESS COUNT為1,REPEAT COUNT為5。放開後,RELEASE為1,LAST CURRENT為0,LAST PREVIOUS為16。FAILED CHECKS應為0。改變按住的時間會改變計數;程式會根據實際觀測到的時間檢查連發間隔。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\input.c .\kitaq-docs\samples\api-examples\gb\input_edges.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\input_edges.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm --no-cache實作與原始碼
kitaqgb/lib/input.h:42
Return whether any masked button produced a fresh press or scheduled repeat pulse.
kitaqgb/lib/input.c:86
u8 input_repeat(u8 mask)
{
return (u8)((kq_input_repeat_keys & mask) != 0);
}input_update
將目前遮罩保存為前次狀態,透過 __readpadex 讀取 Game Boy 按鈕,計算放開事件,並推進各按鈕獨立的重複計時器。每個遊戲輸入週期呼叫一次,再查詢快取狀態。
語法
void input_update();回傳值
無(void)。
使用條件與限制
共用遮罩為 BTN_RIGHT=0x01、BTN_LEFT=0x02、BTN_UP=0x04、BTN_DOWN=0x08、BTN_A=0x10、BTN_B=0x20、BTN_SELECT=0x40、BTN_START=0x80。位元為 1 表示按住。GB 與 FC 的 input_* 均使用此格式;FC 原始手把函式的位元順序不同。
重複觸發以更新次數計時,不是毫秒。新按下時立即觸發。預設 INPUT_REPEAT_DELAY=18、INPUT_REPEAT_RATE=5 時,19 次更新後再次觸發,之後每 6 次更新觸發一次。各按鈕獨立計數。修改設定時,編譯 input.c 也必須使用相同巨集值;只修改呼叫端的標頭檔不會改變函式庫設定。
使用範例
input_update(); // One update per input tick, followed by any number of queries.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此程式示範持續按住、剛按下、剛放開與自動連發的差別。按住A達40次更新後放開。FIRST DOWN、FIRST PRESS、FIRST REPEAT為1,FIRST CURRENT為16。HELD TICKS為40,PRESS COUNT為1,REPEAT COUNT為5。放開後,RELEASE為1,LAST CURRENT為0,LAST PREVIOUS為16。FAILED CHECKS應為0。改變按住的時間會改變計數;程式會根據實際觀測到的時間檢查連發間隔。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\input.c .\kitaq-docs\samples\api-examples\gb\input_edges.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\input_edges.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm --no-cache實作與原始碼
kitaqgb/lib/input.h:34
Sample input once per game tick and derive press, release and repeat masks. Repeat delays are measured in calls to this function, not elapsed wall-clock time.
kitaqgb/lib/input.c:35
void input_update()
{
u8 i;
u16 kt;
kq_input_prev_keys = kq_input_keys;
// The intrinsic packs held buttons in the low byte and new presses in the high byte.
kt = __readpadex(kq_input_prev_keys);
kq_input_keys = (u8)kt;
kq_input_press_keys = (u8)(kt >> 8);
kq_input_release_keys = (u8)(kq_input_prev_keys & (u8)(kq_input_keys ^ 0xFF));
kq_input_repeat_keys = kq_input_press_keys;
i = 0;
while (i < 8) {
u8 mask = input_mask_for_index(i);
if ((kq_input_keys & mask) != 0) {
if ((kq_input_press_keys & mask) != 0) {
input_repeat_timer[i] = INPUT_REPEAT_DELAY;
} else if (input_repeat_timer[i] != 0) {
input_repeat_timer[i]--;
} else {
kq_input_repeat_keys = (u8)(kq_input_repeat_keys | mask);
input_repeat_timer[i] = INPUT_REPEAT_RATE;
}
} else {
input_repeat_timer[i] = INPUT_REPEAT_DELAY;
}
i++;
}
}link.h — 序列通訊與邏輯封包
函式庫提供三層:位元組交換、最多 24 位元組封包,以及各對端佇列。請從 BYTE MASTER/SLAVE 開始,再學 PACKET 與 LINK4,了解誰提供時脈及何時可接收。每個程式須依序包含硬體暫存器單元、link.c、link_packet.c,且各僅一次;gb_link_example.h 提供此順序。
Link4 管理邏輯主機槽位 0 與對端槽位 1~3。SelectPeer 不會傳送切換實體接線的命令。KOKURA 的 link4 拓撲透過編譯器中繼資料跟隨所選對端。實體 DMG-07 協定請使用 LinkDmg07。
兩端都須持續輪詢。逾時計算的是沒有進展的 90 次呼叫,不是硬體影格。僅為 ACK 提供時脈而傳送 0xFF 不會延長期限;傳送最多嘗試三次。重試可能造成重複送達,若命令必須恰好執行一次,請加入應用層識別碼。
Link4_BeginTransferTo
選擇目的地,再啟動一次位元組交換。
語法
u8 __stackcall Link4_BeginTransferTo(u8 peer_slot, u8 out);參數
peer_slot已設定的遠端槽位:主機使用 1~slot_count−1,對端使用 0。
out要送出的八位元值。
回傳值
傳回選擇/啟動時第一個錯誤,成功則為 0。
使用條件與限制
Link4 管理邏輯主機槽位 0 與對端槽位 1~3。SelectPeer 不會傳送切換實體接線的命令。KOKURA 的 link4 拓撲透過編譯器中繼資料跟隨所選對端。實體 DMG-07 協定請使用 LinkDmg07。
錯誤碼為 0=無、1=忙碌、2=逾時、3=接收溢位、4=設定/協定無效、5=伴隨類似斷線回應的 ACK 逾時。啟動/設定呼叫以 0 表示成功,接收/取出呼叫以 1 表示成功。成功呼叫不會清除已鎖存的錯誤。
Link4 將每個接收位元組同時複製到一般環狀緩衝區與對端專用環狀緩衝區。讀取其中一個不會清空另一個。封包輪詢會消耗一般緩衝區;也須定期丟棄未使用的對端原始位元組,避免溢位。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
result[6+slot]=Link4_BeginTransferTo(slot,16+slot);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
請以 KOKURA 的 link4 拓撲連接四個 ROM。主機從對端 1/2/3 收到 161/162/163,並顯示 LAST PEER=3。接著傳送命令 65/66/67 與有效負載 7/42/255;也請在各對端畫面確認這些值。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png實作與原始碼
kitaqgb/lib/link.h:129
Select the logical peer and start a byte exchange, returning the first error.
kitaqgb/lib/link.c:584
u8 __stackcall Link4_BeginTransferTo(u8 peer_slot, u8 out) {
u8 err = Link4_SelectPeer(peer_slot);
if (err != LINK_ERR_NONE) return err;
return Link_BeginTransfer(out);
}Link4_GetLastRxPeer
讀取最後完成接收的位元組所屬對端。
語法
u8 Link4_GetLastRxPeer();回傳值
主機傳回選定對端,對端傳回 0;尚未接收時傳回 255。
使用條件與限制
Link4 管理邏輯主機槽位 0 與對端槽位 1~3。SelectPeer 不會傳送切換實體接線的命令。KOKURA 的 link4 拓撲透過編譯器中繼資料跟隨所選對端。實體 DMG-07 協定請使用 LinkDmg07。
這些函式讀取設定/歷史紀錄,不偵測實體連接、不查詢所有對端,也不等待傳輸完成。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
result[19]=Link4_GetLastRxPeer();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
請以 KOKURA 的 link4 拓撲連接四個 ROM。主機從對端 1/2/3 收到 161/162/163,並顯示 LAST PEER=3。接著傳送命令 65/66/67 與有效負載 7/42/255;也請在各對端畫面確認這些值。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png實作與原始碼
kitaqgb/lib/link.h:121
Return the peer attributed to the last completed byte transfer.
kitaqgb/lib/link.c:540
u8 Link4_GetLastRxPeer() {
return Link4_LastRxPeer;
}Link4_GetLastTxPeer
讀取最後一次位元組傳輸啟動時記錄的目的地。
語法
u8 Link4_GetLastTxPeer();回傳值
傳回記錄的目的地;從未啟動過時為 255。
使用條件與限制
Link4 管理邏輯主機槽位 0 與對端槽位 1~3。SelectPeer 不會傳送切換實體接線的命令。KOKURA 的 link4 拓撲透過編譯器中繼資料跟隨所選對端。實體 DMG-07 協定請使用 LinkDmg07。
這些函式讀取設定/歷史紀錄,不偵測實體連接、不查詢所有對端,也不等待傳輸完成。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
result[20]=Link4_GetLastTxPeer();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
請以 KOKURA 的 link4 拓撲連接四個 ROM。主機從對端 1/2/3 收到 161/162/163,並顯示 LAST PEER=3。接著傳送命令 65/66/67 與有效負載 7/42/255;也請在各對端畫面確認這些值。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png實作與原始碼
kitaqgb/lib/link.h:123
Return the peer attributed when the last byte transfer was started.
kitaqgb/lib/link.c:545
u8 Link4_GetLastTxPeer() {
return Link4_LastTxPeer;
}Link4_GetLocalSlot
讀取本機已設定的槽位。
語法
u8 Link4_GetLocalSlot();回傳值
主機為 0,對端為 1~3。未設定狀態也傳回 0。
使用條件與限制
Link4 管理邏輯主機槽位 0 與對端槽位 1~3。SelectPeer 不會傳送切換實體接線的命令。KOKURA 的 link4 拓撲透過編譯器中繼資料跟隨所選對端。實體 DMG-07 協定請使用 LinkDmg07。
這些函式讀取設定/歷史紀錄,不偵測實體連接、不查詢所有對端,也不等待傳輸完成。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
result[2]=Link4_GetLocalSlot();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
請以 KOKURA 的 link4 拓撲連接四個 ROM。主機從對端 1/2/3 收到 161/162/163,並顯示 LAST PEER=3。接著傳送命令 65/66/67 與有效負載 7/42/255;也請在各對端畫面確認這些值。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png實作與原始碼
kitaqgb/lib/link.h:115
Return the configured zero-based local slot.
kitaqgb/lib/link.c:525
u8 Link4_GetLocalSlot() {
return Link4_LocalSlot;
}Link4_GetMode
讀取已設定的邏輯角色。
語法
u8 Link4_GetMode();回傳值
0=未設定、1=主機、2=對端。
使用條件與限制
Link4 管理邏輯主機槽位 0 與對端槽位 1~3。SelectPeer 不會傳送切換實體接線的命令。KOKURA 的 link4 拓撲透過編譯器中繼資料跟隨所選對端。實體 DMG-07 協定請使用 LinkDmg07。
這些函式讀取設定/歷史紀錄,不偵測實體連接、不查詢所有對端,也不等待傳輸完成。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
result[1]=Link4_GetMode();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
請以 KOKURA 的 link4 拓撲連接四個 ROM。主機從對端 1/2/3 收到 161/162/163,並顯示 LAST PEER=3。接著傳送命令 65/66/67 與有效負載 7/42/255;也請在各對端畫面確認這些值。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png實作與原始碼
kitaqgb/lib/link.h:113
Return the configured cooperative role; this is not a hardware connection probe.
kitaqgb/lib/link.c:520
u8 Link4_GetMode() {
return Link4_ModeState;
}Link4_GetSelectedPeer
讀取目前選定的邏輯目的地。
語法
u8 Link4_GetSelectedPeer();回傳值
主機傳回所選對端,對端傳回 0,未設定傳回 255。
使用條件與限制
Link4 管理邏輯主機槽位 0 與對端槽位 1~3。SelectPeer 不會傳送切換實體接線的命令。KOKURA 的 link4 拓撲透過編譯器中繼資料跟隨所選對端。實體 DMG-07 協定請使用 LinkDmg07。
這些函式讀取設定/歷史紀錄,不偵測實體連接、不查詢所有對端,也不等待傳輸完成。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
result[4]=Link4_GetSelectedPeer();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
請以 KOKURA 的 link4 拓撲連接四個 ROM。主機從對端 1/2/3 收到 161/162/163,並顯示 LAST PEER=3。接著傳送命令 65/66/67 與有效負載 7/42/255;也請在各對端畫面確認這些值。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png實作與原始碼
kitaqgb/lib/link.h:119
Return the current logical destination, or the invalid-slot sentinel when unset.
kitaqgb/lib/link.c:535
u8 Link4_GetSelectedPeer() {
return Link4_SelectedPeer;
}Link4_GetSlotCount
讀取已設定的總槽位數。
語法
u8 Link4_GetSlotCount();回傳值
有效設定傳回 2~4,未設定傳回 0。
使用條件與限制
Link4 管理邏輯主機槽位 0 與對端槽位 1~3。SelectPeer 不會傳送切換實體接線的命令。KOKURA 的 link4 拓撲透過編譯器中繼資料跟隨所選對端。實體 DMG-07 協定請使用 LinkDmg07。
這些函式讀取設定/歷史紀錄,不偵測實體連接、不查詢所有對端,也不等待傳輸完成。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
result[3]=Link4_GetSlotCount();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
請以 KOKURA 的 link4 拓撲連接四個 ROM。主機從對端 1/2/3 收到 161/162/163,並顯示 LAST PEER=3。接著傳送命令 65/66/67 與有效負載 7/42/255;也請在各對端畫面確認這些值。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png實作與原始碼
kitaqgb/lib/link.h:117
Return the configured number of logical slots, not a live connection count.
kitaqgb/lib/link.c:530
u8 Link4_GetSlotCount() {
return Link4_SlotCount;
}Link4_HasByteFrom
檢查某一對端接收環狀緩衝區中的未讀資料。
語法
u8 __stackcall Link4_HasByteFrom(u8 peer_slot);參數
peer_slot已設定的遠端槽位:主機使用 1~slot_count−1,對端使用 0。
回傳值
有排入的資料傳回 1;為空或對端無效傳回 0。
使用條件與限制
八個項目的接收環狀緩衝區可存七個位元組。已滿時會捨棄新位元組並鎖存錯誤 3。收到的零位元組也是有效資料。
Link4 將每個接收位元組同時複製到一般環狀緩衝區與對端專用環狀緩衝區。讀取其中一個不會清空另一個。封包輪詢會消耗一般緩衝區;也須定期丟棄未使用的對端原始位元組,避免溢位。
此查詢不輪詢硬體;無效對端不會變更已鎖存錯誤。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
result[9+slot]=Link4_HasByteFrom(slot);value=0;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
請以 KOKURA 的 link4 拓撲連接四個 ROM。主機從對端 1/2/3 收到 161/162/163,並顯示 LAST PEER=3。接著傳送命令 65/66/67 與有效負載 7/42/255;也請在各對端畫面確認這些值。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png實作與原始碼
kitaqgb/lib/link.h:131
Inspect a valid peer ring without polling the hardware.
kitaqgb/lib/link.c:591
u8 __stackcall Link4_HasByteFrom(u8 peer_slot) {
if (Link4_IsValidRemoteSlotInternal(peer_slot) == 0) return 0;
if (Link4_RxHead[(__safe_index u8)peer_slot] == Link4_RxTail[(__safe_index u8)peer_slot]) return 0;
return 1;
}Link4_HasPacketFrom
檢查某個遠端槽位的完整封包信箱。
語法
u8 __stackcall Link4_HasPacketFrom(u8 peer_slot);參數
peer_slot已設定的遠端槽位:主機使用 1~slot_count−1,對端使用 0。
回傳值
有未讀封包時傳回 1,為空或對端無效時傳回 0。
使用條件與限制
Link4 管理邏輯主機槽位 0 與對端槽位 1~3。SelectPeer 不會傳送切換實體接線的命令。KOKURA 的 link4 拓撲透過編譯器中繼資料跟隨所選對端。實體 DMG-07 協定請使用 LinkDmg07。
封包包含 0xA5、命令、長度、0~24 個有效負載位元組及 XOR 檢查碼。回應為 0x79(ACK,接受)或 0x1F(NAK,拒絕)。檢查碼由命令、長度及有效負載做 XOR 得到。每台主機有一個共用封包信箱,Link4 另為每個對端提供一個信箱。
此查詢不輪詢硬體;無效對端不會變更已鎖存錯誤。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
result[9]=Link4_HasPacketFrom(0);result[10]=Link4_ReadPacketFrom(0,&cmd,&len,data);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
作為四槽位中的對端 1,預期 HOST BYTE=17、COMMAND=65、LENGTH=3、PAYLOAD 2=42。CONSUMED=0 是取出後的主機信箱旗標。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png實作與原始碼
kitaqgb/lib/link.h:142
Inspect the one-packet mailbox for a valid remote slot without consuming it.
kitaqgb/lib/link_packet.c:484
u8 __stackcall Link4_HasPacketFrom(u8 peer_slot) {
return Link4_PacketPeerReady(peer_slot);
}Link4_InitHost
初始化包含二至四個槽位的邏輯主機,並選擇對端 1。
語法
u8 __stackcall Link4_InitHost(u8 slot_count);參數
slot_count包含主機的槽位數,範圍為 2~4。
回傳值
設定有效傳回 0,槽位數無效傳回 4。
使用條件與限制
初始化會捨棄位元組佇列、封包、對端選擇及錯誤,並停用傳輸與序列 IRQ 來源。不保留進行中的交換。
Link4 管理邏輯主機槽位 0 與對端槽位 1~3。SelectPeer 不會傳送切換實體接線的命令。KOKURA 的 link4 拓撲透過編譯器中繼資料跟隨所選對端。實體 DMG-07 協定請使用 LinkDmg07。
內部臨界區會追蹤軟體巢狀深度。離開最外層時會啟用 CPU 中斷,因此不可假設原本停用的 IME 狀態會被保留。
先初始化再驗證。即使呼叫失敗,仍會捨棄先前拓撲與未讀資料。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
result[0]=Link4_InitHost(4);result[1]=Link4_GetMode();result[2]=Link4_GetLocalSlot();result[3]=Link4_GetSlotCount();result[4]=Link4_GetSelectedPeer();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
請以 KOKURA 的 link4 拓撲連接四個 ROM。主機從對端 1/2/3 收到 161/162/163,並顯示 LAST PEER=3。接著傳送命令 65/66/67 與有效負載 7/42/255;也請在各對端畫面確認這些值。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png實作與原始碼
kitaqgb/lib/link.h:108
Cooperative 4-player adapter helpers. This layer models the common host-selected adapter pattern: - Slot 0 is always the host. - The host selects one active peer slot at a time. - Packet mailboxes stay one-deep per peer. - The original Link_* API remains available for normal 2-player projects. Reset as master, validate slot count and select logical peer one. Invalid configuration still discards old link state.
kitaqgb/lib/link.c:489
u8 __stackcall Link4_InitHost(u8 slot_count) {
u8 err;
Link_InitMaster();
err = Link4_ValidateConfig(LINK4_MODE_HOST, LINK4_HOST_SLOT, slot_count);
if (err != LINK_ERR_NONE) {
Link_SetErrorInternal(err);
return err;
}
Link4_ApplyConfig(LINK4_MODE_HOST, LINK4_HOST_SLOT, slot_count);
return LINK_ERR_NONE;
}Link4_InitPeer
初始化使用外部時脈的對端,並選擇主機槽位 0。
語法
u8 __stackcall Link4_InitPeer(u8 local_slot, u8 slot_count);參數
local_slot本機槽位,範圍為 1~slot_count−1。
slot_count包含主機的總槽位數,範圍為 2~4。
回傳值
設定有效傳回 0,槽位數或本機槽位無效傳回 4。
使用條件與限制
初始化會捨棄位元組佇列、封包、對端選擇及錯誤,並停用傳輸與序列 IRQ 來源。不保留進行中的交換。
Link4 管理邏輯主機槽位 0 與對端槽位 1~3。SelectPeer 不會傳送切換實體接線的命令。KOKURA 的 link4 拓撲透過編譯器中繼資料跟隨所選對端。實體 DMG-07 協定請使用 LinkDmg07。
內部臨界區會追蹤軟體巢狀深度。離開最外層時會啟用 CPU 中斷,因此不可假設原本停用的 IME 狀態會被保留。
先初始化再驗證。即使呼叫失敗,仍會捨棄先前拓撲與未讀資料。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
result[0]=Link4_InitPeer(1,4);result[1]=Link4_GetMode();result[2]=Link4_GetLocalSlot();result[3]=Link4_GetSlotCount();result[4]=Link4_GetSelectedPeer();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
作為四槽位中的對端 1,預期 HOST BYTE=17、COMMAND=65、LENGTH=3、PAYLOAD 2=42。CONSUMED=0 是取出後的主機信箱旗標。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png實作與原始碼
kitaqgb/lib/link.h:111
Reset as slave and validate the local nonzero slot and total slot count. An invalid configuration still discards the previous link state.
kitaqgb/lib/link.c:505
u8 __stackcall Link4_InitPeer(u8 local_slot, u8 slot_count) {
u8 err;
Link_InitSlave();
err = Link4_ValidateConfig(LINK4_MODE_PEER, local_slot, slot_count);
if (err != LINK_ERR_NONE) {
Link_SetErrorInternal(err);
return err;
}
Link4_ApplyConfig(LINK4_MODE_PEER, local_slot, slot_count);
return LINK_ERR_NONE;
}Link4_PollPacket
針對目前選定對端,將共用封包處理引擎推進一次。
語法
void Link4_PollPacket();回傳值
無傳回值。
使用條件與限制
Link4 管理邏輯主機槽位 0 與對端槽位 1~3。SelectPeer 不會傳送切換實體接線的命令。KOKURA 的 link4 拓撲透過編譯器中繼資料跟隨所選對端。實體 DMG-07 協定請使用 LinkDmg07。
封包包含 0xA5、命令、長度、0~24 個有效負載位元組及 XOR 檢查碼。回應為 0x79(ACK,接受)或 0x1F(NAK,拒絕)。檢查碼由命令、長度及有效負載做 XOR 得到。每台主機有一個共用封包信箱,Link4 另為每個對端提供一個信箱。
兩端都須持續輪詢。逾時計算的是沒有進展的 90 次呼叫,不是硬體影格。僅為 ACK 提供時脈而傳送 0xFF 不會延長期限;傳送最多嘗試三次。重試可能造成重複送達,若命令必須恰好執行一次,請加入應用層識別碼。
Link4 將每個接收位元組同時複製到一般環狀緩衝區與對端專用環狀緩衝區。讀取其中一個不會清空另一個。封包輪詢會消耗一般緩衝區;也須定期丟棄未使用的對端原始位元組,避免溢位。
不會輪流處理所有槽位。只有交換完成且允許選擇時,才能變更對端。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
for(i=0;i<50;i++){Link4_PollPacket();while(Link4_TryReadByteFrom(slot,0)){}m_wait();}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
請以 KOKURA 的 link4 拓撲連接四個 ROM。主機從對端 1/2/3 收到 161/162/163,並顯示 LAST PEER=3。接著傳送命令 65/66/67 與有效負載 7/42/255;也請在各對端畫面確認這些值。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png實作與原始碼
kitaqgb/lib/link.h:140
Advance the shared packet engine; this does not poll every logical peer in turn.
kitaqgb/lib/link_packet.c:479
void Link4_PollPacket() {
Link_PollPacket();
}Link4_ReadPacketFrom
複製指定對端的封包,並從其信箱取走。
語法
u8 __stackcall Link4_ReadPacketFrom(u8 peer_slot, u8 *cmd, u8 *len, u8 *dst);參數
peer_slot已設定的遠端槽位:主機使用 1~slot_count−1,對端使用 0。
cmd可寫入的命令位元組;null 表示省略此輸出。
len可寫入的長度位元組,範圍為 0~24;null 表示省略此輸出。
dst可寫入且容納 24 位元組的有效負載緩衝區;null 表示捨棄有效負載。
回傳值
取出成功傳回 1;為空或對端無效傳回 0。
使用條件與限制
沒有目的地容量參數。使用 dst 時須提供 24 個可寫入位元組。cmd、len、dst 可各自為 null。須將信箱檢查與取用序列化,避免與其他程式碼或中斷同時操作。
只有共用信箱指向同一對端封包時才清除它。其他對端的未讀封包仍可使用。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
result[9]=Link4_HasPacketFrom(0);result[10]=Link4_ReadPacketFrom(0,&cmd,&len,data);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
作為四槽位中的對端 1,預期 HOST BYTE=17、COMMAND=65、LENGTH=3、PAYLOAD 2=42。CONSUMED=0 是取出後的主機信箱旗標。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png實作與原始碼
kitaqgb/lib/link.h:146
Consume a peer mailbox, copying to optional outputs. A nonnull destination needs room for the entire payload. Clear the shared mailbox only when it refers to this same peer.
kitaqgb/lib/link_packet.c:491
u8 __stackcall Link4_ReadPacketFrom(u8 peer_slot, u8 *cmd, u8 *len, u8 *dst) {
u8 i;
u8 offset;
if (Link4_PacketPeerReady(peer_slot) == 0) return 0;
if (cmd != 0) *cmd = Link4_ReceivedPacketCmd[(__safe_index u8)peer_slot];
if (len != 0) *len = Link4_ReceivedPacketLen[(__safe_index u8)peer_slot];
if (dst != 0) {
for (i = 0; i < Link4_ReceivedPacketLen[(__safe_index u8)peer_slot]; ++i) {
offset = Link4_PacketOffset(peer_slot, i);
dst[(__safe_index u8)i] = Link4_ReceivedPacketBuf[(__safe_index u8)offset];
}
}
Link4_ReceivedPacketReady[(__safe_index u8)peer_slot] = 0;
if (Link4_LastPacketPeer == peer_slot) {
Link_ReceivedPacketReady = 0;
Link4_LastPacketPeer = LINK4_INVALID_SLOT;
}
return 1;
}Link4_SelectPeer
輪詢完成狀態,並僅在閒置時變更邏輯目的地。
語法
u8 __stackcall Link4_SelectPeer(u8 peer_slot);參數
peer_slot已設定的遠端槽位:主機使用 1~slot_count−1,對端使用 0。
回傳值
選擇成功傳回 0;位元組/封包/ACK 狀態忙碌傳回 1;未設定或對端無效傳回 4。
使用條件與限制
Link4 管理邏輯主機槽位 0 與對端槽位 1~3。SelectPeer 不會傳送切換實體接線的命令。KOKURA 的 link4 拓撲透過編譯器中繼資料跟隨所選對端。實體 DMG-07 協定請使用 LinkDmg07。
錯誤碼為 0=無、1=忙碌、2=逾時、3=接收溢位、4=設定/協定無效、5=伴隨類似斷線回應的 ACK 逾時。啟動/設定呼叫以 0 表示成功,接收/取出呼叫以 1 表示成功。成功呼叫不會清除已鎖存的錯誤。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
result[25]=Link4_SelectPeer(1);result[26]=Link_LastError();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
請以 KOKURA 的 link4 拓撲連接四個 ROM。主機從對端 1/2/3 收到 161/162/163,並顯示 LAST PEER=3。接著傳送命令 65/66/67 與有效負載 7/42/255;也請在各對端畫面確認這些值。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png實作與原始碼
kitaqgb/lib/link.h:127
Poll completion, then change the logical destination only while byte and packet state are idle. A peer can select only the host. No adapter-routing command is sent here; the transport must provide the matching physical route.
kitaqgb/lib/link.c:552
u8 __stackcall Link4_SelectPeer(u8 peer_slot) {
Link_Poll();
if (Link4_IsEnabledInternal() == 0) {
Link_SetErrorInternal(LINK_ERR_PROTOCOL);
return LINK_ERR_PROTOCOL;
}
if (Link_Busy != 0 || Link_PacketState != LINK_PKT_STATE_IDLE || Link_PendingAck != 0) {
Link_SetErrorInternal(LINK_ERR_BUSY);
return LINK_ERR_BUSY;
}
if (Link4_ModeState == LINK4_MODE_HOST) {
if (Link4_IsValidRemoteSlotInternal(peer_slot) == 0) {
Link_SetErrorInternal(LINK_ERR_PROTOCOL);
return LINK_ERR_PROTOCOL;
}
Link4_SelectedPeer = peer_slot;
return LINK_ERR_NONE;
}
if (Link4_ModeState == LINK4_MODE_PEER && peer_slot == LINK4_HOST_SLOT) {
Link4_SelectedPeer = LINK4_HOST_SLOT;
return LINK_ERR_NONE;
}
Link_SetErrorInternal(LINK_ERR_PROTOCOL);
return LINK_ERR_PROTOCOL;
}Link4_SendPacketTo
選擇邏輯對端、複製封包並排程傳送。
語法
u8 __stackcall Link4_SendPacketTo(u8 peer_slot, const u8 *data, u8 len, u8 cmd);參數
peer_slot已設定的遠端槽位:主機使用 1~slot_count−1,對端使用 0。
data可讀取 len 個位元組的來源;只有 len 為零時才可為 null。
len有效負載長度,以位元組為單位,範圍為 0~24。
cmd應用程式定義的八位元命令。
回傳值
傳回選擇/排入佇列時第一個錯誤;0 表示接受。
使用條件與限制
Link4 管理邏輯主機槽位 0 與對端槽位 1~3。SelectPeer 不會傳送切換實體接線的命令。KOKURA 的 link4 拓撲透過編譯器中繼資料跟隨所選對端。實體 DMG-07 協定請使用 LinkDmg07。
錯誤碼為 0=無、1=忙碌、2=逾時、3=接收溢位、4=設定/協定無效、5=伴隨類似斷線回應的 ACK 逾時。啟動/設定呼叫以 0 表示成功,接收/取出呼叫以 1 表示成功。成功呼叫不會清除已鎖存的錯誤。
封包包含 0xA5、命令、長度、0~24 個有效負載位元組及 XOR 檢查碼。回應為 0x79(ACK,接受)或 0x1F(NAK,拒絕)。檢查碼由命令、長度及有效負載做 XOR 得到。每台主機有一個共用封包信箱,Link4 另為每個對端提供一個信箱。
兩端都須持續輪詢。逾時計算的是沒有進展的 90 次呼叫,不是硬體影格。僅為 ACK 提供時脈而傳送 0xFF 不會延長期限;傳送最多嘗試三次。重試可能造成重複送達,若命令必須恰好執行一次,請加入應用層識別碼。
Link4 將每個接收位元組同時複製到一般環狀緩衝區與對端專用環狀緩衝區。讀取其中一個不會清空另一個。封包輪詢會消耗一般緩衝區;也須定期丟棄未使用的對端原始位元組,避免溢位。
先選擇目的地再驗證有效負載;即使有效負載被拒絕,仍可能保留新選定的目的地。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
result[21+slot]=Link4_SendPacketTo(slot,data,3,64+slot);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
請以 KOKURA 的 link4 拓撲連接四個 ROM。主機從對端 1/2/3 收到 161/162/163,並顯示 LAST PEER=3。接著傳送命令 65/66/67 與有效負載 7/42/255;也請在各對端畫面確認這些值。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png實作與原始碼
kitaqgb/lib/link.h:138
Select a logical peer, then copy and schedule a packet; return the first error.
kitaqgb/lib/link_packet.c:472
u8 __stackcall Link4_SendPacketTo(u8 peer_slot, const u8 *data, u8 len, u8 cmd) {
u8 err = Link4_SelectPeer(peer_slot);
if (err != LINK_ERR_NONE) return err;
return Link_SendPacket(data, len, cmd);
}Link4_TryReadByteAny
依編號遞增順序掃描遠端槽位,取出第一個可用位元組。
語法
u8 __stackcall Link4_TryReadByteAny(u8 *peer_slot, u8 *out);參數
peer_slot用於來源槽位的可寫入位元組;null 表示省略來源輸出。
out可寫入的位元組目的地;null 表示捨棄該位元組。
回傳值
收到資料傳回 1,否則為 0。
使用條件與限制
八個項目的接收環狀緩衝區可存七個位元組。已滿時會捨棄新位元組並鎖存錯誤 3。收到的零位元組也是有效資料。
Link4 將每個接收位元組同時複製到一般環狀緩衝區與對端專用環狀緩衝區。讀取其中一個不會清空另一個。封包輪詢會消耗一般緩衝區;也須定期丟棄未使用的對端原始位元組,避免溢位。
內部臨界區會追蹤軟體巢狀深度。離開最外層時會啟用 CPU 中斷,因此不可假設原本停用的 IME 狀態會被保留。
略過本機槽位。較小槽位若持續有資料會優先處理;需要輪流公平讀取時,請使用各對端讀取函式。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
else {other=255;Link4_TryReadByteAny(&other,&value);result[12+slot]=other;}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
請以 KOKURA 的 link4 拓撲連接四個 ROM。主機從對端 1/2/3 收到 161/162/163,並顯示 LAST PEER=3。接著傳送命令 65/66/67 與有效負載 7/42/255;也請在各對端畫面確認這些值。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png實作與原始碼
kitaqgb/lib/link.h:136
Scan remote rings in increasing slot order and return the first available byte. Null output pointers are allowed; lower slots have polling priority.
kitaqgb/lib/link.c:604
u8 __stackcall Link4_TryReadByteAny(u8 *peer_slot, u8 *out) {
u8 slot;
if (Link4_IsEnabledInternal() == 0) return 0;
for (slot = 0; slot < Link4_SlotCount; ++slot) {
if (slot != Link4_LocalSlot) {
if (Link4_PopRxByte(slot, out) != 0) {
if (peer_slot != 0) *peer_slot = slot;
return 1;
}
}
}
return 0;
}Link4_TryReadByteFrom
從指定對端的接收環狀緩衝區取出一個位元組。
語法
u8 __stackcall Link4_TryReadByteFrom(u8 peer_slot, u8 *out);參數
peer_slot已設定的遠端槽位:主機使用 1~slot_count−1,對端使用 0。
out可寫入的位元組目的地;null 表示捨棄該位元組。
回傳值
取出成功傳回 1;為空或對端無效時保留 out 並傳回 0。
使用條件與限制
八個項目的接收環狀緩衝區可存七個位元組。已滿時會捨棄新位元組並鎖存錯誤 3。收到的零位元組也是有效資料。
Link4 將每個接收位元組同時複製到一般環狀緩衝區與對端專用環狀緩衝區。讀取其中一個不會清空另一個。封包輪詢會消耗一般緩衝區;也須定期丟棄未使用的對端原始位元組,避免溢位。
內部臨界區會追蹤軟體巢狀深度。離開最外層時會啟用 CPU 中斷,因此不可假設原本停用的 IME 狀態會被保留。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
if(slot==1)result[13]=Link4_TryReadByteFrom(slot,&value);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
請以 KOKURA 的 link4 拓撲連接四個 ROM。主機從對端 1/2/3 收到 161/162/163,並顯示 LAST PEER=3。接著傳送命令 65/66/67 與有效負載 7/42/255;也請在各對端畫面確認這些值。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png實作與原始碼
kitaqgb/lib/link.h:133
Pop one byte from the selected peer ring; null output discards it.
kitaqgb/lib/link.c:598
u8 __stackcall Link4_TryReadByteFrom(u8 peer_slot, u8 *out) {
return Link4_PopRxByte(peer_slot, out);
}Link_BeginTransfer
載入 SB,並啟動或預備一次全雙工位元組交換。
語法
u8 __stackcall Link_BeginTransfer(u8 out);參數
out要送出的八位元值。即使只在意接收,每次交換仍會送出一個位元組。
回傳值
已啟動或預備時傳回 0,已忙碌時傳回 1。
使用條件與限制
每台主機有一份共用連線狀態。位元組交換採全雙工:一端提供內部時脈,另一端使用外部時脈。一般速度每位元需 512 個時脈,CGB 高速則需 16 個。
錯誤碼為 0=無、1=忙碌、2=逾時、3=接收溢位、4=設定/協定無效、5=伴隨類似斷線回應的 ACK 逾時。啟動/設定呼叫以 0 表示成功,接收/取出呼叫以 1 表示成功。成功呼叫不會清除已鎖存的錯誤。
外部時脈端點會等待另一端提供時脈。忙碌時拒絕請求不會取代正在傳輸的位元組。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
lesson_delay(12);result[0]=Link_BeginTransfer(42);value=0;result[1]=Link_WaitByte(8,&value);result[2]=value;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
請連接 BYTE SLAVE。傳送 42 並接收 99,接著雙向交換零。RECEIVED=1、PEER BYTE=99、ZERO READY=1、ZERO BYTE=0 可區分有效的零資料與無資料。兩個 CGB 實例在第二次交換使用高速時脈。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_raw_master.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_raw_master.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_raw_slave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_raw_slave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology pair --run-frames 360 --link-session "name=raw_master|slot=0|rom=.\out\link_raw_master.gb|save_state=.\out\raw_master.kqs" --link-session "name=raw_slave|slot=1|rom=.\out\link_raw_slave.gb|save_state=.\out\raw_slave.kqs"
.\kokura\kokura-cli.exe .\out\link_raw_master.gb --hardware cgb --load-state .\out\raw_master.kqs --run-frames 2 --png .\out\raw_master.png
.\kokura\kokura-cli.exe .\out\link_raw_slave.gb --hardware cgb --load-state .\out\raw_slave.kqs --run-frames 2 --png .\out\raw_slave.png實作與原始碼
kitaqgb/lib/link.h:66
Start one full-duplex byte exchange, or return BUSY without replacing an active transfer. Slave mode arms reception and waits for external clocks.
kitaqgb/lib/link.c:362
u8 __stackcall Link_BeginTransfer(u8 out) {
u8 sc = LINK_SC_START;
if (Link_Busy != 0) {
Link_SetErrorInternal(LINK_ERR_BUSY);
return LINK_ERR_BUSY;
}
LinkHw_WriteSB(out);
Link_LastTx = out;
Link4_LastTxPeer = Link4_CurrentTransferPeerInternal();
Link_Busy = 1;
LinkHw_WriteIF((u8)(LinkHw_ReadIF() & (u8)~LINK_IF_SERIAL));
if (Link_Mode == LINK_MODE_MASTER) {
sc = (u8)(sc | LINK_SC_INTERNAL);
if (Link_FastClock != 0) sc = (u8)(sc | LINK_SC_FAST);
}
LinkHw_WriteSC(sc);
return LINK_ERR_NONE;
}Link_Cancel
停止正在進行或等待外部時脈的位元組傳輸。
語法
void Link_Cancel();回傳值
無傳回值。
使用條件與限制
內部臨界區會追蹤軟體巢狀深度。離開最外層時會啟用 CPU 中斷,因此不可假設原本停用的 IME 狀態會被保留。
寫入 SC=0,並清除忙碌及序列請求狀態。已接收位元組、封包狀態及錯誤會保留。若要從頭重啟協定,也須重新初始化。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
Link_Cancel();result[12]=Link_IsBusy();result[13]=(SC&128)!=0;Link_ClearError();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
檢查初始化、忙碌時拒絕、外部時脈逾時及環狀緩衝區容量。預期 BUSY ERROR=1、TIMEOUT=2、OPEN RX=255、OVERFLOW=3、QUEUE BYTES=7。觀察到 IRQ REQUEST=1 後,教學會在序列 IRQ 來源仍被遮罩時,明確執行處理常式本體。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_control.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_control.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\link_control.gb --hardware cgb --run-frames 330 --png .\out\control.png實作與原始碼
kitaqgb/lib/link.h:71
Stop the hardware transfer under interrupt protection. Queued receive bytes and packet-layer state remain available; this is not a full protocol reset.
kitaqgb/lib/link.c:396
void Link_Cancel() {
u8 tok = __critical_enter();
Link_Busy = 0;
LinkHw_WriteSC(0x00);
LinkHw_WriteIF((u8)(LinkHw_ReadIF() & (u8)~LINK_IF_SERIAL));
__critical_leave(tok);
}Link_ClearError
只清除鎖存的錯誤。
語法
void Link_ClearError();回傳值
無傳回值。
使用條件與限制
錯誤碼為 0=無、1=忙碌、2=逾時、3=接收溢位、4=設定/協定無效、5=伴隨類似斷線回應的 ACK 逾時。啟動/設定呼叫以 0 表示成功,接收/取出呼叫以 1 表示成功。成功呼叫不會清除已鎖存的錯誤。
傳輸、佇列及封包狀態不變。若要停止位元組傳輸,請用 Link_Cancel;若要捨棄全部狀態,請重新初始化。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
Link_ClearError();result[8]=Link_LastError();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
檢查初始化、忙碌時拒絕、外部時脈逾時及環狀緩衝區容量。預期 BUSY ERROR=1、TIMEOUT=2、OPEN RX=255、OVERFLOW=3、QUEUE BYTES=7。觀察到 IRQ REQUEST=1 後,教學會在序列 IRQ 來源仍被遮罩時,明確執行處理常式本體。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_control.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_control.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\link_control.gb --hardware cgb --run-frames 330 --png .\out\control.png實作與原始碼
kitaqgb/lib/link.h:62
Clear the error latch without resetting queues or an active transfer.
kitaqgb/lib/link.c:356
void Link_ClearError() {
Link_LastErrorCode = LINK_ERR_NONE;
}Link_HasByte
檢查一般接收環狀緩衝區中是否有未讀資料。
語法
u8 Link_HasByte();回傳值
佇列中有資料時傳回 1,否則為 0。
使用條件與限制
八個項目的接收環狀緩衝區可存七個位元組。已滿時會捨棄新位元組並鎖存錯誤 3。收到的零位元組也是有效資料。
不輪詢硬體。請先透過 Link_Poll 或序列處理常式收集已完成的資料。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
result[1]=Link_HasByte();value=77;result[2]=Link_TryReadByte(&value);result[3]=value;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
由 BYTE MASTER 提供時脈。預期 PEER BYTE=42、ZERO READY=1、ZERO BYTE=0。之後 EMPTY READ 也為零,因此須用就緒狀態或 TryRead 的傳回值區分空佇列。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_raw_master.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_raw_master.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_raw_slave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_raw_slave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology pair --run-frames 360 --link-session "name=raw_master|slot=0|rom=.\out\link_raw_master.gb|save_state=.\out\raw_master.kqs" --link-session "name=raw_slave|slot=1|rom=.\out\link_raw_slave.gb|save_state=.\out\raw_slave.kqs"
.\kokura\kokura-cli.exe .\out\link_raw_master.gb --hardware cgb --load-state .\out\raw_master.kqs --run-frames 2 --png .\out\raw_master.png
.\kokura\kokura-cli.exe .\out\link_raw_slave.gb --hardware cgb --load-state .\out\raw_slave.kqs --run-frames 2 --png .\out\raw_slave.png實作與原始碼
kitaqgb/lib/link.h:58
Read the ordinary receive-ready flag without polling hardware.
kitaqgb/lib/link.c:346
u8 Link_HasByte() {
return Link_RxReady;
}Link_HasPacket
檢查共用的完整封包信箱。
語法
u8 Link_HasPacket();回傳值
有未讀封包時傳回 1,否則為 0。
使用條件與限制
封包包含 0xA5、命令、長度、0~24 個有效負載位元組及 XOR 檢查碼。回應為 0x79(ACK,接受)或 0x1F(NAK,拒絕)。檢查碼由命令、長度及有效負載做 XOR 得到。每台主機有一個共用封包信箱,Link4 另為每個對端提供一個信箱。
只讀取旗標,不推進協定。不表示傳送端是否已收到 ACK。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
result[0]=Link_HasPacket();cmd=0;len=0;result[1]=Link_ReadPacket(&cmd,&len,data);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
連接 PACKET MASTER,確認 COMMAND=49、LENGTH=3 及有效負載 7/42/255。ReadPacket 後的 CONSUMED=0 表示信箱現在已空。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_packet_master.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_packet_master.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_packet_slave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_packet_slave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology pair --run-frames 360 --link-session "name=packet_master|slot=0|rom=.\out\link_packet_master.gb|save_state=.\out\packet_master.kqs" --link-session "name=packet_slave|slot=1|rom=.\out\link_packet_slave.gb|save_state=.\out\packet_slave.kqs"
.\kokura\kokura-cli.exe .\out\link_packet_master.gb --hardware cgb --load-state .\out\packet_master.kqs --run-frames 2 --png .\out\packet_master.png
.\kokura\kokura-cli.exe .\out\link_packet_slave.gb --hardware cgb --load-state .\out\packet_slave.kqs --run-frames 2 --png .\out\packet_slave.png實作與原始碼
kitaqgb/lib/link.h:94
Inspect the shared completed-packet flag without advancing the protocol.
kitaqgb/lib/link_packet.c:441
u8 Link_HasPacket() {
return Link_ReceivedPacketReady;
}Link_InitCommon
將共用連線狀態重設為預設的外部時脈模式。
語法
void Link_InitCommon();回傳值
無傳回值。
使用條件與限制
每台主機有一份共用連線狀態。位元組交換採全雙工:一端提供內部時脈,另一端使用外部時脈。一般速度每位元需 512 個時脈,CGB 高速則需 16 個。
初始化會捨棄位元組佇列、封包、對端選擇及錯誤,並停用傳輸與序列 IRQ 來源。不保留進行中的交換。
內部臨界區會追蹤軟體巢狀深度。離開最外層時會啟用 CPU 中斷,因此不可假設原本停用的 IME 狀態會被保留。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
Link_InitCommon();result[0]=Link_IsBusy();result[1]=Link_HasByte();result[2]=Link_LastError();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
檢查初始化、忙碌時拒絕、外部時脈逾時及環狀緩衝區容量。預期 BUSY ERROR=1、TIMEOUT=2、OPEN RX=255、OVERFLOW=3、QUEUE BYTES=7。觀察到 IRQ REQUEST=1 後,教學會在序列 IRQ 來源仍被遮罩時,明確執行處理常式本體。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_control.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_control.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\link_control.gb --hardware cgb --run-frames 330 --png .\out\control.png實作與原始碼
kitaqgb/lib/link.h:43
Reset byte queues, packet mailboxes, cooperative-peer state and errors, then disable serial transfers and serial IRQ delivery. Existing data is discarded.
kitaqgb/lib/link.c:243
void Link_InitCommon() {
u8 i;
Link_Mode = LINK_MODE_SLAVE;
Link_UseInterrupt = 0;
Link_FastClock = LINK_CLOCK_NORMAL;
Link_Busy = 0;
Link_LastRx = 0xFF;
Link_LastTx = 0xFF;
Link_RxReady = 0;
Link_LastErrorCode = LINK_ERR_NONE;
Link_PacketState = LINK_PKT_STATE_IDLE;
Link_TxSeq = 0;
Link_RxSeq = 0;
Link4_ModeState = LINK4_MODE_NONE;
Link4_LocalSlot = LINK4_HOST_SLOT;
Link4_SlotCount = 0;
Link4_SelectedPeer = LINK4_INVALID_SLOT;
Link4_LastRxPeer = LINK4_INVALID_SLOT;
Link4_LastTxPeer = LINK4_INVALID_SLOT;
Link4_LastPacketPeer = LINK4_INVALID_SLOT;
Link_RxHead = 0;
Link_RxTail = 0;
Link_TxHead = 0;
Link_TxTail = 0;
Link_CurrentPacketCmd = 0;
Link_CurrentPacketLen = 0;
Link_CurrentPacketChecksum = 0;
Link_PendingAck = 0;
Link_ReceivedPacketReady = 0;
Link_ReceivedPacketCmd = 0;
Link_ReceivedPacketLen = 0;
Link_ReceivedPacketChecksum = 0;
Link_PacketRetryCount = 0;
Link_PacketTimer = 0;
for (i = 0; i < LINK_RX_QUEUE_SIZE; ++i) Link_RxQueue[(__safe_index u8)i] = 0;
for (i = 0; i < LINK_TX_QUEUE_SIZE; ++i) Link_TxQueue[(__safe_index u8)i] = 0;
for (i = 0; i < LINK4_MAX_PLAYERS; ++i) {
Link4_RxHead[(__safe_index u8)i] = 0;
Link4_RxTail[(__safe_index u8)i] = 0;
Link4_ReceivedPacketReady[(__safe_index u8)i] = 0;
Link4_ReceivedPacketCmd[(__safe_index u8)i] = 0;
Link4_ReceivedPacketLen[(__safe_index u8)i] = 0;
}
for (i = 0; i < (u8)(LINK4_MAX_PLAYERS * LINK_RX_QUEUE_SIZE); ++i) {
Link4_RxQueue[(__safe_index u8)i] = 0;
}
for (i = 0; i < LINK_PKT_MAX_PAYLOAD; ++i) {
Link_CurrentPacketBuf[(__safe_index u8)i] = 0;
Link_ReceivedPacketBuf[(__safe_index u8)i] = 0;
}
for (i = 0; i < (u8)(LINK4_MAX_PLAYERS * LINK_PKT_MAX_PAYLOAD); ++i) {
Link4_ReceivedPacketBuf[(__safe_index u8)i] = 0;
}
LinkHw_WriteSB(0xFF);
LinkHw_WriteSC(0x00);
LinkHw_WriteIF((u8)(LinkHw_ReadIF() & (u8)~LINK_IF_SERIAL));
Link_SetSerialInterruptEnabled(0);
}Link_InitMaster
重設狀態,並將本機設為時脈來源。
語法
void Link_InitMaster();回傳值
無傳回值。
使用條件與限制
每台主機有一份共用連線狀態。位元組交換採全雙工:一端提供內部時脈,另一端使用外部時脈。一般速度每位元需 512 個時脈,CGB 高速則需 16 個。
初始化會捨棄位元組佇列、封包、對端選擇及錯誤,並停用傳輸與序列 IRQ 來源。不保留進行中的交換。
內部臨界區會追蹤軟體巢狀深度。離開最外層時會啟用 CPU 中斷,因此不可假設原本停用的 IME 狀態會被保留。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
Link_InitMaster();Link_SetUseInterrupt(0);Link_SetFastClock(0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
請連接 BYTE SLAVE。傳送 42 並接收 99,接著雙向交換零。RECEIVED=1、PEER BYTE=99、ZERO READY=1、ZERO BYTE=0 可區分有效的零資料與無資料。兩個 CGB 實例在第二次交換使用高速時脈。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_raw_master.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_raw_master.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_raw_slave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_raw_slave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology pair --run-frames 360 --link-session "name=raw_master|slot=0|rom=.\out\link_raw_master.gb|save_state=.\out\raw_master.kqs" --link-session "name=raw_slave|slot=1|rom=.\out\link_raw_slave.gb|save_state=.\out\raw_slave.kqs"
.\kokura\kokura-cli.exe .\out\link_raw_master.gb --hardware cgb --load-state .\out\raw_master.kqs --run-frames 2 --png .\out\raw_master.png
.\kokura\kokura-cli.exe .\out\link_raw_slave.gb --hardware cgb --load-state .\out\raw_slave.kqs --run-frames 2 --png .\out\raw_slave.png實作與原始碼
kitaqgb/lib/link.h:45
Reset link state and select the internal-clock role for subsequent transfers.
kitaqgb/lib/link.c:309
void Link_InitMaster() {
Link_InitCommon();
Link_Mode = LINK_MODE_MASTER;
}Link_InitSlave
重設狀態並選擇外部時脈通訊。
語法
void Link_InitSlave();回傳值
無傳回值。
使用條件與限制
每台主機有一份共用連線狀態。位元組交換採全雙工:一端提供內部時脈,另一端使用外部時脈。一般速度每位元需 512 個時脈,CGB 高速則需 16 個。
初始化會捨棄位元組佇列、封包、對端選擇及錯誤,並停用傳輸與序列 IRQ 來源。不保留進行中的交換。
內部臨界區會追蹤軟體巢狀深度。離開最外層時會啟用 CPU 中斷,因此不可假設原本停用的 IME 狀態會被保留。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
Link_InitSlave();result[0]=Link_BeginTransfer(99);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
由 BYTE MASTER 提供時脈。預期 PEER BYTE=42、ZERO READY=1、ZERO BYTE=0。之後 EMPTY READ 也為零,因此須用就緒狀態或 TryRead 的傳回值區分空佇列。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_raw_master.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_raw_master.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_raw_slave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_raw_slave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology pair --run-frames 360 --link-session "name=raw_master|slot=0|rom=.\out\link_raw_master.gb|save_state=.\out\raw_master.kqs" --link-session "name=raw_slave|slot=1|rom=.\out\link_raw_slave.gb|save_state=.\out\raw_slave.kqs"
.\kokura\kokura-cli.exe .\out\link_raw_master.gb --hardware cgb --load-state .\out\raw_master.kqs --run-frames 2 --png .\out\raw_master.png
.\kokura\kokura-cli.exe .\out\link_raw_slave.gb --hardware cgb --load-state .\out\raw_slave.kqs --run-frames 2 --png .\out\raw_slave.png實作與原始碼
kitaqgb/lib/link.h:47
Reset link state and select the external-clock role for subsequent transfers.
kitaqgb/lib/link.c:315
void Link_InitSlave() {
Link_InitCommon();
Link_Mode = LINK_MODE_SLAVE;
}Link_IsBusy
輪詢一次完成狀態,再回報交換是否仍在進行。
語法
u8 Link_IsBusy();回傳值
忙碌時傳回 1,否則為 0。
使用條件與限制
八個項目的接收環狀緩衝區可存七個位元組。已滿時會捨棄新位元組並鎖存錯誤 3。收到的零位元組也是有效資料。
這不是被動查詢;已完成的 SB 位元組會加入佇列,可能改變資料就緒與錯誤狀態。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
result[3]=Link_IsBusy();result[4]=Link_HasByte();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
請連接 BYTE SLAVE。傳送 42 並接收 99,接著雙向交換零。RECEIVED=1、PEER BYTE=99、ZERO READY=1、ZERO BYTE=0 可區分有效的零資料與無資料。兩個 CGB 實例在第二次交換使用高速時脈。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_raw_master.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_raw_master.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_raw_slave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_raw_slave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology pair --run-frames 360 --link-session "name=raw_master|slot=0|rom=.\out\link_raw_master.gb|save_state=.\out\raw_master.kqs" --link-session "name=raw_slave|slot=1|rom=.\out\link_raw_slave.gb|save_state=.\out\raw_slave.kqs"
.\kokura\kokura-cli.exe .\out\link_raw_master.gb --hardware cgb --load-state .\out\raw_master.kqs --run-frames 2 --png .\out\raw_master.png
.\kokura\kokura-cli.exe .\out\link_raw_slave.gb --hardware cgb --load-state .\out\raw_slave.kqs --run-frames 2 --png .\out\raw_slave.png實作與原始碼
kitaqgb/lib/link.h:56
Poll once before returning busy state, so this query may collect a completed byte.
kitaqgb/lib/link.c:340
u8 Link_IsBusy() {
Link_Poll();
return Link_Busy;
}Link_LastError
讀取最近鎖存的連線錯誤,不將其清除。
語法
u8 Link_LastError();回傳值
傳回目前錯誤碼,範圍為 0~5。
使用條件與限制
錯誤碼為 0=無、1=忙碌、2=逾時、3=接收溢位、4=設定/協定無效、5=伴隨類似斷線回應的 ACK 逾時。啟動/設定呼叫以 0 表示成功,接收/取出呼叫以 1 表示成功。成功呼叫不會清除已鎖存的錯誤。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
result[2]=Link_LastError();Link_ClearError();result[3]=Link_LastError();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
傳送命令 49 與有效負載 7/42/255,然後修改來源陣列。QUEUED=0 表示接受傳送,SECOND SEND=1 表示拒絕第二次啟動。忙碌錯誤會保留至 ClearError。接收端的 PAYLOAD 2=42 證明排入佇列的有效負載是獨立副本。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_packet_master.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_packet_master.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_packet_slave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_packet_slave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology pair --run-frames 360 --link-session "name=packet_master|slot=0|rom=.\out\link_packet_master.gb|save_state=.\out\packet_master.kqs" --link-session "name=packet_slave|slot=1|rom=.\out\link_packet_slave.gb|save_state=.\out\packet_slave.kqs"
.\kokura\kokura-cli.exe .\out\link_packet_master.gb --hardware cgb --load-state .\out\packet_master.kqs --run-frames 2 --png .\out\packet_master.png
.\kokura\kokura-cli.exe .\out\link_packet_slave.gb --hardware cgb --load-state .\out\packet_slave.kqs --run-frames 2 --png .\out\packet_slave.png實作與原始碼
kitaqgb/lib/link.h:60
Return the latest latched error without clearing it.
kitaqgb/lib/link.c:351
u8 Link_LastError() {
return Link_LastErrorCode;
}Link_OnSerialIRQ
從已辨識出序列請求的處理常式收集完成的位元組。
語法
void Link_OnSerialIRQ();回傳值
無傳回值。
使用條件與限制
八個項目的接收環狀緩衝區可存七個位元組。已滿時會捨棄新位元組並鎖存錯誤 3。收到的零位元組也是有效資料。
內部臨界區會追蹤軟體巢狀深度。離開最外層時會啟用 CPU 中斷,因此不可假設原本停用的 IME 狀態會被保留。
函式不檢查 SC 是否完成。序列傳輸中不可從無關的計時器中斷呼叫。範例在真正的 IF.serial 請求後,保持序列 CPU IRQ 來源被遮罩,再明確執行;測試的是本體,不是向量安裝。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
lesson_delay(2);result[14]=(IF_REG&8)!=0;Link_OnSerialIRQ();result[15]=Link_HasByte();result[16]=Link_ReadByte();result[17]=(IF_REG&8)!=0;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
檢查初始化、忙碌時拒絕、外部時脈逾時及環狀緩衝區容量。預期 BUSY ERROR=1、TIMEOUT=2、OPEN RX=255、OVERFLOW=3、QUEUE BYTES=7。觀察到 IRQ REQUEST=1 後,教學會在序列 IRQ 來源仍被遮罩時,明確執行處理常式本體。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_control.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_control.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\link_control.gb --hardware cgb --run-frames 330 --png .\out\control.png實作與原始碼
kitaqgb/lib/link.h:74
Acknowledge serial IRQ and finish a software-busy transfer. Call this from the actual serial interrupt handler, not an unrelated interrupt.
kitaqgb/lib/link.c:410
void Link_OnSerialIRQ() {
LinkHw_WriteIF((u8)(LinkHw_ReadIF() & (u8)~LINK_IF_SERIAL));
if (Link_Busy == 0) return;
Link_FinishTransfer();
}Link_Poll
只有在 SC 清除啟動位元後,才收集原先進行中的傳輸,將收到的位元組排入佇列。
語法
void Link_Poll();回傳值
無傳回值。
使用條件與限制
八個項目的接收環狀緩衝區可存七個位元組。已滿時會捨棄新位元組並鎖存錯誤 3。收到的零位元組也是有效資料。
呼叫不會阻塞。軟體狀態為閒置時不做任何事,也未實作逾時。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
for(i=0;i<24;i++){Link_Poll();if(Link_HasByte())break;m_wait();}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
由 BYTE MASTER 提供時脈。預期 PEER BYTE=42、ZERO READY=1、ZERO BYTE=0。之後 EMPTY READ 也為零,因此須用就緒狀態或 TryRead 的傳回值區分空佇列。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_raw_master.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_raw_master.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_raw_slave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_raw_slave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology pair --run-frames 360 --link-session "name=raw_master|slot=0|rom=.\out\link_raw_master.gb|save_state=.\out\raw_master.kqs" --link-session "name=raw_slave|slot=1|rom=.\out\link_raw_slave.gb|save_state=.\out\raw_slave.kqs"
.\kokura\kokura-cli.exe .\out\link_raw_master.gb --hardware cgb --load-state .\out\raw_master.kqs --run-frames 2 --png .\out\raw_master.png
.\kokura\kokura-cli.exe .\out\link_raw_slave.gb --hardware cgb --load-state .\out\raw_slave.kqs --run-frames 2 --png .\out\raw_slave.png實作與原始碼
kitaqgb/lib/link.h:68
Collect a pending transfer only after hardware clears the SC start bit.
kitaqgb/lib/link.c:388
void Link_Poll() {
if (Link_Busy == 0) return;
if ((LinkHw_ReadSC() & LINK_SC_START) != 0) return;
Link_FinishTransfer();
}Link_PollPacket
解析接收位元組,啟動下一個送出位元組或 ACK,並推進逾時/重試狀態。
語法
void Link_PollPacket();回傳值
無傳回值。
使用條件與限制
封包包含 0xA5、命令、長度、0~24 個有效負載位元組及 XOR 檢查碼。回應為 0x79(ACK,接受)或 0x1F(NAK,拒絕)。檢查碼由命令、長度及有效負載做 XOR 得到。每台主機有一個共用封包信箱,Link4 另為每個對端提供一個信箱。
兩端都須持續輪詢。逾時計算的是沒有進展的 90 次呼叫,不是硬體影格。僅為 ACK 提供時脈而傳送 0xFF 不會延長期限;傳送最多嘗試三次。重試可能造成重複送達,若命令必須恰好執行一次,請加入應用層識別碼。
ReadByte 類原始讀取也會消耗相同的一般環狀緩衝區,可能取走封包的一部分。請勿混用原始讀取與封包接收。
Link4 將每個接收位元組同時複製到一般環狀緩衝區與對端專用環狀緩衝區。讀取其中一個不會清空另一個。封包輪詢會消耗一般緩衝區;也須定期丟棄未使用的對端原始位元組,避免溢位。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
Link_InitSlave();for(i=0;i<120;i++){Link_PollPacket();m_wait();}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
連接 PACKET MASTER,確認 COMMAND=49、LENGTH=3 及有效負載 7/42/255。ReadPacket 後的 CONSUMED=0 表示信箱現在已空。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_packet_master.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_packet_master.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_packet_slave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_packet_slave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology pair --run-frames 360 --link-session "name=packet_master|slot=0|rom=.\out\link_packet_master.gb|save_state=.\out\packet_master.kqs" --link-session "name=packet_slave|slot=1|rom=.\out\link_packet_slave.gb|save_state=.\out\packet_slave.kqs"
.\kokura\kokura-cli.exe .\out\link_packet_master.gb --hardware cgb --load-state .\out\packet_master.kqs --run-frames 2 --png .\out\packet_master.png
.\kokura\kokura-cli.exe .\out\link_packet_slave.gb --hardware cgb --load-state .\out\packet_slave.kqs --run-frames 2 --png .\out\packet_slave.png使用範例
Link_InitMaster();result[0]=Link_SendPacket(0,0,7);
// An absent peer cannot acknowledge the packet, despite completed FF exchanges.
for(ticks=0;ticks<300;ticks++){Link_PollPacket();m_wait();}
result[1]=Link_LastError();Link_Cancel();result[2]=Link_IsBusy();Link_ClearError();result[3]=Link_LastError();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
在未連接對端時傳送。內部時脈會讓位元組傳輸完成,但不會收到 ACK;重試後 NO ACK ERROR=5。Cancel 後為 CANCEL BUSY=0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_deadline.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_deadline.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\link_deadline.gb --hardware cgb --run-frames 330 --png .\out\deadline.png實作與原始碼
kitaqgb/lib/link.h:92
Drain received bytes, advance one outgoing exchange and update the retry timer. Timeout ticks count calls without progress, not hardware frames; call with a controlled cadence and avoid mixing raw reads with packet consumption.
kitaqgb/lib/link_packet.c:400
void Link_PollPacket() {
u8 progress = 0;
u8 previous_state;
u8 value = 0;
Link_Poll();
if (Link_PacketState == LINK_PKT_STATE_ERROR) {
Link_PacketGoIdle();
return;
}
while (Link_TryReadByte(&value) != 0) {
if (Link_PacketConsumeByte(value) != 0) progress = 1;
}
if (Link_PacketState == LINK_PKT_STATE_SEND_ACK) {
if (Link_PacketStartAckTransfer() != 0) progress = 1;
} else if (Link_PacketIsSendState() != 0) {
// Clocking an ACK is not protocol progress: a missing peer must time out.
previous_state = Link_PacketState;
if (Link_PacketStartNextTransfer() != 0 && previous_state != LINK_PKT_STATE_WAIT_ACK) progress = 1;
} else {
if (Link_PacketStartReceiveTransfer() != 0) progress = 1;
}
if (Link_PacketState == LINK_PKT_STATE_IDLE) {
Link_PacketTimer = 0;
return;
}
if (progress != 0) {
Link_PacketTimer = LINK_PKT_TIMEOUT_TICKS;
return;
}
if (Link_PacketTimer != 0) Link_PacketTimer--;
if (Link_PacketTimer == 0) Link_PacketHandleTimeout();
}Link_ReadByte
傳回從一般接收環狀緩衝區取出的一個位元組。
語法
u8 Link_ReadByte();回傳值
傳回接收的位元組;佇列為空時也傳回零。
使用條件與限制
八個項目的接收環狀緩衝區可存七個位元組。已滿時會捨棄新位元組並鎖存錯誤 3。收到的零位元組也是有效資料。
內部臨界區會追蹤軟體巢狀深度。離開最外層時會啟用 CPU 中斷,因此不可假設原本停用的 IME 狀態會被保留。
只靠傳回值無法區分收到零與空佇列。請使用 TryReadByte 的成功旗標,或讀取前先用 HasByte 檢查。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
result[6]=Link_HasByte();result[7]=Link_ReadByte();result[8]=Link_ReadByte();result[9]=Link_LastError();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
由 BYTE MASTER 提供時脈。預期 PEER BYTE=42、ZERO READY=1、ZERO BYTE=0。之後 EMPTY READ 也為零,因此須用就緒狀態或 TryRead 的傳回值區分空佇列。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_raw_master.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_raw_master.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_raw_slave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_raw_slave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology pair --run-frames 360 --link-session "name=raw_master|slot=0|rom=.\out\link_raw_master.gb|save_state=.\out\raw_master.kqs" --link-session "name=raw_slave|slot=1|rom=.\out\link_raw_slave.gb|save_state=.\out\raw_slave.kqs"
.\kokura\kokura-cli.exe .\out\link_raw_master.gb --hardware cgb --load-state .\out\raw_master.kqs --run-frames 2 --png .\out\raw_master.png
.\kokura\kokura-cli.exe .\out\link_raw_slave.gb --hardware cgb --load-state .\out\raw_slave.kqs --run-frames 2 --png .\out\raw_slave.png實作與原始碼
kitaqgb/lib/link.h:80
Pop one byte, returning zero when empty. Use Link_TryReadByte when a received zero byte must be distinguished from an empty queue.
kitaqgb/lib/link.c:427
u8 Link_ReadByte() {
u8 value = 0;
if (Link_PopRxByte(&value) != 0) return value;
return 0;
}Link_ReadPacket
複製完整封包,並從共用信箱取走它。
語法
u8 __stackcall Link_ReadPacket(u8 *cmd, u8 *len, u8 *dst);參數
cmd可寫入的命令位元組;null 表示省略此輸出。
len可寫入的長度位元組,範圍為 0~24;null 表示省略此輸出。
dst可寫入且容納 24 位元組的有效負載緩衝區;null 表示捨棄有效負載。
回傳值
取出時傳回 1,為空時傳回 0;空讀取不變更輸出。
使用條件與限制
沒有目的地容量參數。使用 dst 時須提供 24 個可寫入位元組。cmd、len、dst 可各自為 null。須將信箱檢查與取用序列化,避免與其他程式碼或中斷同時操作。
Link4 模式下也會清除與此共用封包對應的對端信箱。其他對端信箱仍可使用。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
result[0]=Link_HasPacket();cmd=0;len=0;result[1]=Link_ReadPacket(&cmd,&len,data);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
連接 PACKET MASTER,確認 COMMAND=49、LENGTH=3 及有效負載 7/42/255。ReadPacket 後的 CONSUMED=0 表示信箱現在已空。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_packet_master.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_packet_master.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_packet_slave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_packet_slave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology pair --run-frames 360 --link-session "name=packet_master|slot=0|rom=.\out\link_packet_master.gb|save_state=.\out\packet_master.kqs" --link-session "name=packet_slave|slot=1|rom=.\out\link_packet_slave.gb|save_state=.\out\packet_slave.kqs"
.\kokura\kokura-cli.exe .\out\link_packet_master.gb --hardware cgb --load-state .\out\packet_master.kqs --run-frames 2 --png .\out\packet_master.png
.\kokura\kokura-cli.exe .\out\link_packet_slave.gb --hardware cgb --load-state .\out\packet_slave.kqs --run-frames 2 --png .\out\packet_slave.png實作與原始碼
kitaqgb/lib/link.h:98
Consume the shared packet mailbox and its matching peer flag. Any output may be null; a nonnull destination needs room for the received payload because there is no destination-capacity argument.
kitaqgb/lib/link_packet.c:448
u8 __stackcall Link_ReadPacket(u8 *cmd, u8 *len, u8 *dst) {
u8 i;
u8 peer_slot = Link4_LastPacketPeer;
if (Link_ReceivedPacketReady == 0) return 0;
if (cmd != 0) *cmd = Link_ReceivedPacketCmd;
if (len != 0) *len = Link_ReceivedPacketLen;
if (dst != 0) {
for (i = 0; i < Link_ReceivedPacketLen; ++i) {
dst[(__safe_index u8)i] = Link_ReceivedPacketBuf[(__safe_index u8)i];
}
}
Link_ReceivedPacketReady = 0;
if (Link4_IsValidRemoteSlotInternal(peer_slot) != 0) {
Link4_ReceivedPacketReady[(__safe_index u8)peer_slot] = 0;
}
Link4_LastPacketPeer = LINK4_INVALID_SLOT;
return 1;
}Link_SendPacket
將有效負載複製到內部持有的儲存空間,並排程封包傳送。
語法
u8 __stackcall Link_SendPacket(const u8 *data, u8 len, u8 cmd);參數
data可讀取 len 個位元組的來源;只有 len 為零時才可為 null。
len有效負載長度,以位元組為單位,範圍為 0~24。
cmd應用程式定義的八位元命令。
回傳值
接受時傳回 0,封包狀態忙碌時傳回 1,長度或指標無效時傳回 4。
使用條件與限制
錯誤碼為 0=無、1=忙碌、2=逾時、3=接收溢位、4=設定/協定無效、5=伴隨類似斷線回應的 ACK 逾時。啟動/設定呼叫以 0 表示成功,接收/取出呼叫以 1 表示成功。成功呼叫不會清除已鎖存的錯誤。
封包包含 0xA5、命令、長度、0~24 個有效負載位元組及 XOR 檢查碼。回應為 0x79(ACK,接受)或 0x1F(NAK,拒絕)。檢查碼由命令、長度及有效負載做 XOR 得到。每台主機有一個共用封包信箱,Link4 另為每個對端提供一個信箱。
兩端都須持續輪詢。逾時計算的是沒有進展的 90 次呼叫,不是硬體影格。僅為 ACK 提供時脈而傳送 0xFF 不會延長期限;傳送最多嘗試三次。重試可能造成重複送達,若命令必須恰好執行一次,請加入應用層識別碼。
零表示已排入佇列,不代表對端已接收或確認。接受後可重複使用來源陣列。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
result[0]=Link_SendPacket(data,3,0x31);data[1]=0;result[1]=Link_SendPacket(data,3,0x32);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
傳送命令 49 與有效負載 7/42/255,然後修改來源陣列。QUEUED=0 表示接受傳送,SECOND SEND=1 表示拒絕第二次啟動。忙碌錯誤會保留至 ClearError。接收端的 PAYLOAD 2=42 證明排入佇列的有效負載是獨立副本。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_packet_master.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_packet_master.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_packet_slave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_packet_slave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology pair --run-frames 360 --link-session "name=packet_master|slot=0|rom=.\out\link_packet_master.gb|save_state=.\out\packet_master.kqs" --link-session "name=packet_slave|slot=1|rom=.\out\link_packet_slave.gb|save_state=.\out\packet_slave.kqs"
.\kokura\kokura-cli.exe .\out\link_packet_master.gb --hardware cgb --load-state .\out\packet_master.kqs --run-frames 2 --png .\out\packet_master.png
.\kokura\kokura-cli.exe .\out\link_packet_slave.gb --hardware cgb --load-state .\out\packet_slave.kqs --run-frames 2 --png .\out\packet_slave.png實作與原始碼
kitaqgb/lib/link.h:88
Validate payload size and idle packet state, copy payload bytes into owned storage and schedule transmission. Return success means queued, not acknowledged; keep polling to progress the exchange and inspect the error latch.
kitaqgb/lib/link_packet.c:361
u8 __stackcall Link_SendPacket(const u8 *data, u8 len, u8 cmd) {
u8 i;
u8 checksum = (u8)(cmd ^ len);
if (len > LINK_PKT_MAX_PAYLOAD) {
Link_SetErrorInternal(LINK_ERR_PROTOCOL);
return LINK_ERR_PROTOCOL;
}
if (len != 0 && data == 0) {
Link_SetErrorInternal(LINK_ERR_PROTOCOL);
return LINK_ERR_PROTOCOL;
}
if (Link_PacketState != LINK_PKT_STATE_IDLE || Link_PendingAck != 0) {
Link_SetErrorInternal(LINK_ERR_BUSY);
return LINK_ERR_BUSY;
}
Link_CurrentPacketCmd = cmd;
Link_CurrentPacketLen = len;
for (i = 0; i < len; ++i) {
Link_CurrentPacketBuf[(__safe_index u8)i] = data[(__safe_index u8)i];
checksum = (u8)(checksum ^ data[(__safe_index u8)i]);
}
Link_CurrentPacketChecksum = checksum;
Link_TxSeq = 0;
Link_RxSeq = 0;
Link_PacketRetryCount = 0;
Link_PacketTimer = LINK_PKT_TIMEOUT_TICKS;
Link_PacketState = LINK_PKT_STATE_SEND_SYNC;
return LINK_ERR_NONE;
}Link_SetFastClock
選擇後續內部時脈傳輸是否使用 CGB 高速時脈位元。
語法
void __stackcall Link_SetFastClock(u8 on);參數
on零要求一般速度,非零要求高速。
回傳值
無傳回值。
使用條件與限制
每台主機有一份共用連線狀態。位元組交換採全雙工:一端提供內部時脈,另一端使用外部時脈。一般速度每位元需 512 個時脈,CGB 高速則需 16 個。
不會變更進行中的傳輸。外部時脈傳輸忽略此設定。不檢查硬體支援,請讓範例兩端使用相符的硬體模式。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
lesson_delay(12);Link_SetFastClock(__cgb_is_cgb());result[5]=Link_BeginTransfer(0);value=77;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
請連接 BYTE SLAVE。傳送 42 並接收 99,接著雙向交換零。RECEIVED=1、PEER BYTE=99、ZERO READY=1、ZERO BYTE=0 可區分有效的零資料與無資料。兩個 CGB 實例在第二次交換使用高速時脈。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_raw_master.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_raw_master.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_raw_slave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_raw_slave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology pair --run-frames 360 --link-session "name=raw_master|slot=0|rom=.\out\link_raw_master.gb|save_state=.\out\raw_master.kqs" --link-session "name=raw_slave|slot=1|rom=.\out\link_raw_slave.gb|save_state=.\out\raw_slave.kqs"
.\kokura\kokura-cli.exe .\out\link_raw_master.gb --hardware cgb --load-state .\out\raw_master.kqs --run-frames 2 --png .\out\raw_master.png
.\kokura\kokura-cli.exe .\out\link_raw_slave.gb --hardware cgb --load-state .\out\raw_slave.kqs --run-frames 2 --png .\out\raw_slave.png實作與原始碼
kitaqgb/lib/link.h:53
Select the fast-clock bit for future master transfers; this does not restart an active transfer or verify that the hardware supports CGB fast mode.
kitaqgb/lib/link.c:334
void __stackcall Link_SetFastClock(u8 on) {
if (on != 0) Link_FastClock = LINK_CLOCK_FAST;
else Link_FastClock = LINK_CLOCK_NORMAL;
}Link_SetUseInterrupt
設定序列中斷啟用位元,並清除待處理的序列請求。
語法
void __stackcall Link_SetUseInterrupt(u8 on);參數
on零表示停用,任何非零值表示啟用。
回傳值
無傳回值。
使用條件與限制
內部臨界區會追蹤軟體巢狀深度。離開最外層時會啟用 CPU 中斷,因此不可假設原本停用的 IME 狀態會被保留。
請另外在向量 0058h 安裝處理常式;此函式庫不會註冊。範例在傳輸前再次遮罩來源,不測試 CPU 中斷入口程式。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
Link_SetUseInterrupt(1);result[3]=(IE_REG&8)!=0;Link_SetUseInterrupt(0);result[4]=(IE_REG&8)!=0;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
檢查初始化、忙碌時拒絕、外部時脈逾時及環狀緩衝區容量。預期 BUSY ERROR=1、TIMEOUT=2、OPEN RX=255、OVERFLOW=3、QUEUE BYTES=7。觀察到 IRQ REQUEST=1 後,教學會在序列 IRQ 來源仍被遮罩時,明確執行處理常式本體。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_control.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_control.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\link_control.gb --hardware cgb --run-frames 330 --png .\out\control.png實作與原始碼
kitaqgb/lib/link.h:50
Enable or disable serial IRQ delivery and clear its pending flag. Enabling does not install the handler. Leaving its outer critical section enables CPU interrupts.
kitaqgb/lib/link.c:322
void __stackcall Link_SetUseInterrupt(u8 on) {
if (on != 0) {
Link_UseInterrupt = 1;
Link_SetSerialInterruptEnabled(1);
} else {
Link_UseInterrupt = 0;
Link_SetSerialInterruptEnabled(0);
}
}Link_TryReadByte
不等待,直接從一般接收環狀緩衝區取出一個位元組。
語法
u8 __stackcall Link_TryReadByte(u8 *out);參數
out可寫入的位元組目的地;null 表示捨棄該位元組。
回傳值
取出成功傳回 1,為空時傳回 0;空讀取不變更 out。
使用條件與限制
八個項目的接收環狀緩衝區可存七個位元組。已滿時會捨棄新位元組並鎖存錯誤 3。收到的零位元組也是有效資料。
內部臨界區會追蹤軟體巢狀深度。離開最外層時會啟用 CPU 中斷,因此不可假設原本停用的 IME 狀態會被保留。
Link4 將每個接收位元組同時複製到一般環狀緩衝區與對端專用環狀緩衝區。讀取其中一個不會清空另一個。封包輪詢會消耗一般緩衝區;也須定期丟棄未使用的對端原始位元組,避免溢位。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
result[1]=Link_HasByte();value=77;result[2]=Link_TryReadByte(&value);result[3]=value;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
由 BYTE MASTER 提供時脈。預期 PEER BYTE=42、ZERO READY=1、ZERO BYTE=0。之後 EMPTY READ 也為零,因此須用就緒狀態或 TryRead 的傳回值區分空佇列。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_raw_master.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_raw_master.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_raw_slave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_raw_slave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology pair --run-frames 360 --link-session "name=raw_master|slot=0|rom=.\out\link_raw_master.gb|save_state=.\out\raw_master.kqs" --link-session "name=raw_slave|slot=1|rom=.\out\link_raw_slave.gb|save_state=.\out\raw_slave.kqs"
.\kokura\kokura-cli.exe .\out\link_raw_master.gb --hardware cgb --load-state .\out\raw_master.kqs --run-frames 2 --png .\out\raw_master.png
.\kokura\kokura-cli.exe .\out\link_raw_slave.gb --hardware cgb --load-state .\out\raw_slave.kqs --run-frames 2 --png .\out\raw_slave.png實作與原始碼
kitaqgb/lib/link.h:77
Pop the ordinary receive queue without waiting or polling hardware; null discards a byte.
kitaqgb/lib/link.c:417
u8 __stackcall Link_TryReadByte(u8 *out) {
return Link_PopRxByte(out);
}Link_WaitByte
立即輪詢,再以 VBlank 為等待上限的基準等候一個位元組。
語法
u8 __stackcall Link_WaitByte(u16 timeout_frames, u8 *out);參數
timeout_framesVBlank 等待次數上限。即使為零,仍會先輪詢並讀取一次。
out必須提供可寫入位元組。null 會立即傳回零,不變更已鎖存錯誤。
回傳值
收到資料傳回 1,逾時或輸出為 null 時傳回 0。
使用條件與限制
八個項目的接收環狀緩衝區可存七個位元組。已滿時會捨棄新位元組並鎖存錯誤 3。收到的零位元組也是有效資料。
請在 LCD 運作時使用。逾時會鎖存錯誤 2,且不變更 out。傳輸本身不會取消;若放棄傳輸,請呼叫 Cancel。
畫面來自 KOKURA。多端點範例會檢查相互連接的模擬器實例數值,並從最後儲存的狀態擷取畫面。這些檢查不證明實體線材或四人轉接器的行為。
請在包含 kitaqgb、kokura、kitaq-docs 的上層資料夾執行這些 PowerShell 命令。啟動連線工作階段前,先建置所有參與的 ROM。Link4 須將產生的符號中繼資料保留在 ROM 旁。若以 DMG 執行,請將所有命令中的 --cgb=cgb 改為 --cgb=dmg,--hardware cgb 改為 --hardware dmg。
使用範例
value=77;result[9]=Link_WaitByte(2,&value);result[10]=value;result[11]=Link_LastError();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
檢查初始化、忙碌時拒絕、外部時脈逾時及環狀緩衝區容量。預期 BUSY ERROR=1、TIMEOUT=2、OPEN RX=255、OVERFLOW=3、QUEUE BYTES=7。觀察到 IRQ REQUEST=1 後,教學會在序列 IRQ 來源仍被遮罩時,明確執行處理常式本體。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_control.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_control.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\link_control.gb --hardware cgb --run-frames 330 --png .\out\control.png實作與原始碼
kitaqgb/lib/link.h:83
Require an output pointer, poll immediately, then wait at most timeout_frames VBlanks for a byte. Zero timeout still performs the initial poll and read.
kitaqgb/lib/link.c:435
u8 __stackcall Link_WaitByte(u16 timeout_frames, u8 *out) {
u16 waited = 0;
if (out == 0) return 0;
Link_Poll();
if (Link_TryReadByte(out) != 0) return 1;
while (waited < timeout_frames) {
__wait_vblank();
waited++;
Link_Poll();
if (Link_TryReadByte(out) != 0) return 1;
}
Link_SetErrorInternal(LINK_ERR_TIMEOUT);
return 0;
}link_dmg07.h — DMG-07 外部時脈通訊
DMG-07 將各主機提交的一個位元組廣播給四位玩家。此函式庫處理探索、玩家 1 啟動、延遲封包廣播及對齊的重新啟動控制。EXCHANGE 示範四機交換,NO ADAPTER 示範逾時,OVERFLOW 示範未讀資料,RESTART 示範復原。
函式庫玩家編號為 1..4,零表示尚未發現。連線遮罩位元 0..3 對應玩家 1..4。KOKURA --link-session 的 slot 值為 0..3,與 ROM API 是不同編號慣例。
此驅動程式獨占序列埠。不可同時執行一般 Link 或 Link4;link_hwregs_gb.c 與 link_dmg07.c 各包含一次。外部時脈由轉接器提供;驅動程式不選取 CGB 高速序列模式。
每影格持續重複呼叫 Poll,TickFrame 則恰好呼叫一次。每個 VBlank 只 Poll 一次,無法在轉接器的位元組之間重新準備埠。共用標頭的 d_poll 偵測進入 LY >= 144,呼叫一次 TickFrame。請序列化兩項操作,避免 ISR 與主迴圈競爭。
SIZE=1 時,各主機提交一個位元組,四位元組廣播依玩家 1..4 排列。首次廣播會被丟棄;後續廣播包含上一封包提交的值。四個位元組全為 0xFF 的廣播保留為重新啟動指示。
LinkDmg07_ClearError
將最後錯誤碼重設為零。
語法
void LinkDmg07_ClearError();回傳值
無傳回值。
使用條件與限制
SilenceFrames 與診斷計數器飽和於 255。Init 重設全部計數;一般通訊協定重新啟動保留診斷計數器。ClearError 只清除錯誤碼。
保留接收資料、階段、連線資訊與逾時鎖存。僅此呼叫不會重新連線或恢復接收。
畫面擷取自 KOKURA 的 DMG-07 模型。各主機獨立執行,並比對傳送與接收值。實體轉接器/線材的電氣行為及時序尚未驗證。CGB 畫面以藍色顯示數值。
將 kitaqgb、kokura、kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。四主機範例會在四個工作階段啟動相同 ROM。DMG 檢查時,請將所有 --cgb=cgb 換成 --cgb=dmg,--hardware cgb 換成 --hardware dmg。
使用範例
LinkDmg07_ClearError();result[21]=LinkDmg07_LastError();result[22]=LinkDmg07_GetErrorCount();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
保留第一個有效封包不讀,直到另一封包到達。預期 SENT SEQ=3、PACKET SEQ=2、ERROR=6,讀取傳回最新的 33/34/35/36。ClearError 使 CLEAR ERROR 歸零,ErrorCount 仍為一。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_overflow.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_overflow.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_overflow.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_overflow.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_overflow.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_overflow.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_overflow.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_overflow.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_overflow.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_overflow.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png實作與原始碼
kitaqgb/lib/link_dmg07.h:125
Clear only the latest error code, preserving counters and protocol state.
kitaqgb/lib/link_dmg07.c:541
void LinkDmg07_ClearError() {
LinkDmg07_LastErrorCode = LINK_DMG07_ERR_NONE;
}LinkDmg07_ConsumePingStatus
消費並清除探索完成通知。
語法
u8 LinkDmg07_ConsumePingStatus();回傳值
成功消費時傳回 1,否則為 0。
使用條件與限制
只清除通知,保留 slot、mask 與 LastStatus。新通知到達前,後續呼叫傳回零。
畫面擷取自 KOKURA 的 DMG-07 模型。各主機獨立執行,並比對傳送與接收值。實體轉接器/線材的電氣行為及時序尚未驗證。CGB 畫面以藍色顯示數值。
將 kitaqgb、kokura、kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。四主機範例會在四個工作階段啟動相同 ROM。DMG 檢查時,請將所有 --cgb=cgb 換成 --cgb=dmg,--hardware cgb 換成 --hardware dmg。
使用範例
result[3]=LinkDmg07_ConsumePingStatus();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
四台主機執行相同 ROM,各自傳送 32 加上玩家編號。每台都收到 PLAYER 1..4 = 33/34/35/36。第一個有效廣播記錄 SENT SEQ=2、PACKET SEQ=1,顯示一個封包的延遲。畫面凍結此觀察結果;實際遊戲之後仍持續輪詢。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png實作與原始碼
kitaqgb/lib/link_dmg07.h:71
Clear and report the completed-discovery flag; return zero if no new status exists.
kitaqgb/lib/link_dmg07.c:418
u8 LinkDmg07_ConsumePingStatus() {
if (LinkDmg07_PingStatusReady == 0) return 0;
LinkDmg07_PingStatusReady = 0;
return 1;
}LinkDmg07_GetConnectedMask
讀取最後接受狀態中的四位元玩家集合。
語法
u8 LinkDmg07_GetConnectedMask();回傳值
位元 0..3 表示已連線玩家。尚未發現為零,四位玩家連線為 15。
使用條件與限制
函式庫玩家編號為 1..4,零表示尚未發現。連線遮罩位元 0..3 對應玩家 1..4。KOKURA --link-session 的 slot 值為 0..3,與 ROM API 是不同編號慣例。
傳回快取的探索狀態,不探測實體接線。傳輸期間反映最近接受的通知。
畫面擷取自 KOKURA 的 DMG-07 模型。各主機獨立執行,並比對傳送與接收值。實體轉接器/線材的電氣行為及時序尚未驗證。CGB 畫面以藍色顯示數值。
將 kitaqgb、kokura、kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。四主機範例會在四個工作階段啟動相同 ROM。DMG 檢查時,請將所有 --cgb=cgb 換成 --cgb=dmg,--hardware cgb 換成 --hardware dmg。
使用範例
result[1]=LinkDmg07_GetConnectedMask();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
四台主機執行相同 ROM,各自傳送 32 加上玩家編號。每台都收到 PLAYER 1..4 = 33/34/35/36。第一個有效廣播記錄 SENT SEQ=2、PACKET SEQ=1,顯示一個封包的延遲。畫面凍結此觀察結果;實際遊戲之後仍持續輪詢。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png實作與原始碼
kitaqgb/lib/link_dmg07.h:65
Normalized mask: bit 0 is player 1, ..., bit 3 is player 4.
kitaqgb/lib/link_dmg07.c:403
u8 LinkDmg07_GetConnectedMask() {
return LinkDmg07_ConnectedMask;
}LinkDmg07_GetDisconnectCount
讀取已記錄的斷線事件:曾看見轉接器後靜默,或玩家從探索狀態消失。
語法
u8 LinkDmg07_GetDisconnectCount();回傳值
傳回 0..255 次事件,不是失去連線的玩家人數。
使用條件與限制
SilenceFrames 與診斷計數器飽和於 255。Init 重設全部計數;一般通訊協定重新啟動保留診斷計數器。ClearError 只清除錯誤碼。
從未觀察到轉接器之前的逾時不增加此值。一個狀態變更移除多位玩家時,只算一次事件。
畫面擷取自 KOKURA 的 DMG-07 模型。各主機獨立執行,並比對傳送與接收值。實體轉接器/線材的電氣行為及時序尚未驗證。CGB 畫面以藍色顯示數值。
將 kitaqgb、kokura、kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。四主機範例會在四個工作階段啟動相同 ROM。DMG 檢查時,請將所有 --cgb=cgb 換成 --cgb=dmg,--hardware cgb 換成 --hardware dmg。
使用範例
result[8]=LinkDmg07_GetDisconnectCount();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
不接轉接器執行。預期 PLAYER=0、START ERROR=2、SILENT FRAME=12、TIMEOUTS=1、ERROR=4。因從未發現轉接器,DISCONNECTS 維持零。空讀取保留 EMPTY BUFFER=77;ClearError 使 CLEARED=0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_absent.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_absent.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\dmg07_absent.gb --hardware cgb --run-frames 90 --png .\out\absent.png實作與原始碼
kitaqgb/lib/link_dmg07.h:118
Return the saturating count of removed-player and previously-seen-adapter timeout events.
kitaqgb/lib/link_dmg07.c:525
u8 LinkDmg07_GetDisconnectCount() {
return LinkDmg07_DisconnectCount;
}LinkDmg07_GetErrorCount
讀取接收通訊協定錯誤及未讀封包覆寫次數。
語法
u8 LinkDmg07_GetErrorCount();回傳值
傳回 0..255,不包含請求驗證/狀態錯誤或逾時。
使用條件與限制
SilenceFrames 與診斷計數器飽和於 255。Init 重設全部計數;一般通訊協定重新啟動保留診斷計數器。ClearError 只清除錯誤碼。
接收信箱只保存最新封包。另一封包完成時會覆寫未讀資料、記錄錯誤 6 並遞增 ErrorCount。轉接器不會等待應用程式讀取信箱。
畫面擷取自 KOKURA 的 DMG-07 模型。各主機獨立執行,並比對傳送與接收值。實體轉接器/線材的電氣行為及時序尚未驗證。CGB 畫面以藍色顯示數值。
將 kitaqgb、kokura、kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。四主機範例會在四個工作階段啟動相同 ROM。DMG 檢查時,請將所有 --cgb=cgb 換成 --cgb=dmg,--hardware cgb 換成 --hardware dmg。
使用範例
result[19]=LinkDmg07_GetErrorCount();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
保留第一個有效封包不讀,直到另一封包到達。預期 SENT SEQ=3、PACKET SEQ=2、ERROR=6,讀取傳回最新的 33/34/35/36。ClearError 使 CLEAR ERROR 歸零,ErrorCount 仍為一。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_overflow.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_overflow.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_overflow.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_overflow.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_overflow.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_overflow.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_overflow.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_overflow.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_overflow.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_overflow.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png實作與原始碼
kitaqgb/lib/link_dmg07.h:121
Return the saturating protocol/overflow error count. Timeout and request validation paths use separate counters or latches and do not increment this value.
kitaqgb/lib/link_dmg07.c:531
u8 LinkDmg07_GetErrorCount() {
return LinkDmg07_ErrorCount;
}LinkDmg07_GetLastStatus
讀取最後通過驗證的原始轉接器狀態位元組。
語法
u8 LinkDmg07_GetLastStatus();回傳值
高半位元組為連線遮罩,最低三位元為本機玩家編號。初值為零。
使用條件與限制
函式庫玩家編號為 1..4,零表示尚未發現。連線遮罩位元 0..3 對應玩家 1..4。KOKURA --link-session 的 slot 值為 0..3,與 ROM API 是不同編號慣例。
拒絕位元 3 已設定、玩家編號為零或大於四,以及發現後本機編號改變的狀態。拒絕時記錄錯誤 5,不將該值存為 LastStatus。
畫面擷取自 KOKURA 的 DMG-07 模型。各主機獨立執行,並比對傳送與接收值。實體轉接器/線材的電氣行為及時序尚未驗證。CGB 畫面以藍色顯示數值。
將 kitaqgb、kokura、kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。四主機範例會在四個工作階段啟動相同 ROM。DMG 檢查時,請將所有 --cgb=cgb 換成 --cgb=dmg,--hardware cgb 換成 --hardware dmg。
使用範例
result[2]=LinkDmg07_GetLastStatus();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
四台主機執行相同 ROM,各自傳送 32 加上玩家編號。每台都收到 PLAYER 1..4 = 33/34/35/36。第一個有效廣播記錄 SENT SEQ=2、PACKET SEQ=1,顯示一個封包的延遲。畫面凍結此觀察結果;實際遊戲之後仍持續輪詢。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png實作與原始碼
kitaqgb/lib/link_dmg07.h:67
Return the last validated raw adapter status byte.
kitaqgb/lib/link_dmg07.c:408
u8 LinkDmg07_GetLastStatus() {
return LinkDmg07_LastStatus;
}LinkDmg07_GetLocalSlot
讀取由轉接器狀態得知的本機玩家編號。
語法
u8 LinkDmg07_GetLocalSlot();回傳值
已發現時傳回 1..4;探索前或探索重設後立即傳回零。
使用條件與限制
函式庫玩家編號為 1..4,零表示尚未發現。連線遮罩位元 0..3 對應玩家 1..4。KOKURA --link-session 的 slot 值為 0..3,與 ROM API 是不同編號慣例。
畫面擷取自 KOKURA 的 DMG-07 模型。各主機獨立執行,並比對傳送與接收值。實體轉接器/線材的電氣行為及時序尚未驗證。CGB 畫面以藍色顯示數值。
將 kitaqgb、kokura、kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。四主機範例會在四個工作階段啟動相同 ROM。DMG 檢查時,請將所有 --cgb=cgb 換成 --cgb=dmg,--hardware cgb 換成 --hardware dmg。
使用範例
slot=LinkDmg07_GetLocalSlot();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
四台主機執行相同 ROM,各自傳送 32 加上玩家編號。每台都收到 PLAYER 1..4 = 33/34/35/36。第一個有效廣播記錄 SENT SEQ=2、PACKET SEQ=1,顯示一個封包的延遲。畫面凍結此觀察結果;實際遊戲之後仍持續輪詢。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png實作與原始碼
kitaqgb/lib/link_dmg07.h:62
Return the one-based player slot, or LINK_DMG07_NO_SLOT before discovery.
kitaqgb/lib/link_dmg07.c:398
u8 LinkDmg07_GetLocalSlot() {
return LinkDmg07_LocalSlot;
}LinkDmg07_GetPacketSequence
讀取最近發布封包所分配的序號。
語法
u8 LinkDmg07_GetPacketSequence();回傳值
傳回 8 位元封包序號,不改變就緒狀態。
使用條件與限制
序號從 255 回捲至零。發布封包時,PacketSequence 等於 SentSequence 減一。後續傳送開始會遞增 SentSequence,因此稍後讀取兩個 getter 的值不一定相差一。
接收信箱只保存最新封包。另一封包完成時會覆寫未讀資料、記錄錯誤 6 並遞增 ErrorCount。轉接器不會等待應用程式讀取信箱。
畫面擷取自 KOKURA 的 DMG-07 模型。各主機獨立執行,並比對傳送與接收值。實體轉接器/線材的電氣行為及時序尚未驗證。CGB 畫面以藍色顯示數值。
將 kitaqgb、kokura、kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。四主機範例會在四個工作階段啟動相同 ROM。DMG 檢查時,請將所有 --cgb=cgb 換成 --cgb=dmg,--hardware cgb 換成 --hardware dmg。
使用範例
result[7]=LinkDmg07_GetPacketSequence();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
四台主機執行相同 ROM,各自傳送 32 加上玩家編號。每台都收到 PLAYER 1..4 = 33/34/35/36。第一個有效廣播記錄 SENT SEQ=2、PACKET SEQ=1,顯示一個封包的延遲。畫面凍結此觀察結果;實際遊戲之後仍持續輪詢。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png實作與原始碼
kitaqgb/lib/link_dmg07.h:109
Return the modulo-256 sequence associated with the most recently published packet.
kitaqgb/lib/link_dmg07.c:510
u8 LinkDmg07_GetPacketSequence() {
return LinkDmg07_PacketSequence;
}LinkDmg07_GetPacketSlot
從快取封包儲存區讀取一位玩家的位元組。
語法
u8 __stackcall LinkDmg07_GetPacketSlot(u8 player_slot);參數
player_slot實體玩家編號,1..4。
回傳值
傳回玩家 1..4 的快取位元組;編號無效時為零。
使用條件與限制
函式庫玩家編號為 1..4,零表示尚未發現。連線遮罩位元 0..3 對應玩家 1..4。KOKURA --link-session 的 slot 值為 0..3,與 ROM API 是不同編號慣例。
不檢查也不消費就緒狀態。初始化後立即傳回零;消費或探索重設後可能傳回保留位元組。不可用來判斷新資料。
畫面擷取自 KOKURA 的 DMG-07 模型。各主機獨立執行,並比對傳送與接收值。實體轉接器/線材的電氣行為及時序尚未驗證。CGB 畫面以藍色顯示數值。
將 kitaqgb、kokura、kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。四主機範例會在四個工作階段啟動相同 ROM。DMG 檢查時,請將所有 --cgb=cgb 換成 --cgb=dmg,--hardware cgb 換成 --hardware dmg。
使用範例
result[16]=LinkDmg07_GetPacketSlot(4);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
四台主機執行相同 ROM,各自傳送 32 加上玩家編號。每台都收到 PLAYER 1..4 = 33/34/35/36。第一個有效廣播記錄 SENT SEQ=2、PACKET SEQ=1,顯示一個封包的延遲。畫面凍結此觀察結果;實際遊戲之後仍持續輪詢。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png實作與原始碼
kitaqgb/lib/link_dmg07.h:102
Read one cached player byte using a one-based slot. Invalid slots return zero; the function neither requires readiness nor consumes the packet.
kitaqgb/lib/link_dmg07.c:499
u8 __stackcall LinkDmg07_GetPacketSlot(u8 player_slot) {
if ((player_slot == 0) || (player_slot > LINK_DMG07_MAX_PLAYERS)) return 0;
return LinkDmg07_RxPacket[(__safe_index u8)(player_slot - 1)];
}LinkDmg07_GetPhase
讀取目前的探索、啟動請求、確認或傳輸階段。
語法
u8 LinkDmg07_GetPhase();回傳值
0=PING、1=REQUEST_AA、2=WAIT_CC、3=TRANSFER。
使用條件與限制
不輪詢或等待。啟動請求獲接受仍不足以進入 TRANSFER;需要連續四個 0xCC 位元組。
畫面擷取自 KOKURA 的 DMG-07 模型。各主機獨立執行,並比對傳送與接收值。實體轉接器/線材的電氣行為及時序尚未驗證。CGB 畫面以藍色顯示數值。
將 kitaqgb、kokura、kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。四主機範例會在四個工作階段啟動相同 ROM。DMG 檢查時,請將所有 --cgb=cgb 換成 --cgb=dmg,--hardware cgb 換成 --hardware dmg。
使用範例
result[8]=LinkDmg07_GetPhase();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
四台主機執行相同 ROM,各自傳送 32 加上玩家編號。每台都收到 PLAYER 1..4 = 33/34/35/36。第一個有效廣播記錄 SENT SEQ=2、PACKET SEQ=1,顯示一個封包的延遲。畫面凍結此觀察結果;實際遊戲之後仍持續輪詢。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png實作與原始碼
kitaqgb/lib/link_dmg07.h:60
Return the discovery, start-handshake or transfer phase without polling.
kitaqgb/lib/link_dmg07.c:393
u8 LinkDmg07_GetPhase() {
return LinkDmg07_Phase;
}LinkDmg07_GetRestartState
讀取重新啟動控制是無、等待中,或傳送中。
語法
u8 LinkDmg07_GetRestartState();回傳值
0=無、1=等待邊界、2=傳送控制資料。
使用條件與限制
與通訊階段分開。僅為零不代表已建立或可用的連線。
畫面擷取自 KOKURA 的 DMG-07 模型。各主機獨立執行,並比對傳送與接收值。實體轉接器/線材的電氣行為及時序尚未驗證。CGB 畫面以藍色顯示數值。
將 kitaqgb、kokura、kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。四主機範例會在四個工作階段啟動相同 ROM。DMG 檢查時,請將所有 --cgb=cgb 換成 --cgb=dmg,--hardware cgb 換成 --hardware dmg。
使用範例
result[4]=LinkDmg07_GetRestartState();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
玩家 2 請求重新啟動,該主機記錄 PENDING=1 與 SENT FF=1。四台皆顯示 DATA VALID=1、RESET PHASE=0、SLOT AFTER=0、RESET PRIME=0。驅動程式保留進行中的交換,直到轉接器指示使其回到探索。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_restart.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_restart.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_restart.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_restart.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_restart.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_restart.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_restart.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_restart.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_restart.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_restart.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png實作與原始碼
kitaqgb/lib/link_dmg07.h:85
Return whether aligned recovery is absent, pending or sending control traffic.
kitaqgb/lib/link_dmg07.c:457
u8 LinkDmg07_GetRestartState() {
return LinkDmg07_RestartState;
}LinkDmg07_GetSentSequence
讀取實際由時脈送出的應用程式提交位元組數。
語法
u8 LinkDmg07_GetSentSequence();回傳值
傳回 8 位元傳送序號。包含首次提交,但排除重新啟動控制通訊。
使用條件與限制
序號從 255 回捲至零。發布封包時,PacketSequence 等於 SentSequence 減一。後續傳送開始會遞增 SentSequence,因此稍後讀取兩個 getter 的值不一定相差一。
SIZE=1 時,各主機提交一個位元組,四位元組廣播依玩家 1..4 排列。首次廣播會被丟棄;後續廣播包含上一封包提交的值。四個位元組全為 0xFF 的廣播保留為重新啟動指示。
畫面擷取自 KOKURA 的 DMG-07 模型。各主機獨立執行,並比對傳送與接收值。實體轉接器/線材的電氣行為及時序尚未驗證。CGB 畫面以藍色顯示數值。
將 kitaqgb、kokura、kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。四主機範例會在四個工作階段啟動相同 ROM。DMG 檢查時,請將所有 --cgb=cgb 換成 --cgb=dmg,--hardware cgb 換成 --hardware dmg。
使用範例
result[6]=LinkDmg07_GetSentSequence();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
四台主機執行相同 ROM,各自傳送 32 加上玩家編號。每台都收到 PLAYER 1..4 = 33/34/35/36。第一個有效廣播記錄 SENT SEQ=2、PACKET SEQ=1,顯示一個封包的延遲。畫面凍結此觀察結果;實際遊戲之後仍持續輪詢。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png實作與原始碼
kitaqgb/lib/link_dmg07.h:107
SentSequence increments when this console's packet byte is clocked out. PacketSequence labels the returned four-byte packet. For a valid packet it is one less than SentSequence, making the DMG-07 one-packet delay explicit.
kitaqgb/lib/link_dmg07.c:505
u8 LinkDmg07_GetSentSequence() {
return LinkDmg07_SentSequence;
}LinkDmg07_GetSilenceFrames
讀取上次處理序列傳輸完成後計算的影格數。
語法
u8 LinkDmg07_GetSilenceFrames();回傳值
0..255;處理完成時重設,每次 TickFrame 遞增。
使用條件與限制
每影格持續重複呼叫 Poll,TickFrame 則恰好呼叫一次。每個 VBlank 只 Poll 一次,無法在轉接器的位元組之間重新準備埠。共用標頭的 d_poll 偵測進入 LY >= 144,呼叫一次 TickFrame。請序列化兩項操作,避免 ISR 與主迴圈競爭。
SilenceFrames 與診斷計數器飽和於 255。Init 重設全部計數;一般通訊協定重新啟動保留診斷計數器。ClearError 只清除錯誤碼。
畫面擷取自 KOKURA 的 DMG-07 模型。各主機獨立執行,並比對傳送與接收值。實體轉接器/線材的電氣行為及時序尚未驗證。CGB 畫面以藍色顯示數值。
將 kitaqgb、kokura、kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。四主機範例會在四個工作階段啟動相同 ROM。DMG 檢查時,請將所有 --cgb=cgb 換成 --cgb=dmg,--hardware cgb 換成 --hardware dmg。
使用範例
result[6]=LinkDmg07_GetSilenceFrames();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
不接轉接器執行。預期 PLAYER=0、START ERROR=2、SILENT FRAME=12、TIMEOUTS=1、ERROR=4。因從未發現轉接器,DISCONNECTS 維持零。空讀取保留 EMPTY BUFFER=77;ClearError 使 CLEARED=0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_absent.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_absent.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\dmg07_absent.gb --hardware cgb --run-frames 90 --png .\out\absent.png實作與原始碼
kitaqgb/lib/link_dmg07.h:114
SilenceFrames is reset by every completed serial byte. TimeoutCount counts distinct serial-silence or AA/CC/restart handshake timeouts. DisconnectCount counts adapter-silence outages and ping-status membership drops. All saturate.
kitaqgb/lib/link_dmg07.c:515
u8 LinkDmg07_GetSilenceFrames() {
return LinkDmg07_SilenceFrames;
}LinkDmg07_GetTimeoutCount
讀取靜默或交握期限逾時次數。
語法
u8 LinkDmg07_GetTimeoutCount();回傳值
傳回 0..255 的累計值。
使用條件與限制
SilenceFrames 與診斷計數器飽和於 255。Init 重設全部計數;一般通訊協定重新啟動保留診斷計數器。ClearError 只清除錯誤碼。
接收恢復前,不會每影格重複計算同一段靜默。ClearError 保留此抑制鎖存及累計次數。
畫面擷取自 KOKURA 的 DMG-07 模型。各主機獨立執行,並比對傳送與接收值。實體轉接器/線材的電氣行為及時序尚未驗證。CGB 畫面以藍色顯示數值。
將 kitaqgb、kokura、kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。四主機範例會在四個工作階段啟動相同 ROM。DMG 檢查時,請將所有 --cgb=cgb 換成 --cgb=dmg,--hardware cgb 換成 --hardware dmg。
使用範例
result[7]=LinkDmg07_GetTimeoutCount();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
不接轉接器執行。預期 PLAYER=0、START ERROR=2、SILENT FRAME=12、TIMEOUTS=1、ERROR=4。因從未發現轉接器,DISCONNECTS 維持零。空讀取保留 EMPTY BUFFER=77;ClearError 使 CLEARED=0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_absent.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_absent.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\dmg07_absent.gb --hardware cgb --run-frames 90 --png .\out\absent.png實作與原始碼
kitaqgb/lib/link_dmg07.h:116
Return the saturating lifetime timeout count, preserved across protocol restarts.
kitaqgb/lib/link_dmg07.c:520
u8 LinkDmg07_GetTimeoutCount() {
return LinkDmg07_TimeoutCount;
}LinkDmg07_HasPacket
檢查是否有已完成但未讀取的四位元組資料封包。
語法
u8 LinkDmg07_HasPacket();回傳值
有未讀資料時傳回 1,否則為 0。
使用條件與限制
SIZE=1 時,各主機提交一個位元組,四位元組廣播依玩家 1..4 排列。首次廣播會被丟棄;後續廣播包含上一封包提交的值。四個位元組全為 0xFF 的廣播保留為重新啟動指示。
接收信箱只保存最新封包。另一封包完成時會覆寫未讀資料、記錄錯誤 6 並遞增 ErrorCount。轉接器不會等待應用程式讀取信箱。
畫面擷取自 KOKURA 的 DMG-07 模型。各主機獨立執行,並比對傳送與接收值。實體轉接器/線材的電氣行為及時序尚未驗證。CGB 畫面以藍色顯示數值。
將 kitaqgb、kokura、kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。四主機範例會在四個工作階段啟動相同 ROM。DMG 檢查時,請將所有 --cgb=cgb 換成 --cgb=dmg,--hardware cgb 換成 --hardware dmg。
使用範例
result[15]=LinkDmg07_HasPacket();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
四台主機執行相同 ROM,各自傳送 32 加上玩家編號。每台都收到 PLAYER 1..4 = 33/34/35/36。第一個有效廣播記錄 SENT SEQ=2、PACKET SEQ=1,顯示一個封包的延遲。畫面凍結此觀察結果;實際遊戲之後仍持續輪詢。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png實作與原始碼
kitaqgb/lib/link_dmg07.h:96
Inspect the one-packet receive mailbox without consuming it.
kitaqgb/lib/link_dmg07.c:473
u8 LinkDmg07_HasPacket() {
return LinkDmg07_PacketReady;
}LinkDmg07_HasPingStatus
檢查已完成的四位元組探索交換是否等待確認。
語法
u8 LinkDmg07_HasPingStatus();回傳值
尚有未消費通知時傳回 1,否則為 0。
使用條件與限制
僅讀取旗標。即使狀態位元組被拒絕,探索交換仍可能推進;不可只憑此旗標推斷資料完全有效或啟動已完成。也請檢查 slot、mask 與 LastError。
畫面擷取自 KOKURA 的 DMG-07 模型。各主機獨立執行,並比對傳送與接收值。實體轉接器/線材的電氣行為及時序尚未驗證。CGB 畫面以藍色顯示數值。
將 kitaqgb、kokura、kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。四主機範例會在四個工作階段啟動相同 ROM。DMG 檢查時,請將所有 --cgb=cgb 換成 --cgb=dmg,--hardware cgb 換成 --hardware dmg。
使用範例
result[4]=LinkDmg07_HasPingStatus();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
四台主機執行相同 ROM,各自傳送 32 加上玩家編號。每台都收到 PLAYER 1..4 = 33/34/35/36。第一個有效廣播記錄 SENT SEQ=2、PACKET SEQ=1,顯示一個封包的延遲。畫面凍結此觀察結果;實際遊戲之後仍持續輪詢。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png實作與原始碼
kitaqgb/lib/link_dmg07.h:69
Read the completed-discovery status flag without clearing it.
kitaqgb/lib/link_dmg07.c:413
u8 LinkDmg07_HasPingStatus() {
return LinkDmg07_PingStatusReady;
}LinkDmg07_Init
重設探索狀態、接收儲存空間及診斷,再準備接收轉接器時脈。
語法
void __stackcall LinkDmg07_Init(u8 rate);參數
rate回覆轉接器的 8 位元 RATE;零選取預設值 0x10。
回傳值
無傳回值。
使用條件與限制
此驅動程式獨占序列埠。不可同時執行一般 Link 或 Link4;link_hwregs_gb.c 與 link_dmg07.c 各包含一次。外部時脈由轉接器提供;驅動程式不選取 CGB 高速序列模式。
函式庫玩家編號為 1..4,零表示尚未發現。連線遮罩位元 0..3 對應玩家 1..4。KOKURA --link-session 的 slot 值為 0..3,與 ROM API 是不同編號慣例。
將 SC 設為 0x80、SB 設為 0x88;只清除 IE 與 IF 的序列位元。不改變其他中斷啟用位元或 CPU IME 狀態。
畫面擷取自 KOKURA 的 DMG-07 模型。各主機獨立執行,並比對傳送與接收值。實體轉接器/線材的電氣行為及時序尚未驗證。CGB 畫面以藍色顯示數值。
將 kitaqgb、kokura、kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。四主機範例會在四個工作階段啟動相同 ROM。DMG 檢查時,請將所有 --cgb=cgb 換成 --cgb=dmg,--hardware cgb 換成 --hardware dmg。
使用範例
LinkDmg07_Init(0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
四台主機執行相同 ROM,各自傳送 32 加上玩家編號。每台都收到 PLAYER 1..4 = 33/34/35/36。第一個有效廣播記錄 SENT SEQ=2、PACKET SEQ=1,顯示一個封包的延遲。畫面凍結此觀察結果;實際遊戲之後仍持續輪詢。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png實作與原始碼
kitaqgb/lib/link_dmg07.h:50
Initializes polling-only external-clock operation. A zero RATE is replaced with LINK_DMG07_DEFAULT_RATE. This driver disables only the serial IRQ bit.
kitaqgb/lib/link_dmg07.c:282
void __stackcall LinkDmg07_Init(u8 rate) {
u8 i;
LinkDmg07_Rate = rate;
if (LinkDmg07_Rate == 0) LinkDmg07_Rate = LINK_DMG07_DEFAULT_RATE;
LinkDmg07_LocalByte = 0;
LinkDmg07_SentSequence = 0;
LinkDmg07_PacketSequence = 0;
LinkDmg07_RestartState = LINK_DMG07_RESTART_NONE;
LinkDmg07_SilenceFrames = 0;
LinkDmg07_TimeoutCount = 0;
LinkDmg07_DisconnectCount = 0;
LinkDmg07_ErrorCount = 0;
LinkDmg07_LastErrorCode = LINK_DMG07_ERR_NONE;
LinkDmg07_SeenAdapter = 0;
LinkDmg07_TimeoutLatched = 0;
for (i = 0; i < LINK_DMG07_PACKET_BYTES; ++i) {
LinkDmg07_RxBuild[(__safe_index u8)i] = 0;
LinkDmg07_RxPacket[(__safe_index u8)i] = 0;
}
LinkDmg07_ResetToPingInternal();
LinkHw_WriteIE((u8)(LinkHw_ReadIE() & LINK_DMG07_IRQ_SERIAL_CLEAR));
LinkHw_WriteIF((u8)(LinkHw_ReadIF() & LINK_DMG07_IRQ_SERIAL_CLEAR));
LinkDmg07_ArmInternal(LINK_DMG07_ACK);
}LinkDmg07_IsPipelinePrimed
檢查是否已丟棄最初未定義的廣播。
語法
u8 LinkDmg07_IsPipelinePrimed();回傳值
首次廣播後傳回 1;初始化、探索重設及啟動確認會清除它。
使用條件與限制
SIZE=1 時,各主機提交一個位元組,四位元組廣播依玩家 1..4 排列。首次廣播會被丟棄;後續廣播包含上一封包提交的值。四個位元組全為 0xFF 的廣播保留為重新啟動指示。
管線已準備不代表已有完成封包。請用 HasPacket 判斷是否可讀取。
畫面擷取自 KOKURA 的 DMG-07 模型。各主機獨立執行,並比對傳送與接收值。實體轉接器/線材的電氣行為及時序尚未驗證。CGB 畫面以藍色顯示數值。
將 kitaqgb、kokura、kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。四主機範例會在四個工作階段啟動相同 ROM。DMG 檢查時,請將所有 --cgb=cgb 換成 --cgb=dmg,--hardware cgb 換成 --hardware dmg。
使用範例
result[9]=LinkDmg07_IsPipelinePrimed();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
四台主機執行相同 ROM,各自傳送 32 加上玩家編號。每台都收到 PLAYER 1..4 = 33/34/35/36。第一個有效廣播記錄 SENT SEQ=2、PACKET SEQ=1,顯示一個封包的延遲。畫面凍結此觀察結果;實際遊戲之後仍持續輪詢。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png實作與原始碼
kitaqgb/lib/link_dmg07.h:94
The first incoming adapter data packet is discarded. Thereafter ReadPacket copies four bytes in physical slot order (players 1..4).
kitaqgb/lib/link_dmg07.c:468
u8 LinkDmg07_IsPipelinePrimed() {
return LinkDmg07_PipelinePrimed;
}LinkDmg07_LastError
讀取最近記錄的錯誤碼。
語法
u8 LinkDmg07_LastError();回傳值
傳回錯誤碼 0..6。
使用條件與限制
錯誤碼為 0=無、1=階段錯誤、2=不是玩家 1、3=尚未就緒、4=逾時、5=通訊協定錯誤、6=未讀封包被覆寫。請求成功傳回零,接收/pop 成功傳回一。請求成功不會清除先前錯誤。
讀取不會清除。只儲存最新代碼,不保存所有錯誤歷程。
畫面擷取自 KOKURA 的 DMG-07 模型。各主機獨立執行,並比對傳送與接收值。實體轉接器/線材的電氣行為及時序尚未驗證。CGB 畫面以藍色顯示數值。
將 kitaqgb、kokura、kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。四主機範例會在四個工作階段啟動相同 ROM。DMG 檢查時,請將所有 --cgb=cgb 換成 --cgb=dmg,--hardware cgb 換成 --hardware dmg。
使用範例
result[9]=LinkDmg07_LastError();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
不接轉接器執行。預期 PLAYER=0、START ERROR=2、SILENT FRAME=12、TIMEOUTS=1、ERROR=4。因從未發現轉接器,DISCONNECTS 維持零。空讀取保留 EMPTY BUFFER=77;ClearError 使 CLEARED=0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_absent.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_absent.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\dmg07_absent.gb --hardware cgb --run-frames 90 --png .\out\absent.png實作與原始碼
kitaqgb/lib/link_dmg07.h:123
Return the latest error latch without clearing counters or restarting the protocol.
kitaqgb/lib/link_dmg07.c:536
u8 LinkDmg07_LastError() {
return LinkDmg07_LastErrorCode;
}LinkDmg07_Poll
在目前階段處理一個已完成的序列位元組,立即準備下一個回覆。
語法
void LinkDmg07_Poll();回傳值
無傳回值。
使用條件與限制
此驅動程式獨占序列埠。不可同時執行一般 Link 或 Link4;link_hwregs_gb.c 與 link_dmg07.c 各包含一次。外部時脈由轉接器提供;驅動程式不選取 CGB 高速序列模式。
每影格持續重複呼叫 Poll,TickFrame 則恰好呼叫一次。每個 VBlank 只 Poll 一次,無法在轉接器的位元組之間重新準備埠。共用標頭的 d_poll 偵測進入 LY >= 144,呼叫一次 TickFrame。請序列化兩項操作,避免 ISR 與主迴圈競爭。
SC 啟動位元設定時不執行動作。處理完成會重設 SilenceFrames 與逾時鎖存。請先初始化再輪詢。
畫面擷取自 KOKURA 的 DMG-07 模型。各主機獨立執行,並比對傳送與接收值。實體轉接器/線材的電氣行為及時序尚未驗證。CGB 畫面以藍色顯示數值。
將 kitaqgb、kokura、kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。四主機範例會在四個工作階段啟動相同 ROM。DMG 檢查時,請將所有 --cgb=cgb 換成 --cgb=dmg,--hardware cgb 換成 --hardware dmg。
使用範例
void d_poll(){LinkDmg07_Poll();if(D_LY>=144){if(d_vblank==0){d_vblank=1;LinkDmg07_TickFrame();}}else d_vblank=0;}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
四台主機執行相同 ROM,各自傳送 32 加上玩家編號。每台都收到 PLAYER 1..4 = 33/34/35/36。第一個有效廣播記錄 SENT SEQ=2、PACKET SEQ=1,顯示一個封包的延遲。畫面凍結此觀察結果;實際遊戲之後仍持續輪詢。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png實作與原始碼
kitaqgb/lib/link_dmg07.h:54
Services at most one completed serial byte and immediately re-arms SC=$80. Call continuously from the main loop, including between VBlanks.
kitaqgb/lib/link_dmg07.c:311
void LinkDmg07_Poll() {
u8 value;
u8 next;
if ((LinkHw_ReadSC() & LINK_DMG07_SC_EXTERNAL_START) != 0) return;
value = LinkHw_ReadSB();
LinkDmg07_SilenceFrames = 0;
LinkDmg07_TimeoutLatched = 0;
LinkDmg07_SeenAdapter = 1;
next = 0;
if (LinkDmg07_Phase == LINK_DMG07_PHASE_PING) {
next = LinkDmg07_ProcessPingInternal(value);
} else if (LinkDmg07_Phase == LINK_DMG07_PHASE_REQUEST_AA) {
next = LinkDmg07_ProcessRequestInternal(value);
} else if (LinkDmg07_Phase == LINK_DMG07_PHASE_WAIT_CC) {
next = LinkDmg07_ProcessWaitCcInternal(value);
} else if (LinkDmg07_Phase == LINK_DMG07_PHASE_TRANSFER) {
next = LinkDmg07_ProcessTransferInternal(value);
} else {
LinkDmg07_SetRuntimeErrorInternal(LINK_DMG07_ERR_PROTOCOL);
LinkDmg07_ResetToPingInternal();
next = LINK_DMG07_ACK;
}
LinkDmg07_ArmInternal(next);
}LinkDmg07_ReadPacket
複製最新完成的封包,並清除未讀旗標。
語法
u8 __stackcall LinkDmg07_ReadPacket(u8 *dst);參數
dst四個可寫入位元組;null 會丟棄封包。
回傳值
消費成功傳回 1,無資料傳回 0。空讀取不改變 dst。
使用條件與限制
SIZE=1 時,各主機提交一個位元組,四位元組廣播依玩家 1..4 排列。首次廣播會被丟棄;後續廣播包含上一封包提交的值。四個位元組全為 0xFF 的廣播保留為重新啟動指示。
接收信箱只保存最新封包。另一封包完成時會覆寫未讀資料、記錄錯誤 6 並遞增 ErrorCount。轉接器不會等待應用程式讀取信箱。
消費後仍可透過 GetPacketSlot 取得快取位元組。空的 ReadPacket 不會再次複製這些位元組。
畫面擷取自 KOKURA 的 DMG-07 模型。各主機獨立執行,並比對傳送與接收值。實體轉接器/線材的電氣行為及時序尚未驗證。CGB 畫面以藍色顯示數值。
將 kitaqgb、kokura、kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。四主機範例會在四個工作階段啟動相同 ROM。DMG 檢查時,請將所有 --cgb=cgb 換成 --cgb=dmg,--hardware cgb 換成 --hardware dmg。
使用範例
result[10]=LinkDmg07_ReadPacket(packet);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
四台主機執行相同 ROM,各自傳送 32 加上玩家編號。每台都收到 PLAYER 1..4 = 33/34/35/36。第一個有效廣播記錄 SENT SEQ=2、PACKET SEQ=1,顯示一個封包的延遲。畫面凍結此觀察結果;實際遊戲之後仍持續輪詢。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png實作與原始碼
kitaqgb/lib/link_dmg07.h:99
Consume the latest four-byte packet. A nonnull destination must hold four bytes; null discards the packet. Packet storage remains after the flag clears.
kitaqgb/lib/link_dmg07.c:479
u8 __stackcall LinkDmg07_ReadPacket(u8 *dst) {
if (LinkDmg07_PacketReady == 0) return 0;
if (dst != 0) {
// Keep this as a sequential pointer copy. Besides being smaller for a
// fixed four-byte packet, it avoids making a serial hot-path copy
// depend on general variable-index pointer lowering.
*dst = LinkDmg07_RxPacket[0];
dst++;
*dst = LinkDmg07_RxPacket[1];
dst++;
*dst = LinkDmg07_RxPacket[2];
dst++;
*dst = LinkDmg07_RxPacket[3];
}
LinkDmg07_PacketReady = 0;
return 1;
}LinkDmg07_RequestRestart
排程在傳輸封包邊界開始的重新啟動控制通訊。
語法
u8 LinkDmg07_RequestRestart();回傳值
在 TRANSFER 傳回 0,其他情況為 1。等待或傳送期間重複請求也傳回 0。
使用條件與限制
SIZE=1 時,各主機提交一個位元組,四位元組廣播依玩家 1..4 排列。首次廣播會被丟棄;後續廣播包含上一封包提交的值。四個位元組全為 0xFF 的廣播保留為重新啟動指示。
錯誤碼為 0=無、1=階段錯誤、2=不是玩家 1、3=尚未就緒、4=逾時、5=通訊協定錯誤、6=未讀封包被覆寫。請求成功傳回零,接收/pop 成功傳回一。請求成功不會清除先前錯誤。
任何玩家皆可請求。保留目前位元組位置,傳送對齊的 0xFF 控制資料,在轉接器回傳全 0xFF 指示後回到探索。僅提出請求不會清除本機 slot 或接收管線。
畫面擷取自 KOKURA 的 DMG-07 模型。各主機獨立執行,並比對傳送與接收值。實體轉接器/線材的電氣行為及時序尚未驗證。CGB 畫面以藍色顯示數值。
將 kitaqgb、kokura、kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。四主機範例會在四個工作階段啟動相同 ROM。DMG 檢查時,請將所有 --cgb=cgb 換成 --cgb=dmg,--hardware cgb 換成 --hardware dmg。
使用範例
result[3]=LinkDmg07_RequestRestart();result[4]=LinkDmg07_GetRestartState();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
玩家 2 請求重新啟動,該主機記錄 PENDING=1 與 SENT FF=1。四台皆顯示 DATA VALID=1、RESET PHASE=0、SLOT AFTER=0、RESET PRIME=0。驅動程式保留進行中的交換,直到轉接器指示使其回到探索。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_restart.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_restart.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_restart.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_restart.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_restart.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_restart.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_restart.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_restart.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_restart.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_restart.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png實作與原始碼
kitaqgb/lib/link_dmg07.h:83
Any physical slot may schedule FF FF FF FF at the next four-byte packet boundary while remaining in TRANSFER phase. The driver keeps sending aligned FF bytes until it sees the adapter's complete all-FF indicator packet, then returns to PING. A transfer-phase silence timeout schedules the same recovery automatically and preserves the current byte position for clocks that resume.
kitaqgb/lib/link_dmg07.c:445
u8 LinkDmg07_RequestRestart() {
if (LinkDmg07_Phase != LINK_DMG07_PHASE_TRANSFER) {
LinkDmg07_LastErrorCode = LINK_DMG07_ERR_STATE;
return LINK_DMG07_ERR_STATE;
}
if (LinkDmg07_RestartState == LINK_DMG07_RESTART_NONE) {
LinkDmg07_RestartState = LINK_DMG07_RESTART_PENDING;
}
return LINK_DMG07_ERR_NONE;
}LinkDmg07_RequestTransmission
將實體玩家 1 的啟動請求排到下一個探索封包邊界。
語法
u8 LinkDmg07_RequestTransmission();回傳值
已排程傳回 0;階段錯誤為 1;不是玩家 1 為 2;缺少本機連線位元為 3。
使用條件與限制
函式庫玩家編號為 1..4,零表示尚未發現。連線遮罩位元 0..3 對應玩家 1..4。KOKURA --link-session 的 slot 值為 0..3,與 ROM API 是不同編號慣例。
錯誤碼為 0=無、1=階段錯誤、2=不是玩家 1、3=尚未就緒、4=逾時、5=通訊協定錯誤、6=未讀封包被覆寫。請求成功傳回零,接收/pop 成功傳回一。請求成功不會清除先前錯誤。
只能在 PING 排程。不會自行等待四位玩家;範例在應用程式檢查遮罩 15。排程為非同步:對齊的 0xAA 通訊先於 0xCC 確認。
畫面擷取自 KOKURA 的 DMG-07 模型。各主機獨立執行,並比對傳送與接收值。實體轉接器/線材的電氣行為及時序尚未驗證。CGB 畫面以藍色顯示數值。
將 kitaqgb、kokura、kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。四主機範例會在四個工作階段啟動相同 ROM。DMG 檢查時,請將所有 --cgb=cgb 換成 --cgb=dmg,--hardware cgb 換成 --hardware dmg。
使用範例
result[5]=LinkDmg07_RequestTransmission();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
四台主機執行相同 ROM,各自傳送 32 加上玩家編號。每台都收到 PLAYER 1..4 = 33/34/35/36。第一個有效廣播記錄 SENT SEQ=2、PACKET SEQ=1,顯示一個封包的延遲。畫面凍結此觀察結果;實際遊戲之後仍持續輪詢。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png實作與原始碼
kitaqgb/lib/link_dmg07.h:76
Only physical player 1 may request AA AA AA AA. The bytes are aligned to the next FE/status/status/status ping packet. All consoles enter transfer mode only after receiving four consecutive CC bytes.
kitaqgb/lib/link_dmg07.c:426
u8 LinkDmg07_RequestTransmission() {
if (LinkDmg07_Phase != LINK_DMG07_PHASE_PING) {
LinkDmg07_LastErrorCode = LINK_DMG07_ERR_STATE;
return LINK_DMG07_ERR_STATE;
}
if (LinkDmg07_LocalSlot != 1) {
LinkDmg07_LastErrorCode = LINK_DMG07_ERR_NOT_PLAYER1;
return LINK_DMG07_ERR_NOT_PLAYER1;
}
if ((LinkDmg07_ConnectedMask & (u8)0x01) == 0) {
LinkDmg07_LastErrorCode = LINK_DMG07_ERR_NOT_READY;
return LINK_DMG07_ERR_NOT_READY;
}
LinkDmg07_StartRequested = 1;
return LINK_DMG07_ERR_NONE;
}LinkDmg07_SetLocalByte
設定未來送出封包的一位元組應用程式值。
語法
void __stackcall LinkDmg07_SetLocalByte(u8 value);參數
value要提交的 8 位元應用程式值。
回傳值
無傳回值。
使用條件與限制
SIZE=1 時,各主機提交一個位元組,四位元組廣播依玩家 1..4 排列。首次廣播會被丟棄;後續廣播包含上一封包提交的值。四個位元組全為 0xFF 的廣播保留為重新啟動指示。
準備封包位元組零時取樣,不修改已準備的 SB 位元組。請在請求啟動前設定第一個提交值。
畫面擷取自 KOKURA 的 DMG-07 模型。各主機獨立執行,並比對傳送與接收值。實體轉接器/線材的電氣行為及時序尚未驗證。CGB 畫面以藍色顯示數值。
將 kitaqgb、kokura、kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。四主機範例會在四個工作階段啟動相同 ROM。DMG 檢查時,請將所有 --cgb=cgb 換成 --cgb=dmg,--hardware cgb 換成 --hardware dmg。
使用範例
LinkDmg07_SetLocalByte(32+slot);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
四台主機執行相同 ROM,各自傳送 32 加上玩家編號。每台都收到 PLAYER 1..4 = 33/34/35/36。第一個有效廣播記錄 SENT SEQ=2、PACKET SEQ=1,顯示一個封包的延遲。畫面凍結此觀察結果;實際遊戲之後仍持續輪詢。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png實作與原始碼
kitaqgb/lib/link_dmg07.h:90
Sets the byte sampled when byte 0 of the next adapter packet is armed. Set it before the current packet completes (and before requesting start for the first submission). During normal transfer, bytes 1..3 are sent as zero.
kitaqgb/lib/link_dmg07.c:463
void __stackcall LinkDmg07_SetLocalByte(u8 value) {
LinkDmg07_LocalByte = value;
}LinkDmg07_TickFrame
將靜默及啟動/重新啟動監控推進一影格,到期限時請求復原。
語法
void LinkDmg07_TickFrame();回傳值
無傳回值。
使用條件與限制
每影格持續重複呼叫 Poll,TickFrame 則恰好呼叫一次。每個 VBlank 只 Poll 一次,無法在轉接器的位元組之間重新準備埠。共用標頭的 d_poll 偵測進入 LY >= 144,呼叫一次 TickFrame。請序列化兩項操作,避免 ISR 與主迴圈競爭。
SilenceFrames 與診斷計數器飽和於 255。Init 重設全部計數;一般通訊協定重新啟動保留診斷計數器。ClearError 只清除錯誤碼。
預設期限為 12 次呼叫。若需其他期限,請在包含前將 LINK_DMG07_TIMEOUT_FRAMES 定義為 1..255。每段靜默只計一次,直到另一位元組清除鎖存。傳輸復原保留位元組對齊;探索/啟動復原回到探索階段。
畫面擷取自 KOKURA 的 DMG-07 模型。各主機獨立執行,並比對傳送與接收值。實體轉接器/線材的電氣行為及時序尚未驗證。CGB 畫面以藍色顯示數值。
將 kitaqgb、kokura、kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。四主機範例會在四個工作階段啟動相同 ROM。DMG 檢查時,請將所有 --cgb=cgb 換成 --cgb=dmg,--hardware cgb 換成 --hardware dmg。
使用範例
void d_poll(){LinkDmg07_Poll();if(D_LY>=144){if(d_vblank==0){d_vblank=1;LinkDmg07_TickFrame();}}else d_vblank=0;}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
不接轉接器執行。預期 PLAYER=0、START ERROR=2、SILENT FRAME=12、TIMEOUTS=1、ERROR=4。因從未發現轉接器,DISCONNECTS 維持零。空讀取保留 EMPTY BUFFER=77;ClearError 使 CLEARED=0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_absent.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_absent.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\dmg07_absent.gb --hardware cgb --run-frames 90 --png .\out\absent.png實作與原始碼
kitaqgb/lib/link_dmg07.h:57
Advances saturating frame-based silence and handshake timeout counters.
kitaqgb/lib/link_dmg07.c:369
void LinkDmg07_TickFrame() {
LinkDmg07_SilenceFrames = LinkDmg07_IncrementSaturatingInternal(LinkDmg07_SilenceFrames);
if ((LinkDmg07_Phase == LINK_DMG07_PHASE_REQUEST_AA) ||
(LinkDmg07_Phase == LINK_DMG07_PHASE_WAIT_CC) ||
(LinkDmg07_RestartState == LINK_DMG07_RESTART_SENDING)) {
LinkDmg07_HandshakeFrames = LinkDmg07_IncrementSaturatingInternal(LinkDmg07_HandshakeFrames);
} else {
LinkDmg07_HandshakeFrames = 0;
}
if ((LinkDmg07_SilenceFrames >= LINK_DMG07_TIMEOUT_FRAMES) &&
(LinkDmg07_TimeoutLatched == 0)) {
LinkDmg07_TimeoutInternal(1);
return;
}
if ((LinkDmg07_HandshakeFrames >= LINK_DMG07_TIMEOUT_FRAMES) &&
(LinkDmg07_TimeoutLatched == 0)) {
LinkDmg07_TimeoutInternal(0);
}
}physics2d.h — 2D 運動與碰撞
提供盒體積分、AABB 接觸處理,以及可選用的表面反應求解器。物體使用中心與半長表示;active=0 會排除該欄位,inv_mass_q8<=0 則視為靜態物體。KQRect 使用左上角座標與寬度/高度。盒體配對接觸不使用物體的 restitution 欄位;表面反應則使用 KQSurface2D 係數。
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
世界僅借用陣列。呼叫端負責配置並持有物體儲存空間,且須在使用期間維持其有效。初始化世界不會初始化陣列元素。
kq2d_body_apply_friction
將兩個速度分量乘上帶正負號位元組係數再除以 256,不檢查位置或啟用狀態。
語法
void kq2d_body_apply_friction(KQBody2D* body, u8 friction_q8);參數
body指向要修改的物體。本操作未使用的欄位會保持不變。
friction_q8此函式使用的速度倍率。它會轉成 s8,因此 128..255 會成為負係數。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
0..127 對應倍率 0..127/256。128..255 轉成 s8 後成為負數,會反轉速度方向。若要在 0..255 範圍使用非負阻尼,請對各速度分量使用 kq2d_scale_q8。乘積向零截斷。忽略 NULL。
使用範例
kq2d_body_apply_friction(&temp,64);
result[11]=temp.vx; result[12]=temp.vy;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側為初始狀態,右側為一個刻度後。紅色 16x16 盒體的中心為 (24,24)、速度為 (4,16),之後到達 (28,36),在藍色地板上使 Y 速度歸零。面板原點位於螢幕座標 (8,48) 與 (88,48)。DMG 上所有標記皆為黑色。RAM 檢查也涵蓋初始化、設定函式、積分、矩形/點查詢與帶正負號的縮放運算。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body2d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body2d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics2d.h:66
Scale both velocities through the signed 8-bit coefficient intrinsic. Despite the unsigned parameter, values 128..255 become negative coefficients; this is not a full-range unsigned Q8 damping helper. Null is ignored.
kitaqgb/lib/physics2d.c:654
void kq2d_body_apply_friction(KQBody2D* body, u8 friction_q8)
{
if (body == 0) return;
body->vx = (s16)__smul16x8(body->vx, (s8)friction_q8);
body->vy = (s16)__smul16x8(body->vy, (s8)friction_q8);
}kq2d_body_apply_gravity
對作用中的動態物體加上重力,並將每軸速度限制在 +/-max_speed,不更新位置。
語法
void kq2d_body_apply_gravity(KQBody2D* body, s16 gravity_x, s16 gravity_y, s16 max_speed);參數
body指向要修改的物體。本操作未使用的欄位會保持不變。
gravity_x本次呼叫加至 X 速度的加速度。
gravity_y本次呼叫加至 Y 速度的加速度。
max_speed速度上限。各項說明會指出此限制是作用於每個軸,還是整個向量。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
總和、差值、半長總和及接觸位置修正的乘積都必須落在帶正負號的 16 位元範圍內。速度限制在加法之後才套用,無法防止加法本身溢位。
盒體積分與碰撞函式共用暫存空間。請勿從中斷重入這些物理函式。
忽略 NULL、未啟用物體及反質量小於或等於零的物體。速度上限請提供非負值。
使用範例
kq2d_body_apply_gravity(&temp,5,-10,32);
result[9]=temp.vx; result[10]=temp.vy;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側為初始狀態,右側為一個刻度後。紅色 16x16 盒體的中心為 (24,24)、速度為 (4,16),之後到達 (28,36),在藍色地板上使 Y 速度歸零。面板原點位於螢幕座標 (8,48) 與 (88,48)。DMG 上所有標記皆為黑色。RAM 檢查也涵蓋初始化、設定函式、積分、矩形/點查詢與帶正負號的縮放運算。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body2d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body2d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics2d.h:62
Add gravity and clamp each velocity axis separately for an active dynamic body. Null, inactive and static bodies are ignored. Supply a nonnegative limit and avoid overflow in the additions before clamping; position is unchanged.
kitaqgb/lib/physics2d.c:630
void kq2d_body_apply_gravity(KQBody2D* body, s16 gravity_x, s16 gravity_y, s16 max_speed)
{
if (body == 0) return;
if (body->active == 0) return;
if (body->inv_mass_q8 <= 0) return;
kq2d_asm_value = body->vx;
kq2d_asm_operand = gravity_x;
kq2d_add_s16_asm();
kq2d_asm_limit = max_speed;
kq2d_clamp_abs_s16_asm();
body->vx = kq2d_asm_value;
kq2d_asm_value = body->vy;
kq2d_asm_operand = gravity_y;
kq2d_add_s16_asm();
kq2d_asm_limit = max_speed;
kq2d_clamp_abs_s16_asm();
body->vy = kq2d_asm_value;
}kq2d_body_init
以指定半長初始化以中心表示的盒體,將速度設為零、反質量設為 256,並啟用物體。
語法
void kq2d_body_init(KQBody2D* body, s16 x, s16 y, s16 half_x, s16 half_y);參數
body指向要修改的物體。本操作未使用的欄位會保持不變。
x中心或點的 X 座標;範例以像素為單位。
y中心或點的 Y 座標;範例中正方向朝下。
half_xX 軸半長;盒體的完整寬度為此值的兩倍。
half_yY 軸半長;盒體的完整高度為此值的兩倍。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
將 restitution_q8 設為零。body 為 NULL 時忽略呼叫。請提供正的半長。
使用範例
kq2d_body_init(&temp,10,20,8,8);
result[3]=temp.inv_mass_q8; result[4]=temp.active;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側為初始狀態,右側為一個刻度後。紅色 16x16 盒體的中心為 (24,24)、速度為 (4,16),之後到達 (28,36),在藍色地板上使 Y 速度歸零。面板原點位於螢幕座標 (8,48) 與 (88,48)。DMG 上所有標記皆為黑色。RAM 檢查也涵蓋初始化、設定函式、積分、矩形/點查詢與帶正負號的縮放運算。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body2d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body2d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics2d.h:54
Initialize an active unit-inverse-mass body at the supplied center and half extents, with zero velocity and reserved restitution set to zero. Null is ignored.
kitaqgb/lib/physics2d.c:597
void kq2d_body_init(KQBody2D* body, s16 x, s16 y, s16 half_x, s16 half_y)
{
if (body == 0) return;
body->x = x;
body->y = y;
body->vx = 0;
body->vy = 0;
body->half_x = half_x;
body->half_y = half_y;
body->inv_mass_q8 = 256;
body->restitution_q8 = 0;
body->active = 1;
}kq2d_body_limit_speed
此 API 在本機版中的差異,請參閱 2026-10-03 差異與驗證。
保守估計向量長度,並以相同比例縮放兩軸,限制合成速率。
語法
void kq2d_body_limit_speed(KQBody2D* body, s16 max_speed);參數
body指向要修改的物體。本操作未使用的欄位會保持不變。
max_speed速度上限。各項說明會指出此限制是作用於每個軸,還是整個向量。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
速度分量的絕對值與正的 max_speed 都應不超過 16383。上限小於或等於零時,速度歸零。忽略 NULL,但不會因啟用狀態或質量而略過修改。整數量化可能使結果低於上限,極小的縮放係數也可能使結果成為零。
使用範例
kq2d_body_limit_speed(&body,250);
result[2]=body.vx; result[3]=body.vy;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
紅色物體保持原位。綠色速度線由左側的 (8,16) 變為右側的 (2,-8),呈現對藍色表面的反彈與切向摩擦。面板原點為螢幕 (8,48)/(88,48),物體中心為面板內的 (24,40)。入射速率為 16,穿越時間範例傳回 192/256。速度限制範例將 (300,400) 降為 (147,196)。DMG 上所有標記皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_surface.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_surface.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics2d.h:92
Conservative circular bound, with a shared Q8 scale for both components. Quantizes toward zero; very small limits relative to input may yield zero. Components and positive max_speed must be <= 16383 in magnitude.
kitaqgb/lib/physics2d.c:260
void kq2d_body_limit_speed(KQBody2D* body, s16 max_speed)
{
u16 x;
u16 y;
u16 swap;
u16 ratio;
u16 length;
if (body == 0) return;
if (max_speed <= 0) { body->vx = 0; body->vy = 0; return; }
x = (u16)body->vx;
y = (u16)body->vy;
if (body->vx < 0) x = (u16)(0 - body->vx);
if (body->vy < 0) y = (u16)(0 - body->vy);
if (x + y <= (u16)max_speed) return;
if (x < y) { swap = x; x = y; y = swap; }
// major + minor/2 bounds hypot from above for 0 <= minor <= major.
if (x + (y >> 1) + 1 <= (u16)max_speed) return;
// Round the minor/major ratio upward for the 65-entry upper-bound table.
// The extra unit covers truncation when converting the estimate back to speed.
ratio = (kq2d__fraction_q8(y, x) + 4) >> 2;
if (ratio > 64) ratio = 64;
length = x + (u16)kq2d_scale_q8((s16)x, (s16)kq2d_hypot_extra[(__safe_index u8)ratio]) + 1;
if (length <= (u16)max_speed) return;
ratio = kq2d__fraction_q8((u16)max_speed, length);
body->vx = kq2d_scale_q8(body->vx, (s16)ratio);
body->vy = kq2d_scale_q8(body->vy, (s16)ratio);
}kq2d_body_resolve_surface
此 API 在本機版中的差異,請參閱 2026-10-03 差異與驗證。
以相對於移動表面的速度,套用法線方向反彈、最低反彈速率與切向摩擦。
語法
s16 kq2d_body_resolve_surface(KQBody2D* body, const KQSurface2D* surface);參數
body指向要修改的物體。本操作未使用的欄位會保持不變。
surface指向包含法線、速度、反彈與摩擦設定的 KQSurface2D。
回傳值
傳回正的法線方向入射速率;輸入為 NULL 或彼此分離時傳回 0。
使用條件與限制
使用長度為 256 的 Q8 單位法線。相對速度分量須在 +/-8191 內,threshold/kick 須非負,係數須在 0..255。僅在入射速率嚴格大於門檻時套用恢復係數,kick 作為最低反彈速率。輸入為 NULL 或彼此分離時,不改變速度。接觸偵測與穿入修正須另外處理;不檢查啟用狀態或質量。
使用範例
result[6]=kq2d_body_resolve_surface(&body,&surface);
result[7]=body.vx; result[8]=body.vy; result[9]=body.y;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
紅色物體保持原位。綠色速度線由左側的 (8,16) 變為右側的 (2,-8),呈現對藍色表面的反彈與切向摩擦。面板原點為螢幕 (8,48)/(88,48),物體中心為面板內的 (24,40)。入射速率為 16,穿越時間範例傳回 192/256。速度限制範例將 (300,400) 降為 (147,196)。DMG 上所有標記皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_surface.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_surface.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics2d.h:95
Kinematic surface response; returns incoming normal speed, or zero if separating. Caller resolves penetration separately. Relative components must fit +/-8191.
kitaqgb/lib/physics2d.c:314
s16 kq2d_body_resolve_surface(KQBody2D* body, const KQSurface2D* surface)
{
s16 vx;
s16 vy;
s16 speed;
s16 tangent;
s16 bounce = 0;
s16 impulse;
s16 friction;
if (body == 0 || surface == 0) return 0;
vx = (s16)(body->vx - surface->vx);
vy = (s16)(body->vy - surface->vy);
speed = (s16)(kq2d_scale_q8(vx,surface->nx_q8) + kq2d_scale_q8(vy,surface->ny_q8));
if (speed >= 0) return 0;
speed = (s16)(0 - speed);
if (speed > surface->bounce_threshold) bounce = kq2d_scale_q8(speed,(s16)surface->restitution_q8);
if (bounce < surface->kick) bounce = surface->kick;
impulse = (s16)(speed + bounce);
// A resting contact is a tangent constraint, not a tiny rounded bounce.
if (bounce == 0) {
tangent = (s16)(kq2d__rest_component(vy,surface->nx_q8) - kq2d__rest_component(vx,surface->ny_q8));
friction = kq2d_scale_q8(impulse,(s16)surface->friction_q8);
if (tangent > friction) tangent = (s16)(tangent - friction);
else if (tangent < (s16)(0 - friction)) tangent = (s16)(tangent + friction);
else tangent = 0;
body->vx = (s16)(surface->vx - kq2d__rest_component(tangent,surface->ny_q8));
body->vy = (s16)(surface->vy + kq2d__rest_component(tangent,surface->nx_q8));
return speed;
}
body->vx = (s16)(body->vx + kq2d_scale_q8(impulse,surface->nx_q8));
body->vy = (s16)(body->vy + kq2d_scale_q8(impulse,surface->ny_q8));
if (surface->friction_q8 != 0) {
tangent = (s16)(kq2d_scale_q8(vy,surface->nx_q8) - kq2d_scale_q8(vx,surface->ny_q8));
friction = kq2d_scale_q8(impulse,(s16)surface->friction_q8);
if (tangent > friction) tangent = friction;
if (tangent < (s16)(0 - friction)) tangent = (s16)(0 - friction);
body->vx = (s16)(body->vx + kq2d_scale_q8(tangent,surface->ny_q8));
body->vy = (s16)(body->vy - kq2d_scale_q8(tangent,surface->nx_q8));
}
return speed;
}kq2d_body_set_pos
只取代物體中心,保留速度、尺寸與啟用狀態。
語法
void kq2d_body_set_pos(KQBody2D* body, s16 x, s16 y);參數
body指向要修改的物體。本操作未使用的欄位會保持不變。
x中心或點的 X 座標;範例以像素為單位。
y中心或點的 Y 座標;範例中正方向朝下。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
忽略 NULL。指標有效時,未啟用及靜態物體也會被修改。
使用範例
kq2d_body_set_pos(&temp,-12,20);
result[5]=temp.x; result[6]=temp.y;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側為初始狀態,右側為一個刻度後。紅色 16x16 盒體的中心為 (24,24)、速度為 (4,16),之後到達 (28,36),在藍色地板上使 Y 速度歸零。面板原點位於螢幕座標 (8,48) 與 (88,48)。DMG 上所有標記皆為黑色。RAM 檢查也涵蓋初始化、設定函式、積分、矩形/點查詢與帶正負號的縮放運算。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body2d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body2d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics2d.h:56
Replace the center without altering velocity, extents or activity. Null is ignored.
kitaqgb/lib/physics2d.c:612
void kq2d_body_set_pos(KQBody2D* body, s16 x, s16 y)
{
if (body == 0) return;
body->x = x;
body->y = y;
}kq2d_body_set_velocity
直接設定速度,不限制其範圍,也不更新位置。
語法
void kq2d_body_set_velocity(KQBody2D* body, s16 vx, s16 vy);參數
body指向要修改的物體。本操作未使用的欄位會保持不變。
vx每個模擬刻度的 X 位移,單位與位置相同。
vy每個模擬刻度的 Y 位移,單位與位置相同。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
忽略 NULL。指標有效時,未啟用及靜態物體也會被修改。
使用範例
kq2d_body_set_velocity(&temp,40,-30);
result[7]=temp.vx; result[8]=temp.vy;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側為初始狀態,右側為一個刻度後。紅色 16x16 盒體的中心為 (24,24)、速度為 (4,16),之後到達 (28,36),在藍色地板上使 Y 速度歸零。面板原點位於螢幕座標 (8,48) 與 (88,48)。DMG 上所有標記皆為黑色。RAM 檢查也涵蓋初始化、設定函式、積分、矩形/點查詢與帶正負號的縮放運算。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body2d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body2d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics2d.h:58
Replace velocity without clamping or checking activity/mass. Null is ignored.
kitaqgb/lib/physics2d.c:620
void kq2d_body_set_velocity(KQBody2D* body, s16 vx, s16 vy)
{
if (body == 0) return;
body->vx = vx;
body->vy = vy;
}kq2d_integrate_body
對一個動態物體套用世界重力與每軸速度上限,再將速度加至位置。
語法
void kq2d_integrate_body(KQWorld2D* world, KQBody2D* body);參數
world指向持有物體陣列與模擬設定的世界。
body指向要修改的物體。本操作未使用的欄位會保持不變。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
總和、差值、半長總和及接觸位置修正的乘積都必須落在帶正負號的 16 位元範圍內。速度限制在加法之後才套用,無法防止加法本身溢位。
盒體積分與碰撞函式共用暫存空間。請勿從中斷重入這些物理函式。
忽略 NULL、未啟用物體及反質量小於或等於零的物體。速度上限請提供非負值。
此呼叫不處理與其他物體的接觸。world 為 NULL 時也會忽略。
使用範例
kq2d_integrate_body(&world,&temp);
result[18]=temp.x; result[19]=temp.y;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側為初始狀態,右側為一個刻度後。紅色 16x16 盒體的中心為 (24,24)、速度為 (4,16),之後到達 (28,36),在藍色地板上使 Y 速度歸零。面板原點位於螢幕座標 (8,48) 與 (88,48)。DMG 上所有標記皆為黑色。RAM 檢查也涵蓋初始化、設定函式、積分、矩形/點查詢與帶正負號的縮放運算。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body2d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body2d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics2d.h:47
For one active dynamic body, add gravity, clamp each velocity axis and then add velocity to position. Null inputs are ignored; no contacts are solved. Use a nonnegative speed limit and keep additions in signed 16-bit range.
kitaqgb/lib/physics2d.c:664
void kq2d_integrate_body(KQWorld2D* world, KQBody2D* body)
{
if (world == 0) return;
if (body == 0) return;
if (body->active == 0) return;
if (body->inv_mass_q8 <= 0) return;
kq2d_asm_value = body->vx;
kq2d_asm_operand = world->gravity_x;
kq2d_add_s16_asm();
kq2d_asm_limit = world->max_speed;
kq2d_clamp_abs_s16_asm();
body->vx = kq2d_asm_value;
kq2d_asm_value = body->vy;
kq2d_asm_operand = world->gravity_y;
kq2d_add_s16_asm();
kq2d_asm_limit = world->max_speed;
kq2d_clamp_abs_s16_asm();
body->vy = kq2d_asm_value;
kq2d_asm_value = body->x;
kq2d_asm_operand = body->vx;
kq2d_add_s16_asm();
body->x = kq2d_asm_value;
kq2d_asm_value = body->y;
kq2d_asm_operand = body->vy;
kq2d_add_s16_asm();
body->y = kq2d_asm_value;
}kq2d_overlap_aabb
檢查兩個以中心表示的盒體是否在 X、Y 兩軸皆嚴格重疊。
語法
u8 kq2d_overlap_aabb(const KQBody2D* a, const KQBody2D* b);參數
a有效的物體指標。此查詢忽略啟用狀態、質量與旗標。
b有效的物體指標。此查詢忽略啟用狀態、質量與旗標。
回傳值
內部重疊時傳回 1,僅相觸或分離時傳回 0。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
總和、差值、半長總和及接觸位置修正的乘積都必須落在帶正負號的 16 位元範圍內。速度限制在加法之後才套用,無法防止加法本身溢位。
使用範例
result[20]=kq2d_overlap_aabb(&bodies[0],&bodies[1]);
bodies[1].x=40; result[21]=kq2d_overlap_aabb(&bodies[0],&bodies[1]);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側為初始狀態,右側為一個刻度後。紅色 16x16 盒體的中心為 (24,24)、速度為 (4,16),之後到達 (28,36),在藍色地板上使 Y 速度歸零。面板原點位於螢幕座標 (8,48) 與 (88,48)。DMG 上所有標記皆為黑色。RAM 檢查也涵蓋初始化、設定函式、積分、矩形/點查詢與帶正負號的縮放運算。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body2d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body2d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics2d.h:51
Test strict overlap of two centered boxes; touching edges return false. Both pointers must be valid. Active/mass flags are ignored, and coordinate differences and extent sums must fit the signed 16-bit calculations.
kitaqgb/lib/physics2d.c:579
u8 kq2d_overlap_aabb(const KQBody2D* a, const KQBody2D* b)
{
s16 dx = (s16)(b->x - a->x);
s16 dy = (s16)(b->y - a->y);
s16 adx = kq2d__abs_s16(dx);
s16 ady = kq2d__abs_s16(dy);
s16 sx = (s16)(a->half_x + b->half_x);
s16 sy = (s16)(a->half_y + b->half_y);
if (adx >= sx) return 0;
if (ady >= sy) return 0;
return 1;
}kq2d_point_in_rect
檢查點是否位於矩形內;包含左邊與上邊,不包含右邊與下邊。
語法
u8 kq2d_point_in_rect(s16 x, s16 y, KQRect r);參數
x中心或點的 X 座標;範例以像素為單位。
y中心或點的 Y 座標;範例中正方向朝下。
rKQRect 值,包含左上角位置 x/y 與寬度/高度 w/h。
回傳值
位於內部時傳回 1,外部時傳回 0。
使用條件與限制
總和、差值、半長總和及接觸位置修正的乘積都必須落在帶正負號的 16 位元範圍內。速度限制在加法之後才套用,無法防止加法本身溢位。
使用範例
result[16]=kq2d_point_in_rect(0,0,r1);
result[17]=kq2d_point_in_rect(16,0,r1);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側為初始狀態,右側為一個刻度後。紅色 16x16 盒體的中心為 (24,24)、速度為 (4,16),之後到達 (28,36),在藍色地板上使 Y 速度歸零。面板原點位於螢幕座標 (8,48) 與 (88,48)。DMG 上所有標記皆為黑色。RAM 檢查也涵蓋初始化、設定函式、積分、矩形/點查詢與帶正負號的縮放運算。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body2d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body2d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics2d.h:72
Delegate the half-open point test: include left/top and exclude right/bottom. Coordinate-plus-size sums must remain representable as s16.
kitaqgb/lib/physics2d.c:705
u8 kq2d_point_in_rect(s16 x, s16 y, KQRect r)
{
return kq_point_in_rect(x, y, r);
}kq2d_rect_intersect
檢查以左上角位置與尺寸表示的兩個矩形,其內部是否重疊。
語法
u8 kq2d_rect_intersect(KQRect a, KQRect b);參數
aKQRect 值,包含左上角座標及正的寬度與高度。
bKQRect 值,包含左上角座標及正的寬度與高度。
回傳值
內部重疊時傳回 1,僅相觸或分離時傳回 0。
使用條件與限制
總和、差值、半長總和及接觸位置修正的乘積都必須落在帶正負號的 16 位元範圍內。速度限制在加法之後才套用,無法防止加法本身溢位。
不會明確拒絕非正尺寸。請勿將物體中心與半長直接複製到 KQRect。
使用範例
result[14]=kq2d_rect_intersect(r1,r2);
r2.x=16; result[15]=kq2d_rect_intersect(r1,r2);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側為初始狀態,右側為一個刻度後。紅色 16x16 盒體的中心為 (24,24)、速度為 (4,16),之後到達 (28,36),在藍色地板上使 Y 速度歸零。面板原點位於螢幕座標 (8,48) 與 (88,48)。DMG 上所有標記皆為黑色。RAM 檢查也涵蓋初始化、設定函式、積分、矩形/點查詢與帶正負號的縮放運算。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body2d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body2d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics2d.h:69
Delegate strict rectangle overlap to the fixed-point utility; edge-only contact is false. Coordinate-plus-size sums must remain representable as s16.
kitaqgb/lib/physics2d.c:698
u8 kq2d_rect_intersect(KQRect a, KQRect b)
{
return kq_rect_intersect(a, b);
}kq2d_scale_q8
此 API 在本機版中的差異,請參閱 2026-10-03 差異與驗證。
乘上帶正負號的係數再除以 256,不分正負皆向零截斷。
語法
s16 kq2d_scale_q8(s16 value, s16 coefficient);參數
value要縮放的帶正負號 16 位元值。
coefficient範圍為 -256..256 的帶正負號係數,256 代表 1.0。
回傳值
傳回向零截斷的帶正負號 16 位元結果。
使用條件與限制
係數只能使用 -256..256;+/-256 代表 +/-1 倍。value=-32768 且 coefficient=-256 時,數學結果為 32768,無法以 s16 表示。
使用範例
result[0]=kq2d_scale_q8(-257,128);
result[1]=kq2d_scale_q8(300,-256);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
紅色物體保持原位。綠色速度線由左側的 (8,16) 變為右側的 (2,-8),呈現對藍色表面的反彈與切向摩擦。面板原點為螢幕 (8,48)/(88,48),物體中心為面板內的 (24,40)。入射速率為 16,穿越時間範例傳回 192/256。速度限制範例將 (300,400) 降為 (147,196)。DMG 上所有標記皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_surface.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_surface.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics2d.h:88
Truncates toward zero, including negative values; coefficient is -256..256.
kitaqgb/lib/physics2d.c:8
s16 kq2d_scale_q8(s16 value, s16 coefficient)
{
// Eight-bit shift/add product in HL:C, with sign applied after truncation.
__asm {
LD_HL_IMM value
LD_A_HL
LD_E_A
INC_HL
LD_A_HL
LD_D_A
OR_E
JP_Z kqscale_zero
LD_HL_IMM coefficient
LD_A_HL
LD_C_A
INC_HL
LD_A_HL
LD_B_A
LD_A_C
OR_A
JR_NZ kqscale_fraction
LD_A_B
OR_A
JP_Z kqscale_zero
LD_H_D
LD_L_E
AND_IMM 128
RET_Z
JP kqscale_negate
kqscale_fraction:
LD_A_D
XOR_B
AND_IMM 128
PUSH_AF
LD_A_D
AND_IMM 128
JR_Z kqscale_value_positive
XOR_A
SUB_E
LD_E_A
LD_A_IMM 0
SBC_D
LD_D_A
kqscale_value_positive:
LD_A_B
AND_IMM 128
JR_Z kqscale_coefficient_positive
XOR_A
SUB_C
LD_C_A
kqscale_coefficient_positive:
LD_HL_IMM 0
// Unroll eight bits: avoid a loop branch on every fixed-point product.
LD_A_C
AND_IMM 1
JR_Z kqscale_shift_0
ADD_HL_DE
kqscale_shift_0:
LD_A_H
RRA
LD_H_A
LD_A_L
RRA
LD_L_A
LD_A_C
RRA
LD_C_A
LD_A_C
AND_IMM 1
JR_Z kqscale_shift_1
ADD_HL_DE
kqscale_shift_1:
LD_A_H
RRA
LD_H_A
LD_A_L
RRA
LD_L_A
LD_A_C
RRA
LD_C_A
LD_A_C
AND_IMM 1
JR_Z kqscale_shift_2
ADD_HL_DE
kqscale_shift_2:
LD_A_H
RRA
LD_H_A
LD_A_L
RRA
LD_L_A
LD_A_C
RRA
LD_C_A
LD_A_C
AND_IMM 1
JR_Z kqscale_shift_3
ADD_HL_DE
kqscale_shift_3:
LD_A_H
RRA
LD_H_A
LD_A_L
RRA
LD_L_A
LD_A_C
RRA
LD_C_A
LD_A_C
AND_IMM 1
JR_Z kqscale_shift_4
ADD_HL_DE
kqscale_shift_4:
LD_A_H
RRA
LD_H_A
LD_A_L
RRA
LD_L_A
LD_A_C
RRA
LD_C_A
LD_A_C
AND_IMM 1
JR_Z kqscale_shift_5
ADD_HL_DE
kqscale_shift_5:
LD_A_H
RRA
LD_H_A
LD_A_L
RRA
LD_L_A
LD_A_C
RRA
LD_C_A
LD_A_C
AND_IMM 1
JR_Z kqscale_shift_6
ADD_HL_DE
kqscale_shift_6:
LD_A_H
RRA
LD_H_A
LD_A_L
RRA
LD_L_A
LD_A_C
RRA
LD_C_A
LD_A_C
AND_IMM 1
JR_Z kqscale_shift_7
ADD_HL_DE
kqscale_shift_7:
LD_A_H
RRA
LD_H_A
LD_A_L
RRA
LD_L_A
LD_A_C
RRA
LD_C_A
POP_AF
OR_A
RET_Z
kqscale_negate:
XOR_A
SUB_L
LD_L_A
LD_A_IMM 0
SBC_H
LD_H_A
RET
kqscale_zero:
LD_HL_IMM 0
RET
}
}kq2d_step
先積分作用中的動態物體,再處理陣列中已啟用項目之間的接觸。
語法
void kq2d_step(KQWorld2D* world);參數
world指向持有物體陣列與模擬設定的世界。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
世界僅借用陣列。呼叫端負責配置並持有物體儲存空間,且須在使用期間維持其有效。初始化世界不會初始化陣列元素。
總和、差值、半長總和及接觸位置修正的乘積都必須落在帶正負號的 16 位元範圍內。速度限制在加法之後才套用,無法防止加法本身溢位。
接觸沿穿入較淺的軸處理,深度相同時選 Y 軸。位置修正使用反質量,但兩個動態物體在該軸的速度會設為兩者的簡單平均;碰到靜態物體時,該速度分量歸零。此求解器不使用 restitution_q8。這是離散碰撞處理,可能漏掉快速穿越。
盒體積分與碰撞函式共用暫存空間。請勿從中斷重入這些物理函式。
world 或陣列為 NULL 時忽略。即使 solver_iterations 為零,仍會執行一次接觸處理。
使用範例
kq2d_step(&world);
result[22]=bodies[0].x; result[23]=bodies[0].y;
result[24]=bodies[0].vx; result[25]=bodies[0].vy;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側為初始狀態,右側為一個刻度後。紅色 16x16 盒體的中心為 (24,24)、速度為 (4,16),之後到達 (28,36),在藍色地板上使 Y 速度歸零。面板原點位於螢幕座標 (8,48) 與 (88,48)。DMG 上所有標記皆為黑色。RAM 檢查也涵蓋初始化、設定函式、積分、矩形/點查詢與帶正負號的縮放運算。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body2d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body2d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics2d.h:43
Advance active dynamic bodies, then visit each active unordered pair for the configured contact passes (zero means one). Static bodies still participate as obstacles. The world borrows its array and shares non-reentrant ASM scratch. This is discrete integration; fast bodies can pass through thin obstacles.
kitaqgb/lib/physics2d.c:794
void kq2d_step(KQWorld2D* world)
{
if (world == 0) return;
if (world->bodies == 0) return;
KQBody2D* bodies = world->bodies;
u8 count = world->body_count;
// Integrate dynamic bodies.
u8 i;
for (i = 0; i < count; i++)
{
KQBody2D* b = &bodies[(__safe_index u8)i];
if (b->active == 0) continue;
if (b->inv_mass_q8 <= 0) continue;
kq2d_asm_value = b->vx;
kq2d_asm_operand = world->gravity_x;
kq2d_add_s16_asm();
kq2d_asm_limit = world->max_speed;
kq2d_clamp_abs_s16_asm();
b->vx = kq2d_asm_value;
kq2d_asm_value = b->vy;
kq2d_asm_operand = world->gravity_y;
kq2d_add_s16_asm();
kq2d_asm_limit = world->max_speed;
kq2d_clamp_abs_s16_asm();
b->vy = kq2d_asm_value;
kq2d_asm_value = b->x;
kq2d_asm_operand = b->vx;
kq2d_add_s16_asm();
b->x = kq2d_asm_value;
kq2d_asm_value = b->y;
kq2d_asm_operand = b->vy;
kq2d_add_s16_asm();
b->y = kq2d_asm_value;
}
// Solve contacts with a small fixed iteration count.
u8 iterations = world->solver_iterations;
if (iterations == 0) iterations = 1;
u8 it;
for (it = 0; it < iterations; it++)
{
for (i = 0; i < count; i++)
{
KQBody2D* a = &bodies[(__safe_index u8)i];
if (a->active == 0) continue;
u8 j;
for (j = (u8)(i + 1); j < count; j++)
{
KQBody2D* b = &bodies[(__safe_index u8)j];
if (b->active == 0) continue;
kq2d__resolve_pair(a, b);
}
}
}
}kq2d_surface_toi_q8
假設線性運動,以起始與結束的帶正負號間距估計刻度內的穿越時間。
語法
u16 kq2d_surface_toi_q8(s16 start_gap, s16 end_gap);參數
start_gap刻度開始時的帶正負號間距;正值表示位於表面外側。
end_gap刻度結束時的帶正負號間距;負值表示已越過表面。
回傳值
傳回 0..256 的 Q8 時間;192 代表該刻度的 75%。
使用條件與限制
間距須在 +/-8191 內。起始間距小於或等於零時傳回 0;結束間距大於或等於零時傳回 256。初始重疊與時間零共用回傳值,沒有穿越與恰好在終點接觸也共用回傳值。不改變位置。
使用範例
result[4]=kq2d_surface_toi_q8(6,-2);
result[5]=kq2d_surface_toi_q8(6,0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
紅色物體保持原位。綠色速度線由左側的 (8,16) 變為右側的 (2,-8),呈現對藍色表面的反彈與切向摩擦。面板原點為螢幕 (8,48)/(88,48),物體中心為面板內的 (24,40)。入射速率為 16,穿越時間範例傳回 192/256。速度限制範例將 (300,400) 降為 (147,196)。DMG 上所有標記皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_surface.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_surface.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics2d.h:98
Linear crossing time in Q8 (0..256); positive separation is outside. Returns 0 for initial overlap, 256 for no crossing. Gaps must fit +/-8191.
kitaqgb/lib/physics2d.c:291
u16 kq2d_surface_toi_q8(s16 start_gap, s16 end_gap)
{
if (start_gap <= 0) return 0;
if (end_gap >= 0) return 256;
return kq2d__fraction_q8((u16)start_gap, (u16)(start_gap - end_gap));
}kq2d_world_init
將陣列連接至 2D 世界,設定重力為 (0,32)、接觸迭代 4 次,以及每軸速度上限 512。
語法
void kq2d_world_init(KQWorld2D* world, KQBody2D* bodies, u8 body_count);參數
world指向持有物體陣列與模擬設定的世界。
bodies呼叫端持有的物體陣列起始位置,包含 body_count 個元素。
body_count陣列欄位數量,範圍為 0..255,包含未啟用的項目。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
世界僅借用陣列。呼叫端負責配置並持有物體儲存空間,且須在使用期間維持其有效。初始化世界不會初始化陣列元素。
使用範例
kq2d_world_init(&world,bodies,2);
result[0]=world.gravity_y; result[1]=world.solver_iterations; result[2]=world.max_speed;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側為初始狀態,右側為一個刻度後。紅色 16x16 盒體的中心為 (24,24)、速度為 (4,16),之後到達 (28,36),在藍色地板上使 Y 速度歸零。面板原點位於螢幕座標 (8,48) 與 (88,48)。DMG 上所有標記皆為黑色。RAM 檢查也涵蓋初始化、設定函式、積分、矩形/點查詢與帶正負號的縮放運算。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body2d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body2d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics2d.h:38
Retain the caller-owned body array without initializing its elements. Set gravity to (0,32), four contact iterations and a per-axis speed limit of 512. A null world is ignored; the array must outlive subsequent world operations.
kitaqgb/lib/physics2d.c:564
void kq2d_world_init(KQWorld2D* world, KQBody2D* bodies, u8 body_count)
{
if (world == 0) return;
world->bodies = bodies;
world->body_count = body_count;
world->gravity_x = 0;
world->gravity_y = 32;
world->solver_iterations = 4;
world->max_speed = 512;
}physics2d_circle.h — 圓形物體物理
支援圓形半徑、反質量、恢復係數、切向摩擦、世界阻尼與邊界。呼叫端須初始化所有物體欄位。物體的 friction_q8 與 wall_friction_q8 表示移除的切向運動比例,linear_damping_q8 則表示保留的速度比例。位元組係數除以 256,因此 255 並不等於 1.0。
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
圓形的距離與法線採用整數近似。即使各分量降至 255 以下,也不能保證平方距離總和不超過 65535。中心差值、半徑總和與反質量總和都必須能以其資料型別表示;權重計算中的 inv_mass_q8 * 255 也必須不超過 32767。範例使用 64。
kq2dc_overlap_circle
使用縮減後的中心距離與半徑總和,近似判定內部重疊。
語法
u8 kq2dc_overlap_circle(const KQCircleBody2D* a, const KQCircleBody2D* b);參數
a指向第一個圓的有效指標。
b指向第二個圓的有效指標。
回傳值
內部重疊時傳回 1,僅相觸或分離時傳回 0。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
圓形的距離與法線採用整數近似。即使各分量降至 255 以下,也不能保證平方距離總和不超過 65535。中心差值、半徑總和與反質量總和都必須能以其資料型別表示;權重計算中的 inv_mass_q8 * 255 也必須不超過 32767。範例使用 64。
需要兩個有效指標及正半徑。忽略啟用狀態與質量。縮減運算與整數平方根可能使結果與精確的幾何距離測試不同。
使用範例
result[4]=kq2dc_overlap_circle(&balls[0],&balls[1]);
balls[1].x=18; result[5]=kq2dc_overlap_circle(&balls[0],&balls[1]);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
半徑 6 的紅色圓由左側中心 (24,24) 移至右側的 (54,24)。面板內邊界為 (4,4)..(60,60)。右牆將圓心限制在 54,並將 X 速度從 32 改為 -15:先套用牆面恢復係數 128/256,再套用阻尼 255/256。面板原點位於螢幕 (8,48)/(88,48)。DMG 上圓與邊界皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_circle.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_circle.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics2d_circle.h:55
Compare a reduced integer center distance with the reduced radius sum. Valid pointers and positive radii are required; activity and mass are ignored. This approximate test requires representable differences, radius sums and squared-distance sum. Touching at the computed distance returns false.
kitaqgb/lib/physics2d_circle.c:397
u8 kq2dc_overlap_circle(const KQCircleBody2D* a, const KQCircleBody2D* b)
{
s16 dx;
s16 dy;
s16 sdx;
s16 sdy;
u8 shift;
u16 adx;
u16 ady;
u16 dist_sq;
u16 dist_scaled;
s16 radius_sum;
u16 radius_sum_scaled;
dx = (s16)(b->x - a->x);
dy = (s16)(b->y - a->y);
sdx = dx;
sdy = dy;
shift = kq2dc__reduce_vector(&sdx, &sdy);
adx = (u16)kq2dc__abs_s16(sdx);
ady = (u16)kq2dc__abs_s16(sdy);
dist_sq = (u16)((adx * adx) + (ady * ady));
dist_scaled = kq2dc__isqrt_u16(dist_sq);
radius_sum = (s16)(a->radius + b->radius);
radius_sum_scaled = kq2dc__scale_down_positive(radius_sum, shift);
if (dist_scaled >= radius_sum_scaled) return 0;
return 1;
}kq2dc_set_bounds
儲存並啟用圓形世界的邊界,不會立即移動物體。
語法
void kq2dc_set_bounds(KQCircleWorld2D* world, s16 min_x, s16 min_y, s16 max_x, s16 max_y);參數
world指向持有物體陣列與模擬設定的世界。
min_x左側邊界;圓心不得小於 min_x + radius。
min_y上側邊界;圓心不得小於 min_y + radius。
max_x右側邊界;圓心不得大於 max_x - radius。
max_y下側邊界;圓心不得大於 max_y - radius。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
忽略 NULL。不檢查邊界順序或容納空間,因此寬度與高度至少須等於圓的直徑。實際位置修正在模擬步驟中進行。
使用範例
kq2dc_set_bounds(&world,4,4,60,60);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
半徑 6 的紅色圓由左側中心 (24,24) 移至右側的 (54,24)。面板內邊界為 (4,4)..(60,60)。右牆將圓心限制在 54,並將 X 速度從 32 改為 -15:先套用牆面恢復係數 128/256,再套用阻尼 255/256。面板原點位於螢幕 (8,48)/(88,48)。DMG 上圓與邊界皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_circle.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_circle.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics2d_circle.h:45
Store and enable bounds without validating their order or fitting bodies immediately. Supply extents large enough for body diameters. Null is ignored.
kitaqgb/lib/physics2d_circle.c:382
void kq2dc_set_bounds(KQCircleWorld2D* world, s16 min_x, s16 min_y, s16 max_x, s16 max_y)
{
if (world == 0) return;
world->use_bounds = 1;
world->min_x = min_x;
world->min_y = min_y;
world->max_x = max_x;
world->max_y = max_y;
}kq2dc_step
先積分圓形,處理邊界與圓形之間的接觸,再套用線性阻尼。
語法
void kq2dc_step(KQCircleWorld2D* world);參數
world指向持有物體陣列與模擬設定的世界。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
世界僅借用陣列。呼叫端負責配置並持有物體儲存空間,且須在使用期間維持其有效。初始化世界不會初始化陣列元素。
圓形的距離與法線採用整數近似。即使各分量降至 255 以下,也不能保證平方距離總和不超過 65535。中心差值、半徑總和與反質量總和都必須能以其資料型別表示;權重計算中的 inv_mass_q8 * 255 也必須不超過 32767。範例使用 64。
最後將 -1..1 的速度分量歸零。即使阻尼為 255,速度仍會略減。靜止圓之間可能殘留重疊。啟用邊界時,靜態圓也會被移入邊界。迭代次數為零代表執行一次;忽略 NULL 世界/陣列。此求解器採離散與量化運算,速度改變時,處理接觸的順序也可能不同。
使用範例
kq2dc_step(&world);
result[6]=balls[0].x; result[7]=balls[0].y; result[8]=balls[0].vx;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
半徑 6 的紅色圓由左側中心 (24,24) 移至右側的 (54,24)。面板內邊界為 (4,4)..(60,60)。右牆將圓心限制在 54,並將 X 速度從 32 改為 -15:先套用牆面恢復係數 128/256,再套用阻尼 255/256。面板原點位於螢幕 (8,48)/(88,48)。DMG 上圓與邊界皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_circle.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_circle.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics2d_circle.h:50
Integrate active dynamic bodies, apply bounds, solve contacts, then damp velocity and snap components in -1..1 to zero. Zero solver iterations means one. Pairs with both velocities zero are skipped, so resting overlaps can remain. Bounds can reposition static bodies; null world/array inputs are ignored.
kitaqgb/lib/physics2d_circle.c:433
void kq2dc_step(KQCircleWorld2D* world)
{
KQCircleBody2D* bodies;
u8 count;
u8 i;
u8 iterations;
u8 it;
if (world == 0) return;
if (world->bodies == 0) return;
bodies = world->bodies;
count = world->body_count;
for (i = 0; i < count; i++)
{
KQCircleBody2D* body = &bodies[(__safe_index u8)i];
if (body->active == 0) continue;
if (body->inv_mass_q8 <= 0)
{
if (world->use_bounds != 0) kq2dc__resolve_bounds(world, body);
continue;
}
body->vx = (s16)(body->vx + world->gravity_x);
body->vy = (s16)(body->vy + world->gravity_y);
body->vx = kq2dc__clamp_abs(body->vx, world->max_speed);
body->vy = kq2dc__clamp_abs(body->vy, world->max_speed);
body->x = (s16)(body->x + body->vx);
body->y = (s16)(body->y + body->vy);
if (world->use_bounds != 0) kq2dc__resolve_bounds(world, body);
}
iterations = world->solver_iterations;
if (iterations == 0) iterations = 1;
for (it = 0; it < iterations; it++)
{
for (i = 0; i < count; i++)
{
KQCircleBody2D* a = &bodies[(__safe_index u8)i];
if (a->active == 0) continue;
if (a->vx == 0 && a->vy == 0) continue;
if (world->use_bounds != 0) kq2dc__resolve_bounds(world, a);
{
u8 j;
for (j = 0; j < count; j++)
{
KQCircleBody2D* b = &bodies[(__safe_index u8)j];
s16 radius_sum;
if (j == i) continue;
if (b->active == 0) continue;
// Avoid revisiting an earlier moving body, but still allow a moving body
// to resolve against a stationary slot with a lower index. Velocities are live
// solver state, so contact ordering can change which later pairs are visited.
if (j < i && (b->vx != 0 || b->vy != 0)) continue;
radius_sum = (s16)(a->radius + b->radius);
if (kq2dc__abs_s16((s16)(b->x - a->x)) >= radius_sum) continue;
if (kq2dc__abs_s16((s16)(b->y - a->y)) >= radius_sum) continue;
kq2dc__resolve_pair(a, b);
}
}
}
}
for (i = 0; i < count; i++)
{
KQCircleBody2D* body = &bodies[(__safe_index u8)i];
if (body->active == 0) continue;
if (body->inv_mass_q8 <= 0) continue;
body->vx = kq2dc__mul_q8(body->vx, world->linear_damping_q8);
body->vy = kq2dc__mul_q8(body->vy, world->linear_damping_q8);
if (body->vx >= -1 && body->vx <= 1) body->vx = 0;
if (body->vy >= -1 && body->vy <= 1) body->vy = 0;
if (world->use_bounds != 0) kq2dc__resolve_bounds(world, body);
}
}kq2dc_world_init
連接圓形陣列,設定零重力、4 次處理、每軸速度上限 768 與阻尼 252/256。
語法
void kq2dc_world_init(KQCircleWorld2D* world, KQCircleBody2D* bodies, u8 body_count);參數
world指向持有物體陣列與模擬設定的世界。
bodies呼叫端持有的物體陣列起始位置,包含 body_count 個元素。
body_count陣列欄位數量,範圍為 0..255,包含未啟用的項目。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
世界僅借用陣列。呼叫端負責配置並持有物體儲存空間,且須在使用期間維持其有效。初始化世界不會初始化陣列元素。
邊界初始值為 (0,0)..(159,143),但預設停用;牆面恢復係數為 240,牆面摩擦為 16。沒有圓形物體初始化函式,呼叫端須設定所有物體欄位。world 為 NULL 時忽略。
使用範例
kq2dc_world_init(&world,balls,1);
result[0]=world.gravity_y; result[1]=world.solver_iterations;
result[2]=world.max_speed; result[3]=world.linear_damping_q8;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
半徑 6 的紅色圓由左側中心 (24,24) 移至右側的 (54,24)。面板內邊界為 (4,4)..(60,60)。右牆將圓心限制在 54,並將 X 速度從 32 改為 -15:先套用牆面恢復係數 128/256,再套用阻尼 255/256。面板原點位於螢幕 (8,48)/(88,48)。DMG 上圓與邊界皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_circle.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_circle.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics2d_circle.h:42
Retain a caller-owned array without initializing bodies. Set zero gravity, four contact passes, per-axis limit 768 and damping 252/256; bounds start disabled. A null world is ignored. Keep the array alive for subsequent steps.
kitaqgb/lib/physics2d_circle.c:360
void kq2dc_world_init(KQCircleWorld2D* world, KQCircleBody2D* bodies, u8 body_count)
{
if (world == 0) return;
world->bodies = bodies;
world->body_count = body_count;
world->gravity_x = 0;
world->gravity_y = 0;
world->solver_iterations = 4;
world->max_speed = 768;
world->linear_damping_q8 = 252;
world->use_bounds = 0;
world->min_x = 0;
world->min_y = 0;
world->max_x = 159;
world->max_y = 143;
world->wall_restitution_q8 = 240;
world->wall_friction_q8 = 16;
}physics3d.h — 3D AABB 物理
用於不旋轉的 3D 盒體,以中心及各軸半長表示。質量/反質量決定接觸權重,restitution_q8 控制反彈,ax/ay/az 提供持續加速度。繪製須另外處理。範例繪出同一物體的正視圖與俯視圖,呈現深度方向移動及牆面反彈。
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
physics3d.c 位於 ROM 記憶體庫 2。範例使用 MBC5 128 KB ROM,先引入此實作,再將 main 放在記憶體庫 0。呼叫期間,外部程式不得改變 ROM 映射。
last_impact_speed 記錄沿接觸軸的最大接近速度。積分時會清除作用中動態物體的此值;靜態及未啟用物體則保留。break_speed 與 KQ3D_BODY_BROKEN 都不會自動觸發破壞。遊戲自行決定何時破壞物體,並修改 flags/active。
kq3d_body_init
初始化 3D 中心、半長與質量;將速度、加速度、衝擊與旗標歸零,並啟用物體。
語法
void kq3d_body_init(KQBody3D* body, s16 x, s16 y, s16 z, s16 half_x, s16 half_y, s16 half_z, s16 mass_q8);參數
body指向要修改的物體。本操作未使用的欄位會保持不變。
x中心或點的 X 座標;範例以像素為單位。
y中心或點的 Y 座標;範例中正方向朝下。
z中心的 Z 座標,在範例俯視圖中以垂直方向呈現。
half_xX 軸半長;盒體的完整寬度為此值的兩倍。
half_yY 軸半長;盒體的完整高度為此值的兩倍。
half_zZ 軸半長;完整深度為此值的兩倍。
mass_q8質量值,256 代表 1.0;小於或等於零時建立靜態物體。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
physics3d.c 位於 ROM 記憶體庫 2。範例使用 MBC5 128 KB ROM,先引入此實作,再將 main 放在記憶體庫 0。呼叫期間,外部程式不得改變 ROM 映射。
恢復係數為 224,break_speed 為零。質量遵循 kq3d_body_set_mass 的規則。忽略 NULL;呼叫端須提供有效半長。
使用範例
kq3d_body_init(&temp,10,20,30,8,8,8,256);
result[3]=temp.inv_mass_q8; result[4]=temp.restitution_q8; result[5]=temp.active;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側是 X/Y 正視圖,右側是 X/Z 俯視圖。綠色輪廓標示初始位置 (24,24,16),紅色盒體顯示一個刻度後的 (36,24,24),藍色區域為靜態障礙物。X 速度由 16 反彈為 -14,Z 速度維持 8。衝擊值為 16,但即使 break_speed=1,flags 仍為零。面板原點位於螢幕 (8,48)/(88,48)。DMG 上所有標記皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body3d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics3d.h:50
Initialize an active centered box with zero velocity/acceleration, restitution 224, cleared impact/flags and mass set through the weight helper. The caller supplies valid half extents. Null body is ignored.
kitaqgb/lib/physics3d.c:330
void kq3d_body_init(KQBody3D* body, s16 x, s16 y, s16 z, s16 half_x, s16 half_y, s16 half_z, s16 mass_q8)
{
if (body == 0) return;
body->x = x;
body->y = y;
body->z = z;
body->vx = 0;
body->vy = 0;
body->vz = 0;
body->ax = 0;
body->ay = 0;
body->az = 0;
body->half_x = half_x;
body->half_y = half_y;
body->half_z = half_z;
body->restitution_q8 = 224;
body->break_speed = 0;
body->last_impact_speed = 0;
body->active = 1;
body->flags = 0;
kq3d_body_set_mass(body, mass_q8);
}kq3d_body_set_mass
儲存指定質量,並計算用於修正與反彈的反質量權重。
語法
void kq3d_body_set_mass(KQBody3D* body, s16 mass_q8);參數
body指向要修改的物體。本操作未使用的欄位會保持不變。
mass_q8質量值,256 代表 1.0;小於或等於零時建立靜態物體。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
physics3d.c 位於 ROM 記憶體庫 2。範例使用 MBC5 128 KB ROM,先引入此實作,再將 main 放在記憶體庫 0。呼叫期間,外部程式不得改變 ROM 映射。
質量小於或等於零時,反質量為零,代表靜態物體。正質量使用整數式 32767/max(mass,64),最小值為 1。儲存的質量保留請求值,因此此權重不是精確的 Q8 倒數。質量 256 得到反質量 127。速度與啟用狀態不變;忽略 NULL。
使用範例
kq3d_body_set_mass(&temp,32); result[6]=temp.mass_q8; result[7]=temp.inv_mass_q8;
kq3d_body_set_mass(&temp,0); result[8]=temp.inv_mass_q8;
kq3d_body_set_mass(&temp,256);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側是 X/Y 正視圖,右側是 X/Z 俯視圖。綠色輪廓標示初始位置 (24,24,16),紅色盒體顯示一個刻度後的 (36,24,24),藍色區域為靜態障礙物。X 速度由 16 反彈為 -14,Z 速度維持 8。衝擊值為 16,但即使 break_speed=1,flags 仍為零。面板原點位於螢幕 (8,48)/(88,48)。DMG 上所有標記皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body3d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics3d.h:55
Store the requested mass; nonpositive mass makes the body static. For positive mass compute inverse weight as max(1,32767/max(mass,64)). The stored mass retains the original input; this is a relative solver weight, not an exact Q8 reciprocal. Null body is ignored.
kitaqgb/lib/physics3d.c:311
void kq3d_body_set_mass(KQBody3D* body, s16 mass_q8)
{
if (body == 0) return;
body->mass_q8 = mass_q8;
if (mass_q8 <= 0)
{
body->inv_mass_q8 = 0;
return;
}
if (mass_q8 < 64) mass_q8 = 64;
body->inv_mass_q8 = (s16)(32767 / mass_q8);
if (body->inv_mass_q8 <= 0) body->inv_mass_q8 = 1;
}kq3d_dot_q8_8
將三個帶正負號乘積各除以 256,分別向零截斷後再相加。
語法
s16 kq3d_dot_q8_8(s16 x, s16 y, s16 z, s8 ax, s8 ay, s8 az);參數
x要乘上對應係數的帶正負號 16 位元分量,可代表位置或速度。
y要乘上對應係數的帶正負號 16 位元分量,可代表位置或速度。
z要乘上對應係數的帶正負號 16 位元分量,可代表位置或速度。
ax此軸的帶正負號位元組係數(-128..127),以 1/256 為比例套用。
ay此軸的帶正負號位元組係數(-128..127),以 1/256 為比例套用。
az此軸的帶正負號位元組係數(-128..127),以 1/256 為比例套用。
回傳值
以 s16 傳回三個量化項目的總和。
使用條件與限制
physics3d.c 位於 ROM 記憶體庫 2。範例使用 MBC5 128 KB ROM,先引入此實作,再將 main 放在記憶體庫 0。呼叫期間,外部程式不得改變 ROM 映射。
先將每一項向零截斷,可能與總和只位移一次的結果不同。係數無法儲存 1.0=256。最後的總和不做飽和處理。
使用範例
result[13]=kq3d_dot_q8_8(256,128,0,64,-64,127);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側是 X/Y 正視圖,右側是 X/Z 俯視圖。綠色輪廓標示初始位置 (24,24,16),紅色盒體顯示一個刻度後的 (36,24,24),藍色區域為靜態障礙物。X 速度由 16 反彈為 -14,Z 速度維持 8。衝擊值為 16,但即使 break_speed=1,flags 仍為零。面板原點位於螢幕 (8,48)/(88,48)。DMG 上所有標記皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body3d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics3d.h:74
Sum three signed products, shifting each by eight bits before addition. Coefficients are signed bytes scaled by 1/256; the 16-bit sum is not saturated.
kitaqgb/lib/physics3d.c:576
s16 kq3d_dot_q8_8(s16 x, s16 y, s16 z, s8 ax, s8 ay, s8 az)
{
return __sdot3_q8_8(x, y, z, ax, ay, az);
}kq3d_integrate_body
此 API 在本機版中的差異,請參閱 2026-10-03 差異與驗證。
清除一個作用中動態物體的衝擊值,加上世界重力與物體加速度,限制各軸速度,再推進位置。
語法
void kq3d_integrate_body(KQWorld3D* world, KQBody3D* body);參數
world指向持有物體陣列與模擬設定的世界。
body指向要修改的物體。本操作未使用的欄位會保持不變。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
總和、差值、半長總和及接觸位置修正的乘積都必須落在帶正負號的 16 位元範圍內。速度限制在加法之後才套用,無法防止加法本身溢位。
盒體積分與碰撞函式共用暫存空間。請勿從中斷重入這些物理函式。
physics3d.c 位於 ROM 記憶體庫 2。範例使用 MBC5 128 KB ROM,先引入此實作,再將 main 放在記憶體庫 0。呼叫期間,外部程式不得改變 ROM 映射。
last_impact_speed 記錄沿接觸軸的最大接近速度。積分時會清除作用中動態物體的此值;靜態及未啟用物體則保留。break_speed 與 KQ3D_BODY_BROKEN 都不會自動觸發破壞。遊戲自行決定何時破壞物體,並修改 flags/active。
ax/ay/az 會保留,並在下一次積分時再次套用。此函式本身不處理接觸。不修改 NULL、未啟用或靜態物體。
使用範例
kq3d_integrate_body(&world,&temp);
result[9]=temp.x; result[10]=temp.y; result[11]=temp.z; result[12]=temp.last_impact_speed;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側是 X/Y 正視圖,右側是 X/Z 俯視圖。綠色輪廓標示初始位置 (24,24,16),紅色盒體顯示一個刻度後的 (36,24,24),藍色區域為靜態障礙物。X 速度由 16 反彈為 -14,Z 速度維持 8。衝擊值為 16,但即使 break_speed=1,flags 仍為零。面板原點位於螢幕 (8,48)/(88,48)。DMG 上所有標記皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body3d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics3d.h:66
Reset impact for one active dynamic body, add gravity and persistent body acceleration, clamp velocity per axis and advance position. Static/inactive bodies retain impact state. Null inputs are ignored; no contacts are solved. Use a nonnegative speed limit and avoid overflow before clamping.
kitaqgb/lib/physics3d.c:436
void kq3d_integrate_body(KQWorld3D* world, KQBody3D* body)
{
if (world == 0) return;
if (body == 0) return;
if (body->active == 0) return;
if (body->inv_mass_q8 <= 0) return;
body->last_impact_speed = 0;
kq3d_asm_value = body->vx;
kq3d_asm_operand = world->gravity_x;
kq3d_add_s16_asm();
kq3d_asm_operand = body->ax;
kq3d_add_s16_asm();
kq3d_asm_limit = world->max_speed;
kq3d_clamp_abs_s16_asm();
body->vx = kq3d_asm_value;
kq3d_asm_value = body->vy;
kq3d_asm_operand = world->gravity_y;
kq3d_add_s16_asm();
kq3d_asm_operand = body->ay;
kq3d_add_s16_asm();
kq3d_asm_limit = world->max_speed;
kq3d_clamp_abs_s16_asm();
body->vy = kq3d_asm_value;
kq3d_asm_value = body->vz;
kq3d_asm_operand = world->gravity_z;
kq3d_add_s16_asm();
kq3d_asm_operand = body->az;
kq3d_add_s16_asm();
kq3d_asm_limit = world->max_speed;
kq3d_clamp_abs_s16_asm();
body->vz = kq3d_asm_value;
kq3d_asm_value = body->x;
kq3d_asm_operand = body->vx;
kq3d_add_s16_asm();
body->x = kq3d_asm_value;
kq3d_asm_value = body->y;
kq3d_asm_operand = body->vy;
kq3d_add_s16_asm();
body->y = kq3d_asm_value;
kq3d_asm_value = body->z;
kq3d_asm_operand = body->vz;
kq3d_add_s16_asm();
body->z = kq3d_asm_value;
}kq3d_overlap_aabb
檢查兩個以中心表示的盒體是否在三個軸皆嚴格重疊。
語法
u8 kq3d_overlap_aabb(const KQBody3D* a, const KQBody3D* b);參數
a有效的物體指標。此查詢忽略啟用狀態、質量與旗標。
b有效的物體指標。此查詢忽略啟用狀態、質量與旗標。
回傳值
內部重疊時傳回 1,僅相觸或分離時傳回 0。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
總和、差值、半長總和及接觸位置修正的乘積都必須落在帶正負號的 16 位元範圍內。速度限制在加法之後才套用,無法防止加法本身溢位。
physics3d.c 位於 ROM 記憶體庫 2。範例使用 MBC5 128 KB ROM,先引入此實作,再將 main 放在記憶體庫 0。呼叫期間,外部程式不得改變 ROM 映射。
使用範例
result[14]=kq3d_overlap_aabb(&bodies[0],&bodies[1]);
bodies[1].z=32; result[15]=kq3d_overlap_aabb(&bodies[0],&bodies[1]);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側是 X/Y 正視圖,右側是 X/Z 俯視圖。綠色輪廓標示初始位置 (24,24,16),紅色盒體顯示一個刻度後的 (36,24,24),藍色區域為靜態障礙物。X 速度由 16 反彈為 -14,Z 速度維持 8。衝擊值為 16,但即使 break_speed=1,flags 仍為零。面板原點位於螢幕 (8,48)/(88,48)。DMG 上所有標記皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body3d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics3d.h:70
Test strict overlap on all three axes; face-only contact returns false. Valid pointers are required and flags are ignored. Center differences and extent sums must fit the signed 16-bit magnitude calculations.
kitaqgb/lib/physics3d.c:357
u8 kq3d_overlap_aabb(const KQBody3D* a, const KQBody3D* b)
{
s16 dx = kq3d__abs_s16((s16)(b->x - a->x));
s16 dy = kq3d__abs_s16((s16)(b->y - a->y));
s16 dz = kq3d__abs_s16((s16)(b->z - a->z));
s16 sx = (s16)(a->half_x + b->half_x);
s16 sy = (s16)(a->half_y + b->half_y);
s16 sz = (s16)(a->half_z + b->half_z);
if (dx >= sx) return 0;
if (dy >= sy) return 0;
if (dz >= sz) return 0;
return 1;
}kq3d_step
此 API 在本機版中的差異,請參閱 2026-10-03 差異與驗證。
積分作用中的動態物體,並處理世界內已啟用項目之間的接觸修正、反彈與衝擊記錄。
語法
void kq3d_step(KQWorld3D* world);參數
world指向持有物體陣列與模擬設定的世界。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
世界僅借用陣列。呼叫端負責配置並持有物體儲存空間,且須在使用期間維持其有效。初始化世界不會初始化陣列元素。
總和、差值、半長總和及接觸位置修正的乘積都必須落在帶正負號的 16 位元範圍內。速度限制在加法之後才套用,無法防止加法本身溢位。
盒體積分與碰撞函式共用暫存空間。請勿從中斷重入這些物理函式。
physics3d.c 位於 ROM 記憶體庫 2。範例使用 MBC5 128 KB ROM,先引入此實作,再將 main 放在記憶體庫 0。呼叫期間,外部程式不得改變 ROM 映射。
接觸使用穿入最淺的軸,相同時依 X、Y、Z 的順序選擇。只有彼此接近的運動才會產生反彈,計算使用反質量,以及限制在 0..256 的平均恢復係數。不處理高速穿透、旋轉、角動量或摩擦。
last_impact_speed 記錄沿接觸軸的最大接近速度。積分時會清除作用中動態物體的此值;靜態及未啟用物體則保留。break_speed 與 KQ3D_BODY_BROKEN 都不會自動觸發破壞。遊戲自行決定何時破壞物體,並修改 flags/active。
world 或陣列為 NULL 時忽略。即使 solver_iterations 為零,仍會執行一次接觸處理。
中間運算 impact*(256+restitution) 與 correction*inverse-mass 的乘積也是 s16。乘積須不超過 32767;例如 restitution 為 256 時,impact 應不超過 63。
使用範例
kq3d_step(&world);
result[16]=bodies[0].x; result[17]=bodies[0].y; result[18]=bodies[0].z;
result[19]=bodies[0].vx; result[20]=bodies[0].vz;
result[21]=bodies[0].last_impact_speed; result[22]=bodies[0].flags;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側是 X/Y 正視圖,右側是 X/Z 俯視圖。綠色輪廓標示初始位置 (24,24,16),紅色盒體顯示一個刻度後的 (36,24,24),藍色區域為靜態障礙物。X 速度由 16 反彈為 -14,Z 速度維持 8。衝擊值為 16,但即使 break_speed=1,flags 仍為零。面板原點位於螢幕 (8,48)/(88,48)。DMG 上所有標記皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body3d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics3d.h:61
Integrate active dynamic bodies and reset their impact values, then solve each active unordered pair for the configured passes (zero means one). Static bodies retain previous impact maxima until the game clears them. Acceleration persists; flags and break thresholds remain game-owned. This discrete solver shares non-reentrant ASM scratch and can miss fast crossings.
kitaqgb/lib/physics3d.c:492
void kq3d_step(KQWorld3D* world)
{
if (world == 0) return;
if (world->bodies == 0) return;
KQBody3D* bodies = world->bodies;
u8 count = world->body_count;
u8 i;
for (i = 0; i < count; i++)
{
KQBody3D* b = &bodies[(__safe_index u8)i];
if (b->active == 0) continue;
if (b->inv_mass_q8 <= 0) continue;
b->last_impact_speed = 0;
kq3d_asm_value = b->vx;
kq3d_asm_operand = world->gravity_x;
kq3d_add_s16_asm();
kq3d_asm_operand = b->ax;
kq3d_add_s16_asm();
kq3d_asm_limit = world->max_speed;
kq3d_clamp_abs_s16_asm();
b->vx = kq3d_asm_value;
kq3d_asm_value = b->vy;
kq3d_asm_operand = world->gravity_y;
kq3d_add_s16_asm();
kq3d_asm_operand = b->ay;
kq3d_add_s16_asm();
kq3d_asm_limit = world->max_speed;
kq3d_clamp_abs_s16_asm();
b->vy = kq3d_asm_value;
kq3d_asm_value = b->vz;
kq3d_asm_operand = world->gravity_z;
kq3d_add_s16_asm();
kq3d_asm_operand = b->az;
kq3d_add_s16_asm();
kq3d_asm_limit = world->max_speed;
kq3d_clamp_abs_s16_asm();
b->vz = kq3d_asm_value;
kq3d_asm_value = b->x;
kq3d_asm_operand = b->vx;
kq3d_add_s16_asm();
b->x = kq3d_asm_value;
kq3d_asm_value = b->y;
kq3d_asm_operand = b->vy;
kq3d_add_s16_asm();
b->y = kq3d_asm_value;
kq3d_asm_value = b->z;
kq3d_asm_operand = b->vz;
kq3d_add_s16_asm();
b->z = kq3d_asm_value;
}
u8 iterations = world->solver_iterations;
if (iterations == 0) iterations = 1;
u8 it;
for (it = 0; it < iterations; it++)
{
for (i = 0; i < count; i++)
{
KQBody3D* a = &bodies[(__safe_index u8)i];
if (a->active == 0) continue;
u8 j;
for (j = (u8)(i + 1); j < count; j++)
{
KQBody3D* b = &bodies[(__safe_index u8)j];
if (b->active == 0) continue;
kq3d__resolve_pair(a, b);
}
}
}
}kq3d_world_init
將物體陣列連接至 3D 世界,設定重力 (0,24,0)、4 次處理及每軸速度上限 512。
語法
void kq3d_world_init(KQWorld3D* world, KQBody3D* bodies, u8 body_count);參數
world指向持有物體陣列與模擬設定的世界。
bodies呼叫端持有的物體陣列起始位置,包含 body_count 個元素。
body_count陣列欄位數量,範圍為 0..255,包含未啟用的項目。
回傳值
無回傳值。本項說明會更新哪些欄位,以及何時生效。
使用條件與限制
位置、半徑、各軸半長、速度與重力應使用一致的整數單位。每一步代表一個模擬刻度;範例中一單位等於一像素。這些函式不會自動將位置轉為 Q8.8,也不負責繪製。
世界僅借用陣列。呼叫端負責配置並持有物體儲存空間,且須在使用期間維持其有效。初始化世界不會初始化陣列元素。
physics3d.c 位於 ROM 記憶體庫 2。範例使用 MBC5 128 KB ROM,先引入此實作,再將 main 放在記憶體庫 0。呼叫期間,外部程式不得改變 ROM 映射。
使用範例
kq3d_world_init(&world,bodies,2);
result[0]=world.gravity_y; result[1]=world.solver_iterations; result[2]=world.max_speed;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側是 X/Y 正視圖,右側是 X/Z 俯視圖。綠色輪廓標示初始位置 (24,24,16),紅色盒體顯示一個刻度後的 (36,24,24),藍色區域為靜態障礙物。X 速度由 16 反彈為 -14,Z 速度維持 8。衝擊值為 16,但即使 break_speed=1,flags 仍為零。面板原點位於螢幕 (8,48)/(88,48)。DMG 上所有標記皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body3d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/physics3d.h:46
Borrow the body array without initializing it. Set gravity (0,24,0), four contact passes and a per-axis speed limit of 512. Null world is ignored; the caller retains ownership and must keep the array alive.
kitaqgb/lib/physics3d.c:294
void kq3d_world_init(KQWorld3D* world, KQBody3D* bodies, u8 body_count)
{
if (world == 0) return;
world->bodies = bodies;
world->body_count = body_count;
world->gravity_x = 0;
world->gravity_y = 24;
world->gravity_z = 0;
world->solver_iterations = 4;
world->max_speed = 512;
}raster.h — 分段及逐掃描線捲動表
Raster 函式庫提供 8 項區帶表,以及在全部 144 條可見線改變 X 的 LineX 繪製器。區帶適用於固定 HUD、視差、視窗變更及 CGB 色彩區域;LineX 適合波動標題與畫面效果。請選用一種驅動,勿同時執行。
引入 raster.h,並編譯 raster.c 與 scroll.c。共用表最多容納 8 個區帶。使用 Raster_* 建表時,請勿穿插直接呼叫 Scroll_Split* 或 __scroll_split_*;這些呼叫不會更新包裝層的數量與最後一條線的記錄。
請在 VBlank 或可掌握顯示影響的時段,依清除、加入項目、提交的順序重建。清除也會停止目前的分割效果,並不是在編輯獨立的後備緩衝區。LY 排定的是中斷時機,寫入暫存器還需額外時間。逐掃描線波浪效果請使用獨立的 Raster_LineX* 系列,勿同時執行兩種驅動。
掃描線波浪與動態標題登場
逐條掃描線改變背景 X 座標,可使柱子與文字呈現波浪狀彎曲,適合用於傳送、頭目登場或標題演出。下方預覽會循環播放八張擷取畫面;ROM 則在每個影格推進波形相位。
Raster_Push 操作最多排定八個區段。若需為每條掃描線指定不同的水平偏移,請使用 Raster_LineXRunFrame。精靈與視窗不會彎曲。繪圖器會在全部 144 條可見掃描線期間占用 CPU 並遮蔽中斷,因此請在呼叫間更新遊戲邏輯與音訊。

標題以大幅波動從右側進場,接著轉成細小漣漪,最後穩定。此範例引入同目錄的 raster_wave.c,請將兩個原始碼檔案放在一起。下方 API 項目提供建置命令與個別用法說明。
Raster 函式庫提供 8 項區帶表,以及在全部 144 條可見線改變 X 的 LineX 繪製器。區帶適用於固定 HUD、視差、視窗變更及 CGB 色彩區域;LineX 適合波動標題與畫面效果。請選用一種驅動,勿同時執行。
引入 raster.h,並編譯 raster.c 與 scroll.c。共用表最多容納 8 個區帶。使用 Raster_* 建表時,請勿穿插直接呼叫 Scroll_Split* 或 __scroll_split_*;這些呼叫不會更新包裝層的數量與最後一條線的記錄。
請在 VBlank 或可掌握顯示影響的時段,依清除、加入項目、提交的順序重建。清除也會停止目前的分割效果,並不是在編輯獨立的後備緩衝區。LY 排定的是中斷時機,寫入暫存器還需額外時間。逐掃描線波浪效果請使用獨立的 Raster_LineX* 系列,勿同時執行兩種驅動。
Raster_BuildHudBottom
建立可捲動的上方遊戲區與固定的底部 HUD。LY=0 使用攝影機座標,hud_y 處切換為背景 (0,0)。
語法
u8 Raster_BuildHudBottom(u8 hud_y, u8 camera_x, u8 camera_y);參數
hud_y分割線為 1..143。零或 144 以上會傳回 BAD_RANGE。
camera_x背景捲動位元組,範圍 0..255。SCX/SCY 指定從背景地圖何處讀取,而非螢幕座標。座標會在 256 像素背景中循環。
camera_y背景捲動位元組,範圍 0..255。SCX/SCY 指定從背景地圖何處讀取,而非螢幕座標。座標會在 256 像素背景中循環。
回傳值
成功時傳回 KQ_RASTER_OK(0),失敗時傳回 1..4 的錯誤狀態。請參閱函式限制與 Raster_GetLastError。
使用條件與限制
引入 raster.h,並編譯 raster.c 與 scroll.c。共用表最多容納 8 個區帶。使用 Raster_* 建表時,請勿穿插直接呼叫 Scroll_Split* 或 __scroll_split_*;這些呼叫不會更新包裝層的數量與最後一條線的記錄。
請在 VBlank 或可掌握顯示影響的時段,依清除、加入項目、提交的順序重建。清除也會停止目前的分割效果,並不是在編輯獨立的後備緩衝區。LY 排定的是中斷時機,寫入暫存器還需額外時間。逐掃描線波浪效果請使用獨立的 Raster_LineX* 系列,勿同時執行兩種驅動。
狀態碼為 0 OK、1 FULL、2 BAD_LY、3 UNSORTED、4 BAD_RANGE。加入操作依序檢查 LY 範圍、容量與排序。遭拒的項目不會增加表的大小。之後成功加入項目或清除表,錯誤碼都會歸零,因此每次呼叫後都應立即檢查回傳值。
參數有效時,會停止現有分割、清除表並加入新區帶。參數無效時,保留表與數量,只儲存 BAD_RANGE。成功建表後仍須呼叫 Raster_Commit。
使用範例
Raster_BuildHudBottom(96,8,8);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
從第 96 列起向下保持固定。攝影機 (8,8) 將上方矩形放在 (24,8) 與 (24,72),底部矩形仍在 (32,112)。FIXED BOTTOM HUD 留在底端。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_hud_bottom.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/raster.h:73
Build a scrolling upper playfield and fixed bottom HUD after validating the split.
kitaqgb/lib/raster.c:183
u8 Raster_BuildHudBottom(u8 hud_y, u8 camera_x, u8 camera_y)
{
u8 r;
if (hud_y == 0) return Raster_SetError(KQ_RASTER_BAD_RANGE);
if (hud_y >= 144) return Raster_SetError(KQ_RASTER_BAD_RANGE);
Raster_Clear();
r = Raster_Push(0, camera_x, camera_y);
if (r != KQ_RASTER_OK) return r;
return Raster_Push(hud_y, 0, 0);
}Raster_BuildHudTop
建立兩個背景區帶以固定頂端 HUD:LY=0 使用 (0,0),到 hud_height 改用攝影機座標。這是分割背景捲動,不使用視窗。
語法
u8 Raster_BuildHudTop(u8 hud_height, u8 camera_x, u8 camera_y);參數
hud_height分割線為 1..143。零或 144 以上會傳回 BAD_RANGE。
camera_x背景捲動位元組,範圍 0..255。SCX/SCY 指定從背景地圖何處讀取,而非螢幕座標。座標會在 256 像素背景中循環。
camera_y背景捲動位元組,範圍 0..255。SCX/SCY 指定從背景地圖何處讀取,而非螢幕座標。座標會在 256 像素背景中循環。
回傳值
成功時傳回 KQ_RASTER_OK(0),失敗時傳回 1..4 的錯誤狀態。請參閱函式限制與 Raster_GetLastError。
使用條件與限制
引入 raster.h,並編譯 raster.c 與 scroll.c。共用表最多容納 8 個區帶。使用 Raster_* 建表時,請勿穿插直接呼叫 Scroll_Split* 或 __scroll_split_*;這些呼叫不會更新包裝層的數量與最後一條線的記錄。
請在 VBlank 或可掌握顯示影響的時段,依清除、加入項目、提交的順序重建。清除也會停止目前的分割效果,並不是在編輯獨立的後備緩衝區。LY 排定的是中斷時機,寫入暫存器還需額外時間。逐掃描線波浪效果請使用獨立的 Raster_LineX* 系列,勿同時執行兩種驅動。
狀態碼為 0 OK、1 FULL、2 BAD_LY、3 UNSORTED、4 BAD_RANGE。加入操作依序檢查 LY 範圍、容量與排序。遭拒的項目不會增加表的大小。之後成功加入項目或清除表,錯誤碼都會歸零,因此每次呼叫後都應立即檢查回傳值。
參數有效時,會停止現有分割、清除表並加入新區帶。參數無效時,保留表與數量,只儲存 BAD_RANGE。成功建表後仍須呼叫 Raster_Commit。
使用範例
Raster_BuildHudTop(32,8,8);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
上方 32 列保持固定。上方矩形仍在 (32,16);攝影機 (8,8) 將另外兩個移至 (24,72) 與 (24,104)。FIXED TOP HUD 留在頂端。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_hud_top.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/raster.h:71
Validate the HUD height, then replace pending splits with a fixed top band and scrolling playfield. The new table still requires an explicit commit.
kitaqgb/lib/raster.c:169
u8 Raster_BuildHudTop(u8 hud_height, u8 camera_x, u8 camera_y)
{
u8 r;
if (hud_height == 0) return Raster_SetError(KQ_RASTER_BAD_RANGE);
if (hud_height >= 144) return Raster_SetError(KQ_RASTER_BAD_RANGE);
Raster_Clear();
r = Raster_Push(0, 0, 0);
if (r != KQ_RASTER_OK) return r;
return Raster_Push(hud_height, camera_x, camera_y);
}Raster_BuildParallax2
建立水平偏移不同的兩個背景區帶:LY=0 使用 far_scx,split_y 起使用 near_scx,兩者共用 Y 捲動。
語法
u8 Raster_BuildParallax2(u8 split_y, u8 far_scx, u8 near_scx, u8 scy);參數
split_y分割線為 1..143。零或 144 以上會傳回 BAD_RANGE。
far_scx背景捲動位元組,範圍 0..255。SCX/SCY 指定從背景地圖何處讀取,而非螢幕座標。座標會在 256 像素背景中循環。
near_scx背景捲動位元組,範圍 0..255。SCX/SCY 指定從背景地圖何處讀取,而非螢幕座標。座標會在 256 像素背景中循環。
scy背景捲動位元組,範圍 0..255。SCX/SCY 指定從背景地圖何處讀取,而非螢幕座標。座標會在 256 像素背景中循環。
回傳值
成功時傳回 KQ_RASTER_OK(0),失敗時傳回 1..4 的錯誤狀態。請參閱函式限制與 Raster_GetLastError。
使用條件與限制
引入 raster.h,並編譯 raster.c 與 scroll.c。共用表最多容納 8 個區帶。使用 Raster_* 建表時,請勿穿插直接呼叫 Scroll_Split* 或 __scroll_split_*;這些呼叫不會更新包裝層的數量與最後一條線的記錄。
請在 VBlank 或可掌握顯示影響的時段,依清除、加入項目、提交的順序重建。清除也會停止目前的分割效果,並不是在編輯獨立的後備緩衝區。LY 排定的是中斷時機,寫入暫存器還需額外時間。逐掃描線波浪效果請使用獨立的 Raster_LineX* 系列,勿同時執行兩種驅動。
狀態碼為 0 OK、1 FULL、2 BAD_LY、3 UNSORTED、4 BAD_RANGE。加入操作依序檢查 LY 範圍、容量與排序。遭拒的項目不會增加表的大小。之後成功加入項目或清除表,錯誤碼都會歸零,因此每次呼叫後都應立即檢查回傳值。
參數有效時,會停止現有分割、清除表並加入新區帶。參數無效時,保留表與數量,只儲存 BAD_RANGE。成功建表後仍須呼叫 Raster_Commit。
使用範例
Raster_BuildParallax2(64,0,16,0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
在排定的第 64 線,X 從 0 改為 16。矩形出現在 (32,16)、(16,80)、(16,112),只有下方區域向左移動 16 像素。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_parallax2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/raster.h:76
Build two horizontal-scroll bands sharing one vertical scroll value.
kitaqgb/lib/raster.c:197
u8 Raster_BuildParallax2(u8 split_y, u8 far_scx, u8 near_scx, u8 scy)
{
u8 r;
if (split_y == 0) return Raster_SetError(KQ_RASTER_BAD_RANGE);
if (split_y >= 144) return Raster_SetError(KQ_RASTER_BAD_RANGE);
Raster_Clear();
r = Raster_Push(0, far_scx, scy);
if (r != KQ_RASTER_OK) return r;
return Raster_Push(split_y, near_scx, scy);
}Raster_BuildParallax3
為從 LY=0、y1、y2 開始的區帶登錄 scx0、scx1、scx2。遠、中、近層使用不同水平偏移,並共用 Y 捲動。
語法
u8 Raster_BuildParallax3(u8 y1, u8 y2, u8 scx0, u8 scx1, u8 scx2, u8 scy);參數
y1分割線,必須符合 1 <= y1 < y2 <= 143。
y2分割線,必須符合 1 <= y1 < y2 <= 143。
scx0背景捲動位元組,範圍 0..255。SCX/SCY 指定從背景地圖何處讀取,而非螢幕座標。座標會在 256 像素背景中循環。
scx1背景捲動位元組,範圍 0..255。SCX/SCY 指定從背景地圖何處讀取,而非螢幕座標。座標會在 256 像素背景中循環。
scx2背景捲動位元組,範圍 0..255。SCX/SCY 指定從背景地圖何處讀取,而非螢幕座標。座標會在 256 像素背景中循環。
scy背景捲動位元組,範圍 0..255。SCX/SCY 指定從背景地圖何處讀取,而非螢幕座標。座標會在 256 像素背景中循環。
回傳值
成功時傳回 KQ_RASTER_OK(0),失敗時傳回 1..4 的錯誤狀態。請參閱函式限制與 Raster_GetLastError。
使用條件與限制
引入 raster.h,並編譯 raster.c 與 scroll.c。共用表最多容納 8 個區帶。使用 Raster_* 建表時,請勿穿插直接呼叫 Scroll_Split* 或 __scroll_split_*;這些呼叫不會更新包裝層的數量與最後一條線的記錄。
請在 VBlank 或可掌握顯示影響的時段,依清除、加入項目、提交的順序重建。清除也會停止目前的分割效果,並不是在編輯獨立的後備緩衝區。LY 排定的是中斷時機,寫入暫存器還需額外時間。逐掃描線波浪效果請使用獨立的 Raster_LineX* 系列,勿同時執行兩種驅動。
狀態碼為 0 OK、1 FULL、2 BAD_LY、3 UNSORTED、4 BAD_RANGE。加入操作依序檢查 LY 範圍、容量與排序。遭拒的項目不會增加表的大小。之後成功加入項目或清除表,錯誤碼都會歸零,因此每次呼叫後都應立即檢查回傳值。
參數有效時,會停止現有分割、清除表並加入新區帶。參數無效時,保留表與數量,只儲存 BAD_RANGE。成功建表後仍須呼叫 Raster_Commit。
使用範例
Raster_BuildParallax3(64,104,0,8,16,0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
以排定的第 64、104 線為分界,選用 X 偏移 0、8、16。位於 (32,16)、(24,80)、(16,112) 的矩形呈現三個區帶逐漸增加的位移。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_parallax3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/raster.h:79
Build three horizontal-scroll bands at ordered visible split lines. Invalid parameters leave the previous pending table intact and set the error status.
kitaqgb/lib/raster.c:212
u8 Raster_BuildParallax3(u8 y1, u8 y2, u8 scx0, u8 scx1, u8 scx2, u8 scy)
{
u8 r;
if (y1 == 0) return Raster_SetError(KQ_RASTER_BAD_RANGE);
if (y2 >= 144) return Raster_SetError(KQ_RASTER_BAD_RANGE);
if (y2 <= y1) return Raster_SetError(KQ_RASTER_BAD_RANGE);
Raster_Clear();
r = Raster_Push(0, scx0, scy);
if (r != KQ_RASTER_OK) return r;
r = Raster_Push(y1, scx1, scy);
if (r != KQ_RASTER_OK) return r;
return Raster_Push(y2, scx2, scy);
}Raster_Clear
在同一場景重建表之前,立即停止分割排程,並重設數量、排序與錯誤狀態。不會將表的所有儲存位元組歸零。
語法
void Raster_Clear();回傳值
無傳回值。
使用條件與限制
引入 raster.h,並編譯 raster.c 與 scroll.c。共用表最多容納 8 個區帶。使用 Raster_* 建表時,請勿穿插直接呼叫 Scroll_Split* 或 __scroll_split_*;這些呼叫不會更新包裝層的數量與最後一條線的記錄。
請在 VBlank 或可掌握顯示影響的時段,依清除、加入項目、提交的順序重建。清除也會停止目前的分割效果,並不是在編輯獨立的後備緩衝區。LY 排定的是中斷時機,寫入暫存器還需額外時間。逐掃描線波浪效果請使用獨立的 Raster_LineX* 系列,勿同時執行兩種驅動。
狀態碼為 0 OK、1 FULL、2 BAD_LY、3 UNSORTED、4 BAD_RANGE。加入操作依序檢查 LY 範圍、容量與排序。遭拒的項目不會增加表的大小。之後成功加入項目或清除表,錯誤碼都會歸零,因此每次呼叫後都應立即檢查回傳值。
停止分割不會將 SCX、SCY、WX 或 WY 歸零。請用 Scroll_SetBg 等一般設定函式建立所需的基本狀態。這些函式也不會還原先前的 VBlank/STAT IE 位元或 IME。
使用範例
Raster_Clear();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
三個 24x16 像素的紅色矩形(DMG 上為黑色)出現在 (32,16)、(24,80)、(16,112)。越下方的區帶向左偏移越多。內部結果記錄數量 3、錯誤 0、提交結果 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_bands.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/raster.h:39
Stop splits immediately and clear bookkeeping. Build and commit a new table to restart.
kitaqgb/lib/raster.c:65
void Raster_Clear()
{
Scroll_SplitReset();
Raster_CountValue = 0;
Raster_LastLyValue = 0;
Raster_HasLastLy = 0;
Raster_LastErrorValue = KQ_RASTER_OK;
}Raster_Commit
啟用已建立的共用表。即使先前某次加入失敗,之前成功加入的項目仍會啟用;呼叫端須逐次檢查登錄結果。
語法
u8 Raster_Commit();回傳值
傳回最後儲存的錯誤。零不代表先前每次登錄都成功。
使用條件與限制
引入 raster.h,並編譯 raster.c 與 scroll.c。共用表最多容納 8 個區帶。使用 Raster_* 建表時,請勿穿插直接呼叫 Scroll_Split* 或 __scroll_split_*;這些呼叫不會更新包裝層的數量與最後一條線的記錄。
請在 VBlank 或可掌握顯示影響的時段,依清除、加入項目、提交的順序重建。清除也會停止目前的分割效果,並不是在編輯獨立的後備緩衝區。LY 排定的是中斷時機,寫入暫存器還需額外時間。逐掃描線波浪效果請使用獨立的 Raster_LineX* 系列,勿同時執行兩種驅動。
狀態碼為 0 OK、1 FULL、2 BAD_LY、3 UNSORTED、4 BAD_RANGE。加入操作依序檢查 LY 範圍、容量與排序。遭拒的項目不會增加表的大小。之後成功加入項目或清除表,錯誤碼都會歸零,因此每次呼叫後都應立即檢查回傳值。
表非空時,設定 VBlank/STAT IE 位元並執行 EI 以啟用中斷;其餘 IE 位元保留。空表會停用分割排程,但不還原全域中斷設定。
使用範例
result[2]=Raster_Commit();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
三個 24x16 像素的紅色矩形(DMG 上為黑色)出現在 (32,16)、(24,80)、(16,112)。越下方的區帶向左偏移越多。內部結果記錄數量 3、錯誤 0、提交結果 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_bands.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/raster.h:67
Publish pending splits and return the stored status. This commits even if an earlier append failed; callers should inspect errors while building the table.
kitaqgb/lib/raster.c:161
u8 Raster_Commit()
{
Scroll_SplitCommit();
return Raster_LastErrorValue;
}Raster_Disable
清除並提交空表,以停用光柵區帶。進入不使用分割捲動的場景時,可用此操作明確停止效果。
語法
void Raster_Disable();回傳值
無傳回值。
使用條件與限制
引入 raster.h,並編譯 raster.c 與 scroll.c。共用表最多容納 8 個區帶。使用 Raster_* 建表時,請勿穿插直接呼叫 Scroll_Split* 或 __scroll_split_*;這些呼叫不會更新包裝層的數量與最後一條線的記錄。
請在 VBlank 或可掌握顯示影響的時段,依清除、加入項目、提交的順序重建。清除也會停止目前的分割效果,並不是在編輯獨立的後備緩衝區。LY 排定的是中斷時機,寫入暫存器還需額外時間。逐掃描線波浪效果請使用獨立的 Raster_LineX* 系列,勿同時執行兩種驅動。
狀態碼為 0 OK、1 FULL、2 BAD_LY、3 UNSORTED、4 BAD_RANGE。加入操作依序檢查 LY 範圍、容量與排序。遭拒的項目不會增加表的大小。之後成功加入項目或清除表,錯誤碼都會歸零,因此每次呼叫後都應立即檢查回傳值。
停止分割不會將 SCX、SCY、WX 或 WY 歸零。請用 Scroll_SetBg 等一般設定函式建立所需的基本狀態。這些函式也不會還原先前的 VBlank/STAT IE 位元或 IME。
使用範例
Raster_Disable();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
三個 24x16 像素的紅色矩形(DMG 上為黑色)出現在 (32,16)、(24,80)、(16,112)。越下方的區帶向左偏移越多。內部結果記錄數量 3、錯誤 0、提交結果 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_bands.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/raster.h:41
Commit an empty split table so no raster bands remain active.
kitaqgb/lib/raster.c:75
void Raster_Disable()
{
Raster_Clear();
Scroll_SplitCommit();
}Raster_GetCount
讀取透過 Raster 包裝層登錄的區帶數。Clear/Disable 會歸零;僅提交則保留數量。
語法
u8 Raster_GetCount();回傳值
傳回項目數 0..8。以 8 減去此值即為剩餘容量。讀取不改變狀態。
使用條件與限制
引入 raster.h,並編譯 raster.c 與 scroll.c。共用表最多容納 8 個區帶。使用 Raster_* 建表時,請勿穿插直接呼叫 Scroll_Split* 或 __scroll_split_*;這些呼叫不會更新包裝層的數量與最後一條線的記錄。
請在 VBlank 或可掌握顯示影響的時段,依清除、加入項目、提交的順序重建。清除也會停止目前的分割效果,並不是在編輯獨立的後備緩衝區。LY 排定的是中斷時機,寫入暫存器還需額外時間。逐掃描線波浪效果請使用獨立的 Raster_LineX* 系列,勿同時執行兩種驅動。
狀態碼為 0 OK、1 FULL、2 BAD_LY、3 UNSORTED、4 BAD_RANGE。加入操作依序檢查 LY 範圍、容量與排序。遭拒的項目不會增加表的大小。之後成功加入項目或清除表,錯誤碼都會歸零,因此每次呼叫後都應立即檢查回傳值。
使用範例
result[0]=Raster_GetCount();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
三個 24x16 像素的紅色矩形(DMG 上為黑色)出現在 (32,16)、(24,80)、(16,112)。越下方的區帶向左偏移越多。內部結果記錄數量 3、錯誤 0、提交結果 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_bands.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/raster.h:44
Read the number of bands currently recorded by this wrapper.
kitaqgb/lib/raster.c:82
u8 Raster_GetCount()
{
return Raster_CountValue;
}Raster_GetLastError
讀取最後儲存的 Raster 狀態,不將其清除。這不是先前所有失敗的累計記錄。
語法
u8 Raster_GetLastError();回傳值
傳回儲存的狀態 0..4。提交會回傳此值,但不會自動復原失敗操作或捨棄表。
使用條件與限制
引入 raster.h,並編譯 raster.c 與 scroll.c。共用表最多容納 8 個區帶。使用 Raster_* 建表時,請勿穿插直接呼叫 Scroll_Split* 或 __scroll_split_*;這些呼叫不會更新包裝層的數量與最後一條線的記錄。
請在 VBlank 或可掌握顯示影響的時段,依清除、加入項目、提交的順序重建。清除也會停止目前的分割效果,並不是在編輯獨立的後備緩衝區。LY 排定的是中斷時機,寫入暫存器還需額外時間。逐掃描線波浪效果請使用獨立的 Raster_LineX* 系列,勿同時執行兩種驅動。
狀態碼為 0 OK、1 FULL、2 BAD_LY、3 UNSORTED、4 BAD_RANGE。加入操作依序檢查 LY 範圍、容量與排序。遭拒的項目不會增加表的大小。之後成功加入項目或清除表,錯誤碼都會歸零,因此每次呼叫後都應立即檢查回傳值。
使用範例
result[1]=Raster_GetLastError();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
三個 24x16 像素的紅色矩形(DMG 上為黑色)出現在 (32,16)、(24,80)、(16,112)。越下方的區帶向左偏移越多。內部結果記錄數量 3、錯誤 0、提交結果 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_bands.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/raster.h:46
Read the last stored status without clearing it.
kitaqgb/lib/raster.c:88
u8 Raster_GetLastError()
{
return Raster_LastErrorValue;
}Raster_Init
清空共用區帶表、停止分割,並初始化數量、最後 LY 的有效狀態與錯誤狀態。與 Scroll_Init 不同,此操作不初始化背景/視窗座標。
語法
void Raster_Init();回傳值
無傳回值。
使用條件與限制
引入 raster.h,並編譯 raster.c 與 scroll.c。共用表最多容納 8 個區帶。使用 Raster_* 建表時,請勿穿插直接呼叫 Scroll_Split* 或 __scroll_split_*;這些呼叫不會更新包裝層的數量與最後一條線的記錄。
請在 VBlank 或可掌握顯示影響的時段,依清除、加入項目、提交的順序重建。清除也會停止目前的分割效果,並不是在編輯獨立的後備緩衝區。LY 排定的是中斷時機,寫入暫存器還需額外時間。逐掃描線波浪效果請使用獨立的 Raster_LineX* 系列,勿同時執行兩種驅動。
狀態碼為 0 OK、1 FULL、2 BAD_LY、3 UNSORTED、4 BAD_RANGE。加入操作依序檢查 LY 範圍、容量與排序。遭拒的項目不會增加表的大小。之後成功加入項目或清除表,錯誤碼都會歸零,因此每次呼叫後都應立即檢查回傳值。
停止分割不會將 SCX、SCY、WX 或 WY 歸零。請用 Scroll_SetBg 等一般設定函式建立所需的基本狀態。這些函式也不會還原先前的 VBlank/STAT IE 位元或 IME。
使用範例
Raster_Init();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
三個 24x16 像素的紅色矩形(DMG 上為黑色)出現在 (32,16)、(24,80)、(16,112)。越下方的區帶向左偏移越多。內部結果記錄數量 3、錯誤 0、提交結果 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_bands.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/raster.h:37
Stop split scheduling, empty the shared table and clear error/count state.
kitaqgb/lib/raster.c:59
void Raster_Init()
{
Raster_Clear();
}Raster_LineXGetOffset
計算指定線的 SCX,不改變狀態、顯示或相位。
語法
u8 Raster_LineXGetOffset(const RasterLineX* effect, u8 ly);參數
effect指向已初始化的 RasterLineX,且在整個呼叫期間保持有效。
ly要查詢的線座標,範圍 0..255;可見線為 0..143。查表依波形週期回繞,不回報範圍錯誤。
回傳值
8 位元 SCX,等於基準 X 加上該列位移。範例查詢相位 8、第 0 線時傳回 17。
使用條件與限制
SCX 為 8 位元值,背景每 256 像素回繞。負位移以模 256 的位元組值表示。可見視口外的地圖也必須填好。
此效果改變背景的水平捲動,精靈與視窗不會彎曲。RunFrame 在全部 144 條可見線期間占用 CPU 並遮蔽中斷。請在呼叫之間更新遊戲邏輯與音訊,勿與 STAT 光柵中斷驅動一起使用。
圖片來自 KOKURA 的 DMG 與 CGB 執行。160×144 場景的每個像素,包括柱子與文字,都與預期逐線座標比對。尚未測試實機時序。
將 kitaqgb、kokura 與 kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。ROM 同時支援 DMG 與 CGB;透過 KOKURA --hardware 選擇 dmg 或 cgb。
使用範例
wave_lookup = Raster_LineXGetOffset(&wave, 0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
柱子與文字水平彎曲,最大位移為 24 像素。一個波形跨 64 條掃描線,每影格相位前進一線。CGB 使用藍色柱子與文字。請觀察各列不同的水平偏移,而非整個畫面等量移動。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_wave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_wave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\raster_wave.gb --hardware cgb --run-frames 120 --png .\out\raster_wave.png實作與原始碼
kitaqgb/lib/raster.h:91
Look up the selected periodic profile at LY + phase and add base X modulo 256. An unknown profile returns the unmodified base X.
kitaqgb/lib/raster.c:264
u8 Raster_LineXGetOffset(const RasterLineX* effect, u8 ly)
{
u8 index;
if (effect->profile == KQ_RASTER_LINE_X_TITLE) {
index = (u8)((ly + effect->phase) & 15);
return (u8)(effect->base_x + Raster_LineXXTitle[(__safe_index u8)index]);
}
if (effect->profile == KQ_RASTER_LINE_TRAVEL_GATE) {
index = (u8)((ly + effect->phase) & 63);
return (u8)(effect->base_x + Raster_LineXTravelGate[(__safe_index u8)index]);
}
return effect->base_x;
}Raster_LineXInit
初始化波形設定與基準 X,將相位設為零、每影格相位步進設為一。此呼叫不繪圖,也不寫入捲動暫存器。
語法
void Raster_LineXInit(RasterLineX* effect, u8 profile, u8 base_x);參數
effect指向可寫入的 RasterLineX 儲存空間;無須事先初始化。
profile0(FLAT)不施加位移;1(X_TITLE)每 16 線重複 −4..+3 像素偏移;2(TRAVEL_GATE)每 64 線重複 ±24 像素波形。其他值不施加位移。
base_x加到波形位移上的背景 X,以像素表示,範圍 0..255。
回傳值
無傳回值。
使用條件與限制
SCX 為 8 位元值,背景每 256 像素回繞。負位移以模 256 的位元組值表示。可見視口外的地圖也必須填好。
此效果改變背景的水平捲動,精靈與視窗不會彎曲。RunFrame 在全部 144 條可見線期間占用 CPU 並遮蔽中斷。請在呼叫之間更新遊戲邏輯與音訊,勿與 STAT 光柵中斷驅動一起使用。
圖片來自 KOKURA 的 DMG 與 CGB 執行。160×144 場景的每個像素,包括柱子與文字,都與預期逐線座標比對。尚未測試實機時序。
將 kitaqgb、kokura 與 kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。ROM 同時支援 DMG 與 CGB;透過 KOKURA --hardware 選擇 dmg 或 cgb。
使用範例
Raster_LineXInit(&wave, KQ_RASTER_LINE_TRAVEL_GATE, 0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
柱子與文字水平彎曲,最大位移為 24 像素。一個波形跨 64 條掃描線,每影格相位前進一線。CGB 使用藍色柱子與文字。請觀察各列不同的水平偏移,而非整個畫面等量移動。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_wave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_wave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\raster_wave.gb --hardware cgb --run-frames 120 --png .\out\raster_wave.png實作與原始碼
kitaqgb/lib/raster.h:82
Initialize a scanline-wave state with phase zero and one phase step per frame.
kitaqgb/lib/raster.c:229
void Raster_LineXInit(RasterLineX* effect, u8 profile, u8 base_x)
{
effect->profile = profile;
effect->base_x = base_x;
effect->phase = 0;
effect->phase_step = 1;
effect->frame_divider = 1;
effect->frame_counter = 0;
}Raster_LineXRunFrame
等待 VBlank,接著以逐線背景 X 繪製後續 144 條可見線。完成後推進分頻計數器,並依所選間隔更新相位。
語法
void Raster_LineXRunFrame(RasterLineX* effect);參數
effect指向已初始化的 RasterLineX,且在整個呼叫期間保持有效。
回傳值
無傳回值。
使用條件與限制
LCD 關閉時立即返回,不改變效果。否則會阻塞至全部 144 列的 SCX 更新完成,還原中斷啟用狀態,並將 Scroll 輔助功能同步至最後的 SCX。返回時不保證仍在 VBlank。直接寫入 VRAM 前,請等待 VBlank 或使用能管理安全存取時序的傳輸函式。
SCX 為 8 位元值,背景每 256 像素回繞。負位移以模 256 的位元組值表示。可見視口外的地圖也必須填好。
此效果改變背景的水平捲動,精靈與視窗不會彎曲。RunFrame 在全部 144 條可見線期間占用 CPU 並遮蔽中斷。請在呼叫之間更新遊戲邏輯與音訊,勿與 STAT 光柵中斷驅動一起使用。
圖片來自 KOKURA 的 DMG 與 CGB 執行。160×144 場景的每個像素,包括柱子與文字,都與預期逐線座標比對。尚未測試實機時序。
將 kitaqgb、kokura 與 kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。ROM 同時支援 DMG 與 CGB;透過 KOKURA --hardware 選擇 dmg 或 cgb。
使用範例
Raster_LineXRunFrame(&wave);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
柱子與文字水平彎曲,最大位移為 24 像素。一個波形跨 64 條掃描線,每影格相位前進一線。CGB 使用藍色柱子與文字。請觀察各列不同的水平偏移,而非整個畫面等量移動。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_wave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_wave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\raster_wave.gb --hardware cgb --run-frames 120 --png .\out\raster_wave.png實作與原始碼
kitaqgb/lib/raster.h:96
Render all 144 visible lines with one SCX write per line, then advance phase. This foreground renderer masks interrupts during the visible frame. Do game and audio work between calls; do not combine it with a STAT raster driver. Returns without changing the effect when the LCD is off.
kitaqgb/lib/raster.c:298
void Raster_LineXRunFrame(RasterLineX* effect)
{
u8 interrupt_state;
if ((Raster_LineXLcdc & 0x80) == 0) return;
Raster_LineXTable = Raster_LineXFlat;
Raster_LineXMask = 15;
if (effect->profile == KQ_RASTER_LINE_X_TITLE) {
Raster_LineXTable = Raster_LineXXTitle;
}
if (effect->profile == KQ_RASTER_LINE_TRAVEL_GATE) {
Raster_LineXTable = Raster_LineXTravelGate;
Raster_LineXMask = 63;
}
Raster_LineXPhase = effect->phase;
Raster_LineXBase = effect->base_x;
interrupt_state = __critical_enter();
__asm {
PUSH_AF
PUSH_BC
PUSH_DE
PUSH_HL
// Use the current VBlank when the preceding frame ended there.
// Waiting for another VBlank edge would leave every second frame flat.
raster_linex_vblank:
LDH_A_MEM 0x44
CP_IMM 144
JR_C raster_linex_vblank
LD_B_IMM 0
LD_A_MEM Raster_LineXPhase
LD_C_A
LD_A_MEM Raster_LineXMask
LD_D_A
LD_A_MEM Raster_LineXBase
LD_E_A
raster_linex_line:
LD_A_B
ADD_C
AND_D
LD_L_A
LD_H_IMM 0
PUSH_DE
LD_A_MEM Raster_LineXTable
LD_E_A
LD_A_MEM Raster_LineXTable+1
LD_D_A
ADD_HL_DE
POP_DE
LD_A_HL
ADD_E
PUSH_AF
raster_linex_wait:
LDH_A_MEM 0x44
CP_B
JR_NZ raster_linex_wait
POP_AF
LDH_MEM_A 0x43
INC_B
LD_A_B
CP_IMM 144
JR_NZ raster_linex_line
POP_HL
POP_DE
POP_BC
POP_AF
}
// Synchronize the scroll helper's tracked state with the last hardware write.
__scroll_bg_x_set(Raster_LineXScx);
__critical_leave(interrupt_state);
effect->frame_counter++;
if (effect->frame_counter >= effect->frame_divider) {
effect->frame_counter = 0;
effect->phase = (u8)(effect->phase + effect->phase_step);
}
}Raster_LineXSetPhase
直接設定波形位置,保留基準 X、速度與分頻計數器。
語法
void Raster_LineXSetPhase(RasterLineX* effect, u8 phase);參數
effect指向已初始化的 RasterLineX,且在整個呼叫期間保持有效。
phase8 位元相位值;所選波形每 16 或 64 步重複。
回傳值
無傳回值。
使用條件與限制
SCX 為 8 位元值,背景每 256 像素回繞。負位移以模 256 的位元組值表示。可見視口外的地圖也必須填好。
此效果改變背景的水平捲動,精靈與視窗不會彎曲。RunFrame 在全部 144 條可見線期間占用 CPU 並遮蔽中斷。請在呼叫之間更新遊戲邏輯與音訊,勿與 STAT 光柵中斷驅動一起使用。
圖片來自 KOKURA 的 DMG 與 CGB 執行。160×144 場景的每個像素,包括柱子與文字,都與預期逐線座標比對。尚未測試實機時序。
將 kitaqgb、kokura 與 kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。ROM 同時支援 DMG 與 CGB;透過 KOKURA --hardware 選擇 dmg 或 cgb。
使用範例
Raster_LineXSetPhase(&wave, 8);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
柱子與文字水平彎曲,最大位移為 24 像素。一個波形跨 64 條掃描線,每影格相位前進一線。CGB 使用藍色柱子與文字。請觀察各列不同的水平偏移,而非整個畫面等量移動。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_wave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_wave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\raster_wave.gb --hardware cgb --run-frames 120 --png .\out\raster_wave.png實作與原始碼
kitaqgb/lib/raster.h:88
Set the byte phase directly without resetting the frame-divider counter.
kitaqgb/lib/raster.c:257
void Raster_LineXSetPhase(RasterLineX* effect, u8 phase)
{
effect->phase = phase;
}Raster_LineXSetProfile
選擇波形設定,並將相位與影格分頻計數器歸零。保留基準 X 與速度。
語法
void Raster_LineXSetProfile(RasterLineX* effect, u8 profile);參數
effect指向已初始化的 RasterLineX,且在整個呼叫期間保持有效。
profile0(FLAT)不施加位移;1(X_TITLE)每 16 線重複 −4..+3 像素偏移;2(TRAVEL_GATE)每 64 線重複 ±24 像素波形。其他值不施加位移。
回傳值
無傳回值。
使用條件與限制
SCX 為 8 位元值,背景每 256 像素回繞。負位移以模 256 的位元組值表示。可見視口外的地圖也必須填好。
此效果改變背景的水平捲動,精靈與視窗不會彎曲。RunFrame 在全部 144 條可見線期間占用 CPU 並遮蔽中斷。請在呼叫之間更新遊戲邏輯與音訊,勿與 STAT 光柵中斷驅動一起使用。
圖片來自 KOKURA 的 DMG 與 CGB 執行。160×144 場景的每個像素,包括柱子與文字,都與預期逐線座標比對。尚未測試實機時序。
將 kitaqgb、kokura 與 kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。ROM 同時支援 DMG 與 CGB;透過 KOKURA --hardware 選擇 dmg 或 cgb。
使用範例
Raster_LineXSetProfile(&wave, KQ_RASTER_LINE_X_TITLE);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例的原創標題 ORBIT GUARD 伴隨大波浪從右側進入。繪製 48 個影格後改為小波紋,從第 96 影格起靜止。進場效果在 160 影格後重複。圖片依序顯示進場、小波紋及穩定後的標題。






建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_title_entry.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_title_entry.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\raster_title_entry.gb --hardware cgb --run-frames 120 --png .\out\raster_title_entry.png實作與原始碼
kitaqgb/lib/raster.h:84
Change the wave profile and restart its phase/divider counter.
kitaqgb/lib/raster.c:240
void Raster_LineXSetProfile(RasterLineX* effect, u8 profile)
{
effect->profile = profile;
effect->phase = 0;
effect->frame_counter = 0;
}Raster_LineXSetSpeed
設定相位增量與更新間隔。保留目前相位,重設分頻計數器。
語法
void Raster_LineXSetSpeed(RasterLineX* effect, u8 phase_step, u8 frame_divider);參數
effect指向已初始化的 RasterLineX,且在整個呼叫期間保持有效。
phase_step每次更新的相位增量,範圍 0..255。零會凍結波形;255 利用 8 位元回繞,每次向後一步。
frame_divider每次相位更新所需的 RunFrame 繪製呼叫數,範圍 1..255。零視為一。因 LCD 關閉而返回的呼叫不計入。
回傳值
無傳回值。
使用條件與限制
SCX 為 8 位元值,背景每 256 像素回繞。負位移以模 256 的位元組值表示。可見視口外的地圖也必須填好。
此效果改變背景的水平捲動,精靈與視窗不會彎曲。RunFrame 在全部 144 條可見線期間占用 CPU 並遮蔽中斷。請在呼叫之間更新遊戲邏輯與音訊,勿與 STAT 光柵中斷驅動一起使用。
圖片來自 KOKURA 的 DMG 與 CGB 執行。160×144 場景的每個像素,包括柱子與文字,都與預期逐線座標比對。尚未測試實機時序。
將 kitaqgb、kokura 與 kitaq-docs 放在同一父目錄下,並在該父目錄開啟 PowerShell。ROM 同時支援 DMG 與 CGB;透過 KOKURA --hardware 選擇 dmg 或 cgb。
使用範例
Raster_LineXSetSpeed(&wave, 1, 1);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
柱子與文字水平彎曲,最大位移為 24 像素。一個波形跨 64 條掃描線,每影格相位前進一線。CGB 使用藍色柱子與文字。請觀察各列不同的水平偏移,而非整個畫面等量移動。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_wave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_wave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\raster_wave.gb --hardware cgb --run-frames 120 --png .\out\raster_wave.png實作與原始碼
kitaqgb/lib/raster.h:86
Configure the phase increment and frame interval; clamp a zero interval to one.
kitaqgb/lib/raster.c:248
void Raster_LineXSetSpeed(RasterLineX* effect, u8 phase_step, u8 frame_divider)
{
effect->phase_step = phase_step;
if (frame_divider == 0) frame_divider = 1;
effect->frame_divider = frame_divider;
effect->frame_counter = 0;
}Raster_Push
加入一個在指定 LY 改變背景 SCX/SCY 的區帶。此操作只處理背景,不改變視窗或色彩。
語法
u8 Raster_Push(u8 ly, u8 scx, u8 scy);參數
ly排定的可見線,範圍 0..143,必須嚴格大於表中前一個項目。若第一個項目為 LY=0,會由 VBlank 處理套用,以建立影格開始時的狀態。
scx背景捲動位元組,範圍 0..255。SCX/SCY 指定從背景地圖何處讀取,而非螢幕座標。座標會在 256 像素背景中循環。
scy背景捲動位元組,範圍 0..255。SCX/SCY 指定從背景地圖何處讀取,而非螢幕座標。座標會在 256 像素背景中循環。
回傳值
成功時傳回 KQ_RASTER_OK(0),失敗時傳回 1..4 的錯誤狀態。請參閱函式限制與 Raster_GetLastError。
使用條件與限制
引入 raster.h,並編譯 raster.c 與 scroll.c。共用表最多容納 8 個區帶。使用 Raster_* 建表時,請勿穿插直接呼叫 Scroll_Split* 或 __scroll_split_*;這些呼叫不會更新包裝層的數量與最後一條線的記錄。
請在 VBlank 或可掌握顯示影響的時段,依清除、加入項目、提交的順序重建。清除也會停止目前的分割效果,並不是在編輯獨立的後備緩衝區。LY 排定的是中斷時機,寫入暫存器還需額外時間。逐掃描線波浪效果請使用獨立的 Raster_LineX* 系列,勿同時執行兩種驅動。
狀態碼為 0 OK、1 FULL、2 BAD_LY、3 UNSORTED、4 BAD_RANGE。加入操作依序檢查 LY 範圍、容量與排序。遭拒的項目不會增加表的大小。之後成功加入項目或清除表,錯誤碼都會歸零,因此每次呼叫後都應立即檢查回傳值。
使用範例
Raster_Push(0,0,0);Raster_Push(64,8,0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
三個 24x16 像素的紅色矩形(DMG 上為黑色)出現在 (32,16)、(24,80)、(16,112)。越下方的區帶向左偏移越多。內部結果記錄數量 3、錯誤 0、提交結果 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_bands.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/raster.h:50
Append a validated background-scroll band and advance the monotonic-LY bookkeeping. A successful append clears the previous error.
kitaqgb/lib/raster.c:95
u8 Raster_Push(u8 ly, u8 scx, u8 scy)
{
u8 r;
r = Raster_CheckPush(ly);
if (r != KQ_RASTER_OK) return r;
Scroll_SplitPush(ly, scx, scy);
Raster_LastLyValue = ly;
Raster_HasLastLy = 1;
Raster_CountValue++;
Raster_LastErrorValue = KQ_RASTER_OK;
return KQ_RASTER_OK;
}Raster_PushBgColor0
加入在影格中途改變 CGB 背景調色盤 0 之色彩 0 的區帶。不會選擇其他調色盤,也不改變其餘三色。在 DMG 登錄不會產生色彩效果。
語法
u8 Raster_PushBgColor0(u8 ly, u16 rgb15);參數
ly排定的可見線,範圍 0..143,必須嚴格大於表中前一個項目。若第一個項目為 LY=0,會由 VBlank 處理套用,以建立影格開始時的狀態。
rgb15RGB15:紅色位於位元 0..4,綠色為 5..9,藍色為 10..14。0x001F 是紅色、0x03E0 是綠色、0x7C00 是藍色。不檢查輸入範圍。
回傳值
成功時傳回 KQ_RASTER_OK(0),失敗時傳回 1..4 的錯誤狀態。請參閱函式限制與 Raster_GetLastError。
使用條件與限制
引入 raster.h,並編譯 raster.c 與 scroll.c。共用表最多容納 8 個區帶。使用 Raster_* 建表時,請勿穿插直接呼叫 Scroll_Split* 或 __scroll_split_*;這些呼叫不會更新包裝層的數量與最後一條線的記錄。
請在 VBlank 或可掌握顯示影響的時段,依清除、加入項目、提交的順序重建。清除也會停止目前的分割效果,並不是在編輯獨立的後備緩衝區。LY 排定的是中斷時機,寫入暫存器還需額外時間。逐掃描線波浪效果請使用獨立的 Raster_LineX* 系列,勿同時執行兩種驅動。
狀態碼為 0 OK、1 FULL、2 BAD_LY、3 UNSORTED、4 BAD_RANGE。加入操作依序檢查 LY 範圍、容量與排序。遭拒的項目不會增加表的大小。之後成功加入項目或清除表,錯誤碼都會歸零,因此每次呼叫後都應立即檢查回傳值。
色彩更新使用 BCPS/BCPD,且不保留先前的 BCPS 索引。主程式也寫入調色盤時,請明確設定索引。處理常式會等待可存取的 LCD 模式,因此可見色彩邊界可能落在排定的 LY 之後。
使用範例
Raster_PushBgColor0(0,0x7C00);Raster_PushBgColor0(64,0x001F);Raster_PushBgColor0(112,0x03E0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
已驗證的 CGB 一般速度擷取中,第 0..65 列為藍色、66..113 列為紅色、114..143 列為綠色。排定的 LY 是 0、64、112;中斷與調色盤存取延遲會影響可見邊界。沒有 DMG 彩色版本。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_color.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/raster.h:63
Pack a 15-bit color into the extended band's two scroll-byte fields and select the color-zero operation, which interprets those fields as color data.
kitaqgb/lib/raster.c:154
u8 Raster_PushBgColor0(u8 ly, u16 rgb15)
{
return Raster_PushEx(ly, (u8)rgb15, (u8)(rgb15 >> 8), 0, 0, KQ_RASTER_BG_COLOR0);
}Raster_PushBgWindowScreen
在單一區帶更新背景捲動與視窗座標。包裝函式加上 BG 與 WIN,並將視窗螢幕 X 轉成 WX。
語法
u8 Raster_PushBgWindowScreen(u8 ly, u8 scx, u8 scy, u8 screen_x, u8 screen_y, u8 flags);參數
ly排定的可見線,範圍 0..143,必須嚴格大於表中前一個項目。若第一個項目為 LY=0,會由 VBlank 處理套用,以建立影格開始時的狀態。
scx背景捲動位元組,範圍 0..255。SCX/SCY 指定從背景地圖何處讀取,而非螢幕座標。座標會在 256 像素背景中循環。
scy背景捲動位元組,範圍 0..255。SCX/SCY 指定從背景地圖何處讀取,而非螢幕座標。座標會在 256 像素背景中循環。
screen_x視窗左邊緣的螢幕 X 座標。包裝函式加 7 形成 WX。通常使用 0..159;249 以上會在位元組加法中回繞,請勿藉此隱藏視窗。
screen_y視窗 WY,以距離上邊緣的像素數表示。Y 不像 X,無須加 7。WY 大於或等於 144 時,可見區域中沒有起始線。
flags通常傳入 WIN_SHOW 或 WIN_HIDE。包裝函式會加上 WIN,因此傳入零即可更新座標而不改變顯示狀態。其他支援的位元會原樣傳遞,請避免意外觸發 BG 或色彩操作。
回傳值
成功時傳回 KQ_RASTER_OK(0),失敗時傳回 1..4 的錯誤狀態。請參閱函式限制與 Raster_GetLastError。
使用條件與限制
引入 raster.h,並編譯 raster.c 與 scroll.c。共用表最多容納 8 個區帶。使用 Raster_* 建表時,請勿穿插直接呼叫 Scroll_Split* 或 __scroll_split_*;這些呼叫不會更新包裝層的數量與最後一條線的記錄。
請在 VBlank 或可掌握顯示影響的時段,依清除、加入項目、提交的順序重建。清除也會停止目前的分割效果,並不是在編輯獨立的後備緩衝區。LY 排定的是中斷時機,寫入暫存器還需額外時間。逐掃描線波浪效果請使用獨立的 Raster_LineX* 系列,勿同時執行兩種驅動。
狀態碼為 0 OK、1 FULL、2 BAD_LY、3 UNSORTED、4 BAD_RANGE。加入操作依序檢查 LY 範圍、容量與排序。遭拒的項目不會增加表的大小。之後成功加入項目或清除表,錯誤碼都會歸零,因此每次呼叫後都應立即檢查回傳值。
使用範例
Raster_PushBgWindowScreen(0,8,0,24,48,KQ_RASTER_WIN_SHOW);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
背景 X=8 將紅色背景矩形移至 (24,16)。視窗原點維持 (24,48),因此藍色矩形仍在 (32,56),展示兩套座標系統彼此獨立。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_bg_window.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/raster.h:60
Queue both background and window updates, converting window screen X to WX.
kitaqgb/lib/raster.c:145
u8 Raster_PushBgWindowScreen(u8 ly, u8 scx, u8 scy, u8 screen_x, u8 screen_y, u8 flags)
{
flags = (u8)(flags | KQ_RASTER_BG | KQ_RASTER_WIN);
return Raster_PushEx(ly, scx, scy, (u8)(screen_x + 7), screen_y, flags);
}Raster_PushEx
加入擴充區帶,執行旗標選定的背景、視窗、顯示或色彩操作。一般僅改變背景時,請使用參數較少的 Raster_Push。
語法
u8 Raster_PushEx(u8 ly, u8 scx, u8 scy, u8 wx, u8 wy, u8 flags);參數
ly排定的可見線,範圍 0..143,必須嚴格大於表中前一個項目。若第一個項目為 LY=0,會由 VBlank 處理套用,以建立影格開始時的狀態。
scx背景捲動位元組,範圍 0..255。SCX/SCY 指定從背景地圖何處讀取,而非螢幕座標。座標會在 256 像素背景中循環。
scy背景捲動位元組,範圍 0..255。SCX/SCY 指定從背景地圖何處讀取,而非螢幕座標。座標會在 256 像素背景中循環。
wx硬體 WX 原始值。一般螢幕 X 座標需加 7;WX=7 會將視窗放在左邊緣。此函式不限制或驗證 WX。
wy視窗 WY,以距離上邊緣的像素數表示。Y 不像 X,無須加 7。WY 大於或等於 144 時,可見區域中沒有起始線。
flags旗標:BG=1 更新背景捲動,WIN=2 更新 WX/WY,WIN_SHOW=4 顯示視窗,WIN_HIDE=8 隱藏視窗,BG_COLOR0=16 更新 CGB 背景色零。未知高位元會丟棄。同時指定 SHOW 與 HIDE 時,最後套用 SHOW。色彩更新會重用 SCX/SCY 資料欄位,不可與一般背景捲動合併。
回傳值
成功時傳回 KQ_RASTER_OK(0),失敗時傳回 1..4 的錯誤狀態。請參閱函式限制與 Raster_GetLastError。
使用條件與限制
引入 raster.h,並編譯 raster.c 與 scroll.c。共用表最多容納 8 個區帶。使用 Raster_* 建表時,請勿穿插直接呼叫 Scroll_Split* 或 __scroll_split_*;這些呼叫不會更新包裝層的數量與最後一條線的記錄。
請在 VBlank 或可掌握顯示影響的時段,依清除、加入項目、提交的順序重建。清除也會停止目前的分割效果,並不是在編輯獨立的後備緩衝區。LY 排定的是中斷時機,寫入暫存器還需額外時間。逐掃描線波浪效果請使用獨立的 Raster_LineX* 系列,勿同時執行兩種驅動。
狀態碼為 0 OK、1 FULL、2 BAD_LY、3 UNSORTED、4 BAD_RANGE。加入操作依序檢查 LY 範圍、容量與排序。遭拒的項目不會增加表的大小。之後成功加入項目或清除表,錯誤碼都會歸零,因此每次呼叫後都應立即檢查回傳值。
使用範例
Raster_PushEx(104,16,0,7,0,KQ_RASTER_BG|KQ_RASTER_WIN_HIDE);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
三個 24x16 像素的紅色矩形(DMG 上為黑色)出現在 (32,16)、(24,80)、(16,112)。越下方的區帶向左偏移越多。內部結果記錄數量 3、錯誤 0、提交結果 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_bands.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/raster.h:52
Append a validated extended band after masking flags to supported operations.
kitaqgb/lib/raster.c:112
u8 Raster_PushEx(u8 ly, u8 scx, u8 scy, u8 wx, u8 wy, u8 flags)
{
u8 r;
r = Raster_CheckPush(ly);
if (r != KQ_RASTER_OK) return r;
// Masking removes unknown bits but does not reject conflicting supported operations.
flags = (u8)(flags & KQ_RASTER_FLAG_MASK);
Scroll_SplitPushEx(ly, scx, scy, wx, wy, flags);
Raster_LastLyValue = ly;
Raster_HasLastLy = 1;
Raster_CountValue++;
Raster_LastErrorValue = KQ_RASTER_OK;
return KQ_RASTER_OK;
}Raster_PushWindowRaw
使用硬體原始 WX/WY 加入視窗區帶,自動加上 WIN,並將兩個背景資料位元組設為零。
語法
u8 Raster_PushWindowRaw(u8 ly, u8 wx, u8 wy, u8 flags);參數
ly排定的可見線,範圍 0..143,必須嚴格大於表中前一個項目。若第一個項目為 LY=0,會由 VBlank 處理套用,以建立影格開始時的狀態。
wx硬體 WX 原始值。一般螢幕 X 座標需加 7;WX=7 會將視窗放在左邊緣。此函式不限制或驗證 WX。
wy視窗 WY,以距離上邊緣的像素數表示。Y 不像 X,無須加 7。WY 大於或等於 144 時,可見區域中沒有起始線。
flags通常傳入 WIN_SHOW 或 WIN_HIDE。包裝函式會加上 WIN,因此傳入零即可更新座標而不改變顯示狀態。其他支援的位元會原樣傳遞,請避免意外觸發 BG 或色彩操作。
回傳值
成功時傳回 KQ_RASTER_OK(0),失敗時傳回 1..4 的錯誤狀態。請參閱函式限制與 Raster_GetLastError。
使用條件與限制
引入 raster.h,並編譯 raster.c 與 scroll.c。共用表最多容納 8 個區帶。使用 Raster_* 建表時,請勿穿插直接呼叫 Scroll_Split* 或 __scroll_split_*;這些呼叫不會更新包裝層的數量與最後一條線的記錄。
請在 VBlank 或可掌握顯示影響的時段,依清除、加入項目、提交的順序重建。清除也會停止目前的分割效果,並不是在編輯獨立的後備緩衝區。LY 排定的是中斷時機,寫入暫存器還需額外時間。逐掃描線波浪效果請使用獨立的 Raster_LineX* 系列,勿同時執行兩種驅動。
狀態碼為 0 OK、1 FULL、2 BAD_LY、3 UNSORTED、4 BAD_RANGE。加入操作依序檢查 LY 範圍、容量與排序。遭拒的項目不會增加表的大小。之後成功加入項目或清除表,錯誤碼都會歸零,因此每次呼叫後都應立即檢查回傳值。
使用範例
Raster_PushWindowRaw(0,31,48,KQ_RASTER_WIN_SHOW);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
WX=31、WY=48 會將視窗原點設在螢幕 (24,48)。視窗內 (8,8) 的藍色 16x16 矩形出現在螢幕 (32,56)。上方紅色背景矩形保持在 (32,16)。DMG 上兩者皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_window_raw.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/raster.h:55
Enable window updates and pass hardware WX/WY values without coordinate conversion.
kitaqgb/lib/raster.c:131
u8 Raster_PushWindowRaw(u8 ly, u8 wx, u8 wy, u8 flags)
{
flags = (u8)(flags | KQ_RASTER_WIN);
return Raster_PushEx(ly, 0, 0, wx, wy, flags);
}Raster_PushWindowScreen
以螢幕座標加入視窗區帶。在呼叫原始值版本前先將 X 加 7,呼叫端可直接定位視窗,避免混淆螢幕 X 與 WX。
語法
u8 Raster_PushWindowScreen(u8 ly, u8 screen_x, u8 screen_y, u8 flags);參數
ly排定的可見線,範圍 0..143,必須嚴格大於表中前一個項目。若第一個項目為 LY=0,會由 VBlank 處理套用,以建立影格開始時的狀態。
screen_x視窗左邊緣的螢幕 X 座標。包裝函式加 7 形成 WX。通常使用 0..159;249 以上會在位元組加法中回繞,請勿藉此隱藏視窗。
screen_y視窗 WY,以距離上邊緣的像素數表示。Y 不像 X,無須加 7。WY 大於或等於 144 時,可見區域中沒有起始線。
flags通常傳入 WIN_SHOW 或 WIN_HIDE。包裝函式會加上 WIN,因此傳入零即可更新座標而不改變顯示狀態。其他支援的位元會原樣傳遞,請避免意外觸發 BG 或色彩操作。
回傳值
成功時傳回 KQ_RASTER_OK(0),失敗時傳回 1..4 的錯誤狀態。請參閱函式限制與 Raster_GetLastError。
使用條件與限制
引入 raster.h,並編譯 raster.c 與 scroll.c。共用表最多容納 8 個區帶。使用 Raster_* 建表時,請勿穿插直接呼叫 Scroll_Split* 或 __scroll_split_*;這些呼叫不會更新包裝層的數量與最後一條線的記錄。
請在 VBlank 或可掌握顯示影響的時段,依清除、加入項目、提交的順序重建。清除也會停止目前的分割效果,並不是在編輯獨立的後備緩衝區。LY 排定的是中斷時機,寫入暫存器還需額外時間。逐掃描線波浪效果請使用獨立的 Raster_LineX* 系列,勿同時執行兩種驅動。
狀態碼為 0 OK、1 FULL、2 BAD_LY、3 UNSORTED、4 BAD_RANGE。加入操作依序檢查 LY 範圍、容量與排序。遭拒的項目不會增加表的大小。之後成功加入項目或清除表,錯誤碼都會歸零,因此每次呼叫後都應立即檢查回傳值。
使用範例
Raster_PushWindowScreen(0,24,48,KQ_RASTER_WIN_SHOW);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
直接傳入螢幕座標 (24,48),會得到與原始值範例相同、位於 (32,56) 的藍色視窗矩形。函式庫會在 X 加上 7。上方紅色背景矩形位於 (32,16)。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_window_screen.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/raster.h:58
Convert screen X to hardware WX by adding seven, then queue a window band. The byte addition wraps if callers supply an excessive X coordinate.
kitaqgb/lib/raster.c:139
u8 Raster_PushWindowScreen(u8 ly, u8 screen_x, u8 screen_y, u8 flags)
{
return Raster_PushWindowRaw(ly, (u8)(screen_x + 7), screen_y, flags);
}rpg.h — 亂數、文字、地圖、儲存及 RPG/ADV/SLG 功能
絕對位置文字輔助函式直接繪製到背景地圖。text_window 開啟帶框區域,text_clear_rect 填滿區域,text_print_xy 寫入圖塊位元組而不解讀控制碼。text_print_u8、text_print_u16 與 text_print_s16 將數值轉為十進位,僅占所需格數。替換不同長度的值時,須預留並清空完整欄位。
rpg.h 宣告的 RNG 函式實作於 lib/rng.c,共用編譯器的 GB 產生器:rng_seed 重設狀態,rng8/rng_next8 消耗一個位元組,rng16/rng_next16 消耗兩個,rand_range/rng_range、rng_chance 與 weighted_choice 則調整取值以供遊戲選擇。呼叫這些函式時,請隨程式編譯 rng.c。要讓測試可重現,須固定種子與呼叫順序;以取餘數進行的選擇不保證精確機率。
RLE 解碼使用 count/value 位元組配對與零 count 終止符。rle_decode 由一般指標讀取並解壓至 RAM;rle_decode_far 由指定 ROM 記憶體庫的指標讀取至 RAM;__rle_decode_vram 則以考慮 LCD 時序的寫入,將記憶體庫輸入直接解壓至 VRAM。RAM 函式位於 lib/rle.c,直接 VRAM 操作由編譯器產生。三者皆傳回輸出位元組數,且需要有效串流與足夠目的空間。
rpg.h 宣告的遊戲狀態儲存由 lib/flags.c 實作。三個旗標函式操作 2048 個獨立布林位元;quest_state 與 quest_set_state 則操作 64 個獨立位元組,代表遊戲定義的階段。使用時須編譯 flags.c 並遵守 ID 範圍。若進度須在關機後保留,請使用獨立存檔系統。
視窗對話共用一個作用中矩形、游標及字元速度設定。text_open 初始化區域,text_close 清除區域,text_set_speed 設定逐字 VBlank 等待。text_print 與 text_print_far 解讀控制串流,text_choice 執行阻塞式垂直選單。請載入圖塊、安排適當區域大小,並規劃遊戲如何處理這些阻塞呼叫。
提供地圖/複合圖塊繪製、腳本、SRAM 存檔及尋路。一般格子為 8×8 像素,複合圖塊為 16×16。載入/繪製、移動遮罩及攻擊遮罩各自獨立;遊戲負責協調圖形載入與事件執行。
搜尋使用約 4 KiB 的共用工作區,且不可重入。地圖最多 1024 格,探索距離最多 254。距離 0xFF 表示未到達,因此無法表示 255 步的路徑。成本/遮罩輸出需要 width*height 個可寫入位元組。
預設為四個 512 位元組插槽,每個含六位元組標頭及最多 506 位元組資料。範例使用搭配 8 KiB SRAM 的 MBC5。呼叫結束時會停用 RAM,不還原先前的記憶體庫或啟用狀態。
選單同時支援等待選擇完成的阻塞模式,以及由遊戲迴圈分別呼叫輸入與繪圖的模式。道具選單會顯示名稱及數量。
camera_center
在 20×18 圖塊的可視區域中將一般地圖格子置中,並限制於地圖邊界內。
語法
void camera_center(u8 x, u8 y);參數
x格子的 X 座標。
y格子的 Y 座標。
回傳值
無傳回值。
使用條件與限制
原點先設為 max(x−10,0)、max(y−9,0),再限制於地圖邊界內,最後將原點*8 的低位元組寫入 SCX/SCY。複合圖塊模式不套用此操作。不會將新的列或欄串流載入 VRAM。
使用範例
camera_center(5,4);result[9]=*((u8*)0xFF43);result[10]=*((u8*)0xFF42);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側格線顯示三步內的移動成本,右側顯示從 S 到 G 的最短路徑。綠色星號標出繞過紅色三格牆的九步路徑,藍色數字表示成本。DMG 使用相同配置但以黑色顯示。RAM 檢查也示範攻擊遮罩會忽略牆壁。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_map_path.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_map_path.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/rpg.h:297
Center an ordinary-map tile coordinate within a 20-by-18 viewport and clamp the scroll origin to its edges. This adjusts scroll registers only; it does not stream newly exposed map rows into VRAM.
kitaqgb/lib/map.c:105
void camera_center(u8 x, u8 y)
{
u8 tile_x = 0;
u8 tile_y = 0;
u8 max_x = 0;
u8 max_y = 0;
map_camera_x = x;
map_camera_y = y;
if (map_loaded == 0) return;
if (map_current.width > 20) max_x = (u8)(map_current.width - 20);
if (map_current.height > 18) max_y = (u8)(map_current.height - 18);
if (x > 10) tile_x = (u8)(x - 10);
if (y > 9) tile_y = (u8)(y - 9);
if (tile_x > max_x) tile_x = max_x;
if (tile_y > max_y) tile_y = max_y;
__scroll_bg_set((u8)(tile_x << 3), (u8)(tile_y << 3));
}far_read16
透過帶有記憶體庫資訊的指標讀取小端序雙位元組值。
語法
#define far_read16(p) __farpeek16((p).bank, (p).ptr)參數
p包含 bank 與 ptr 的 far_ptr_t;ptr 是 CPU 可見位址。
回傳值
u16 型別的雙位元組值。
使用條件與限制
巨集分別讀取 p.bank 與 p.ptr,請勿傳入有副作用的運算式。內建函式會暫時選取 ROM 記憶體庫,再還原原設定。請避免中斷同時變更記憶體庫。
使用範例
result[1]=far_read16(far);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
從另一個 ROM 記憶體庫讀取十六進位 34 12 AB:第一個位元組為 52,小端序雙位元組值為 4660,複製後最後一個位元組為 171。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_far.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_far.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/rpg.h:172
far_read8
透過帶有記憶體庫資訊的指標讀取一個位元組。
語法
#define far_read8(p) __farpeek8((p).bank, (p).ptr)參數
p包含 bank 與 ptr 的 far_ptr_t;ptr 是 CPU 可見位址。
回傳值
u8 型別的位元組。
使用條件與限制
巨集分別讀取 p.bank 與 p.ptr,請勿傳入有副作用的運算式。內建函式會暫時選取 ROM 記憶體庫,再還原原設定。請避免中斷同時變更記憶體庫。
使用範例
far.bank=1;far.ptr=bank_bytes;result[0]=far_read8(far);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
從另一個 ROM 記憶體庫讀取十六進位 34 12 AB:第一個位元組為 52,小端序雙位元組值為 4660,複製後最後一個位元組為 171。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_far.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_far.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/rpg.h:171
far_read_block
從帶有記憶體庫資訊的指標,將連續位元組複製到 RAM。
語法
#define far_read_block(dst, p, len) __farmemcpy((dst), (p).bank, (p).ptr, (len))參數
dst長度為 len 個可寫入 RAM 位元組的起點。
p包含 bank 與 ptr 的 far_ptr_t;ptr 是 CPU 可見位址。
len位元組數;來源範圍必須位於同一記憶體庫內。
回傳值
無傳回值。
使用條件與限制
轉交給 __farmemcpy 的巨集。不會自動跨越 ROM 記憶體庫邊界,也不是可處理重疊記憶體區域的搬移操作。
使用範例
far_read_block(copy,far,3);result[2]=copy[2];這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
從另一個 ROM 記憶體庫讀取十六進位 34 12 AB:第一個位元組為 52,小端序雙位元組值為 4660,複製後最後一個位元組為 171。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_far.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_far.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/rpg.h:173
flag_clear
將一個遊戲旗標清為 0,不會清除相鄰旗標。事件條件撤銷或需要明確初始化旗標時使用。原本已清除的旗標仍保持零。
語法
void flag_clear(u16 id);參數
id旗標編號 0~2047,以 u16 傳入。位元組偏移為 id / 8,內部位元為 id % 8,從最低有效位元起算。較寬的參數型別不會擴大固定 2048 個旗標的儲存空間。
回傳值
無(void)。
使用條件與限制
函式不會驗證 ID。旗標 ID 須小於 2048,任務 ID 須小於 64;超出範圍可能讀取或覆寫無關 RAM。範例明確初始化,不依賴啟動時的內容。
flags.c 在 RAM 中擁有 256 位元組旗標儲存區及獨立的 64 位元組任務儲存區。這些函式不存取卡匣存檔 RAM,資料也不會在關機後保留。若要保存進度,遊戲須透過存檔系統序列化旗標與任務值,並於載入時還原。
請包含 rpg.h,並將 lib/flags.c 與遊戲一同編譯。陣列僅供該原始檔內部使用,請透過旗標/任務 API 存取。所有呼叫端共用儲存空間,因此須自行協調主迴圈與中斷處理常式的寫入。
使用範例
flag_clear(9);flag_clear(9); // Mark it closed; clearing twice still leaves 0.
cleared=flag_get(9);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例先設定門旗標 9,再將它清除。即使呼叫清除兩次,DOOR CLOSED 仍顯示 000。先前觀察到的 DOOR OPEN 001 也保留在畫面上,方便比較兩次儲存的觀察結果。
完整程式在白底上顯示十進位結果:DMG 為黑字,CGB 為藍字。FAILED 必須為 000。擷取畫面只呈現 RAM 狀態行為,並非遊戲存檔示範。
DMG 模擬器驗證涵蓋旗標 ID 0~2047 全部、重複設定/清除、相鄰項目,以及 64 個任務各自的全部 256 種狀態值。最後將 256 位元組旗標圖樣及 64 個任務位元組與預期資料比較。兩個教學畫面皆於 240 影格後檢查。未測試實機或存檔持久性。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\flags_quests.c .\kitaqgb\lib\flags.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\flags_quests.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:372
Clear a flag bit; id must be below 2048.
kitaqgb/lib/flags.c:21
void flag_clear(u16 id)
{
__bit_clear(flags_bits, id);
}flag_get
從函式庫的 RAM 位元陣列讀取一個開/關遊戲旗標。可用來查詢門是否開啟、道具是否取得,或其他遊戲定義的事件是否發生。讀取不會變更旗標。
語法
u8 flag_get(u16 id);參數
id旗標編號 0~2047,以 u16 傳入。位元組偏移為 id / 8,內部位元為 id % 8,從最低有效位元起算。較寬的參數型別不會擴大固定 2048 個旗標的儲存空間。
回傳值
正規化的 u8 布林值:旗標清除時為 0,設定時為 1。此 GB 函式庫呼叫會正規化結果的 GB 內建函式 __bit_test。
使用條件與限制
函式不會驗證 ID。旗標 ID 須小於 2048,任務 ID 須小於 64;超出範圍可能讀取或覆寫無關 RAM。範例明確初始化,不依賴啟動時的內容。
flags.c 在 RAM 中擁有 256 位元組旗標儲存區及獨立的 64 位元組任務儲存區。這些函式不存取卡匣存檔 RAM,資料也不會在關機後保留。若要保存進度,遊戲須透過存檔系統序列化旗標與任務值,並於載入時還原。
請包含 rpg.h,並將 lib/flags.c 與遊戲一同編譯。陣列僅供該原始檔內部使用,請透過旗標/任務 API 存取。所有呼叫端共用儲存空間,因此須自行協調主迴圈與中斷處理常式的寫入。
使用範例
before=flag_get(9); // Door-open flag: 0 after explicit initialization.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例以旗標 9 代表門。明確清除後,BEFORE 顯示 000。之後設定及清除旗標,會得到 DOOR OPEN 001 與 DOOR CLOSED 000,顯示讀取結果反映儲存的條件。
完整程式在白底上顯示十進位結果:DMG 為黑字,CGB 為藍字。FAILED 必須為 000。擷取畫面只呈現 RAM 狀態行為,並非遊戲存檔示範。
DMG 模擬器驗證涵蓋旗標 ID 0~2047 全部、重複設定/清除、相鄰項目,以及 64 個任務各自的全部 256 種狀態值。最後將 256 位元組旗標圖樣及 64 個任務位元組與預期資料比較。兩個教學畫面皆於 240 影格後檢查。未測試實機或存檔持久性。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\flags_quests.c .\kitaqgb\lib\flags.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\flags_quests.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:368
Read a bit from the flag array. Callers must keep id below 2048.
kitaqgb/lib/flags.c:9
u8 flag_get(u16 id)
{
return __bit_test(flags_bits, id);
}flag_set
將一個遊戲旗標設為 1,同時保留同一位元組中的其他七個旗標。已設定的旗標仍維持設定狀態;可用來記錄開門等一次性事件。
語法
void flag_set(u16 id);參數
id旗標編號 0~2047,以 u16 傳入。位元組偏移為 id / 8,內部位元為 id % 8,從最低有效位元起算。較寬的參數型別不會擴大固定 2048 個旗標的儲存空間。
回傳值
無(void)。
使用條件與限制
函式不會驗證 ID。旗標 ID 須小於 2048,任務 ID 須小於 64;超出範圍可能讀取或覆寫無關 RAM。範例明確初始化,不依賴啟動時的內容。
flags.c 在 RAM 中擁有 256 位元組旗標儲存區及獨立的 64 位元組任務儲存區。這些函式不存取卡匣存檔 RAM,資料也不會在關機後保留。若要保存進度,遊戲須透過存檔系統序列化旗標與任務值,並於載入時還原。
請包含 rpg.h,並將 lib/flags.c 與遊戲一同編譯。陣列僅供該原始檔內部使用,請透過旗標/任務 API 存取。所有呼叫端共用儲存空間,因此須自行協調主迴圈與中斷處理常式的寫入。
使用範例
flag_set(9); // Mark the door as open; setting an already set flag is harmless.
flag_set(9);
opened=flag_get(9);neighbor=flag_get(8); // 1 and 0: adjacent flag is unchanged.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例將門旗標 9 設定兩次。DOOR OPEN 顯示 001,相鄰旗標 8 仍為 NEIGHBOR 000。兩旗標位於同一位元組,因此相鄰值證明設定其中一個旗標會保留另一個。
完整程式在白底上顯示十進位結果:DMG 為黑字,CGB 為藍字。FAILED 必須為 000。擷取畫面只呈現 RAM 狀態行為,並非遊戲存檔示範。
DMG 模擬器驗證涵蓋旗標 ID 0~2047 全部、重複設定/清除、相鄰項目,以及 64 個任務各自的全部 256 種狀態值。最後將 256 位元組旗標圖樣及 64 個任務位元組與預期資料比較。兩個教學畫面皆於 240 影格後檢查。未測試實機或存檔持久性。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\flags_quests.c .\kitaqgb\lib\flags.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\flags_quests.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:370
Set a flag bit without disturbing adjacent flags; id must be below 2048.
kitaqgb/lib/flags.c:15
void flag_set(u16 id)
{
__bit_set(flags_bits, id);
}map_current_height
讀取作用中地圖的高度。
語法
u8 map_current_height();回傳值
傳回以格子為單位的高度;沒有載入地圖時為零。
使用條件與限制
座標指向目前地圖中的格子:一般圖塊為 8×8 像素,複合圖塊為 16×16 像素。
使用範例
result[1]=map_current_height();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側格線顯示三步內的移動成本,右側顯示從 S 到 G 的最短路徑。綠色星號標出繞過紅色三格牆的九步路徑,藍色數字表示成本。DMG 使用相同配置但以黑色顯示。RAM 檢查也示範攻擊遮罩會忽略牆壁。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_map_path.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_map_path.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/rpg.h:391
Return the active map height in its own cell units, or zero when no map is loaded.
kitaqgb/lib/map.c:25
u8 map_current_height()
{
if (map_meta_loaded != 0) return map_meta_current.height;
if (map_loaded == 0) return 0;
return map_current.height;
}map_current_width
讀取作用中地圖的寬度。
語法
u8 map_current_width();回傳值
傳回以格子為單位的寬度;沒有載入地圖時為零。
使用條件與限制
座標指向目前地圖中的格子:一般圖塊為 8×8 像素,複合圖塊為 16×16 像素。
使用範例
result[0]=map_current_width();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側格線顯示三步內的移動成本,右側顯示從 S 到 G 的最短路徑。綠色星號標出繞過紅色三格牆的九步路徑,藍色數字表示成本。DMG 使用相同配置但以黑色顯示。RAM 檢查也示範攻擊遮罩會忽略牆壁。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_map_path.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_map_path.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/rpg.h:389
Return the active map width in its own cell units, or zero when no map is loaded.
kitaqgb/lib/map.c:17
u8 map_current_width()
{
if (map_meta_loaded != 0) return map_meta_current.width;
if (map_loaded == 0) return 0;
return map_current.width;
}map_draw_visible
從指定原點繪製 10×9 個複合圖塊,並保存該相機位置供後續髒標記重繪使用。
語法
void map_draw_visible(u8 camera_tx, u8 camera_ty);參數
camera_tx最左側格子的 X;請保持不大於 246,以避免遍歷時位元組回捲。
camera_ty最上方格子的 Y;請保持不大於 247。
回傳值
無傳回值。
使用條件與限制
地圖外的格子會繪製複合圖塊 ID 0,因此務必提供定義零。此呼叫不改變 20×18 圖塊可視區域外的格子或 CGB 屬性。
使用範例
map_draw_visible(1,0);result[9]=*((u8*)0x9800);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
修改 RAM 中的複合圖塊 ID、標記變更,再提交。相機 (1,0) 會在左上角顯示綠色 16×16 正方形。範例明確將調色盤中繼資料套用到 CGB 屬性;DMG 顯示黑色正方形。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_metatile.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_metatile.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/rpg.h:304
Draw a 10-by-9 metatile viewport as 20-by-18 individual background tiles. Out-of-range cells use definition zero; palette attributes are not written. Remember the camera and clear the dirty flag after the full redraw.
kitaqgb/lib/map.c:212
void map_draw_visible(u8 camera_tx, u8 camera_ty)
{
u8 my;
if (map_meta_loaded == 0) return;
map_camera_x = camera_tx;
map_camera_y = camera_ty;
my = 0;
while (my < 9) {
u8 mx = 0;
while (mx < 10) {
u8 tx = (u8)(camera_tx + mx);
u8 ty = (u8)(camera_ty + my);
u8 sx = (u8)(mx << 1);
u8 sy = (u8)(my << 1);
metatile_t meta;
u8 id = map_get_metatile(tx, ty);
map_read_metatile(id, &meta);
__settile_xy(sx, sy, meta.tile_tl);
__settile_xy((u8)(sx + 1), sy, meta.tile_tr);
__settile_xy(sx, (u8)(sy + 1), meta.tile_bl);
__settile_xy((u8)(sx + 1), (u8)(sy + 1), meta.tile_br);
mx++;
}
my++;
}
map_dirty = 0;
}map_flush_dirty
有髒標記時,從儲存的相機原點重繪可視區域,並清除髒旗標。
語法
void map_flush_dirty();回傳值
無傳回值。
使用條件與限制
沒有髒標記時不執行任何動作。重繪涵蓋全部 10×9 個複合圖塊,而非僅修改的格子。
使用範例
map_flush_dirty();result[11]=*((u8*)0x9800);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
修改 RAM 中的複合圖塊 ID、標記變更,再提交。相機 (1,0) 會在左上角顯示綠色 16×16 正方形。範例明確將調色盤中繼資料套用到 CGB 屬性;DMG 顯示黑色正方形。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_metatile.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_metatile.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/rpg.h:321
Redraw the remembered metatile viewport only when the shared dirty flag is set.
kitaqgb/lib/map.c:254
void map_flush_dirty()
{
if (map_dirty == 0) return;
map_draw_visible(map_camera_x, map_camera_y);
}map_get_attr
從格子的複合圖塊定義讀取調色盤中繼資料。
語法
u8 map_get_attr(u8 tx, u8 ty);參數
tx複合圖塊的 X 座標。
ty複合圖塊的 Y 座標。
回傳值
傳回調色盤位元組。地圖外的格子使用定義零;未使用複合圖塊模式時傳回零。
使用條件與限制
座標指向目前地圖中的格子:一般圖塊為 8×8 像素,複合圖塊為 16×16 像素。
使用範例
result[3]=map_get_attr(0,0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
修改 RAM 中的複合圖塊 ID、標記變更,再提交。相機 (1,0) 會在左上角顯示綠色 16×16 正方形。範例明確將調色盤中繼資料套用到 CGB 屬性;DMG 顯示黑色正方形。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_metatile.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_metatile.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/rpg.h:310
Return the selected definition's palette byte. An out-of-range coordinate uses the metatile-zero fallback; this function does not write CGB attributes.
kitaqgb/lib/map.c:172
u8 map_get_attr(u8 tx, u8 ty)
{
metatile_t meta;
u8 id;
if (map_meta_loaded == 0) return 0;
id = map_get_metatile(tx, ty);
map_read_metatile(id, &meta);
return meta.palette;
}map_get_event
讀取複合圖塊事件 ID;一般地圖則回報是否存在事件。
語法
u8 map_get_event(u8 tx, u8 ty);參數
tx複合圖塊的 X 座標。
ty複合圖塊的 Y 座標。
回傳值
傳回複合圖塊事件位元組或一般地圖的布林值;沒有地圖或格子位於外部時傳回零。
使用條件與限制
座標指向目前地圖中的格子:一般圖塊為 8×8 像素,複合圖塊為 16×16 像素。
使用範例
result[7]=map_get_event(0,0);result[8]=map_get_event(3,0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
修改 RAM 中的複合圖塊 ID、標記變更,再提交。相機 (1,0) 會在左上角顯示綠色 16×16 正方形。範例明確將調色盤中繼資料套用到 CGB 屬性;DMG 顯示黑色正方形。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_metatile.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_metatile.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/rpg.h:316
Return a metatile event ID, or the ordinary-map Boolean trigger result. Missing/out-of-range metatile cells have no event.
kitaqgb/lib/map.c:197
u8 map_get_event(u8 tx, u8 ty)
{
metatile_t meta;
u8 id;
if (map_meta_loaded == 0) return map_trigger_at(tx, ty);
if (tx >= map_meta_current.width || ty >= map_meta_current.height) return 0;
id = map_get_metatile(tx, ty);
map_read_metatile(id, &meta);
return meta.event;
}map_get_metatile
讀取格子的複合圖塊 ID。
語法
u8 map_get_metatile(u8 tx, u8 ty);參數
tx複合圖塊的 X 座標。
ty複合圖塊的 Y 座標。
回傳值
傳回 ID;地圖外或未使用複合圖塊模式時為零。
使用條件與限制
座標指向目前地圖中的格子:一般圖塊為 8×8 像素,複合圖塊為 16×16 像素。
使用範例
result[1]=map_get_metatile(0,0);result[2]=map_get_metatile(3,0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
修改 RAM 中的複合圖塊 ID、標記變更,再提交。相機 (1,0) 會在左上角顯示綠色 16×16 正方形。範例明確將調色盤中繼資料套用到 CGB 屬性;DMG 顯示黑色正方形。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_metatile.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_metatile.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/rpg.h:307
Read a row-major metatile ID, returning ID zero for inactive or out-of-range lookups. Callers must provide a usable definition for metatile zero.
kitaqgb/lib/map.c:159
u8 map_get_metatile(u8 tx, u8 ty)
{
u16 index;
if (map_meta_loaded == 0) return 0;
if (tx >= map_meta_current.width || ty >= map_meta_current.height) return 0;
index = __map_index(tx, ty, map_meta_current.width);
return __farpeek8(map_meta_data_bank(), map_meta_current.metatile_ids + index);
}map_is_blocked
檢查目的格子是否阻擋移動;複合圖塊模式使用定義中的 collision 欄位。
語法
u8 map_is_blocked(u8 x, u8 y);參數
x格子的 X 座標。
y格子的 Y 座標。
回傳值
牆壁、地圖外座標或沒有地圖時傳回 1;可通行格子傳回 0。一般地圖的碰撞陣列為 NULL 時,所有地圖內格子皆可通行。
使用條件與限制
座標指向目前地圖中的格子:一般圖塊為 8×8 像素,複合圖塊為 16×16 像素。
使用範例
result[4]=map_is_blocked(2,2);result[5]=map_is_blocked(6,2);result[6]=map_is_blocked(1,2);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側格線顯示三步內的移動成本,右側顯示從 S 到 G 的最短路徑。綠色星號標出繞過紅色三格牆的九步路徑,藍色數字表示成本。DMG 使用相同配置但以黑色顯示。RAM 檢查也示範攻擊遮罩會忽略牆壁。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_map_path.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_map_path.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/rpg.h:290
Use metatile collision when that mode is active; otherwise read one packed collision bit. Missing maps/out-of-range cells block movement, but a valid ordinary map without a collision array is entirely passable.
kitaqgb/lib/map.c:68
u8 map_is_blocked(u8 x, u8 y)
{
u16 index;
u8 value;
if (map_meta_loaded != 0) return map_is_solid(x, y);
if (map_loaded == 0) return 1;
if (x >= map_current.width || y >= map_current.height) return 1;
if (map_current.collision_bits == 0) return 0;
index = __map_index(x, y, map_current.width);
// Collision uses least-significant bit first within each row-major group of eight cells.
value = __farpeek8(map_bank, map_current.collision_bits + (index >> 3));
if ((value & (u8)(1 << (index & 7))) != 0) return 1;
return 0;
}map_is_solid
檢查是否為實體;一般地圖模式改以碰撞位元判定。
語法
u8 map_is_solid(u8 tx, u8 ty);參數
tx複合圖塊的 X 座標。
ty複合圖塊的 Y 座標。
回傳值
collision 非零或格子位於地圖外時傳回 1,否則傳回 0。
使用條件與限制
座標指向目前地圖中的格子:一般圖塊為 8×8 像素,複合圖塊為 16×16 像素。
使用範例
result[4]=map_is_solid(0,0);result[5]=map_is_solid(1,0);result[6]=map_is_solid(3,0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
修改 RAM 中的複合圖塊 ID、標記變更,再提交。相機 (1,0) 會在左上角顯示綠色 16×16 正方形。範例明確將調色盤中繼資料套用到 CGB 屬性;DMG 顯示黑色正方形。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_metatile.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_metatile.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/rpg.h:313
Treat out-of-range metatile cells as solid; otherwise inspect the definition collision flag. In ordinary-map mode, delegate to its packed collision bits.
kitaqgb/lib/map.c:184
u8 map_is_solid(u8 tx, u8 ty)
{
metatile_t meta;
u8 id;
if (map_meta_loaded == 0) return map_is_blocked(tx, ty);
if (tx >= map_meta_current.width || ty >= map_meta_current.height) return 1;
id = map_get_metatile(tx, ty);
map_read_metatile(id, &meta);
return (u8)(meta.collision != 0);
}map_load
載入一般地圖描述結構,從左上角最多繪製 20×18 個圖塊至所選背景映射表。
語法
void map_load(u8 bank, const map_t* map);參數
bank存放描述結構、碰撞位元與事件的 ROM 記憶體庫。
map緊密排列的九位元組 map_t。tiles 包含 width*height 個圖塊 ID;collision_bits 從最低位元開始打包各格子的碰撞資訊;events 每格儲存一個位元組。讀取圖塊時使用 bank_tiles。
回傳值
無傳回值。
使用條件與限制
共用一張作用中的地圖。描述結構本身會被複製,但其陣列在使用期間必須持續可讀取。圖塊圖形需另行載入 VRAM。
座標指向目前地圖中的格子:一般圖塊為 8×8 像素,複合圖塊為 16×16 像素。
不會清除小型地圖外的格子。一般地圖中,bank_tiles=0 表示記憶體庫零,不會沿用描述結構所在的記憶體庫。
使用範例
map_load(0,maps);result[2]=map_current_width();result[3]=map_current_height();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側格線顯示三步內的移動成本,右側顯示從 S 到 G 的最短路徑。綠色星號標出繞過紅色三格牆的九步路徑,藍色數字表示成本。DMG 使用相同配置但以黑色顯示。RAM 檢查也示範攻擊遮罩會忽略牆壁。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_map_path.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_map_path.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/rpg.h:286
Load the nine-byte ordinary-map descriptor and draw up to 20 by 18 tiles from its top-left corner. Drawing does not upload tile graphics or clear background cells beyond smaller map dimensions.
kitaqgb/lib/map.c:35
void map_load(u8 bank, const map_t* map)
{
u8 row;
u8 h;
u8 w;
// The literal copy size depends on the packed map_t layout; changing that layout requires updating this copy.
__farmemcpy(&map_current, bank, map, 9);
map_bank = bank;
map_loaded = 1;
map_meta_loaded = 0;
w = map_current.width;
h = map_current.height;
if (w > 20) w = 20;
if (h > 18) h = 18;
row = 0;
while (row < h) {
u8 x = 0;
u16 base_index = __map_index(0, row, map_current.width);
while (x < w) {
map_row[x] = __farpeek8(map_current.bank_tiles, map_current.tiles + base_index + x);
x++;
}
__settile_row(0, row, map_row, w);
row++;
}
}map_load_metatile
選取複合圖塊地圖,將相機 (0,0) 處的 10×9 格可視區域展開成 20×18 圖塊。
語法
void map_load_metatile(u8 bank, const metatile_map_t* map);參數
bank存放描述結構的 ROM 記憶體庫。
map指向 metatile_map_t 的指標。尺寸以 16×16 像素格子計算;結構參照 ID 陣列及每筆七位元組的 metatile_t 定義表。
回傳值
無傳回值。
使用條件與限制
共用一張作用中的地圖。描述結構本身會被複製,但其陣列在使用期間必須持續可讀取。圖塊圖形需另行載入 VRAM。
bank_tiles=0 會沿用描述結構的記憶體庫;非零值則同時指定 ID 與定義所用的記憶體庫。定義依序儲存左上、右上、左下、右下圖塊,以及碰撞、調色盤、事件。繪圖時不會自動套用調色盤中繼資料。
使用範例
map_load_metatile(0,&level);result[0]=*((u8*)0x9800);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
修改 RAM 中的複合圖塊 ID、標記變更,再提交。相機 (1,0) 會在左上角顯示綠色 16×16 正方形。範例明確將調色盤中繼資料套用到 CGB 屬性;DMG 顯示黑色正方形。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_metatile.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_metatile.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/rpg.h:300
Select metatile mode, copy its descriptor and draw the initial viewport with the camera at cell (0,0).
kitaqgb/lib/map.c:145
void map_load_metatile(u8 bank, const metatile_map_t* map)
{
map_meta_bank = bank;
__farmemcpy(&map_meta_current, bank, map, sizeof(metatile_map_t));
map_meta_loaded = 1;
map_loaded = 0;
map_dirty = 0;
map_camera_x = 0;
map_camera_y = 0;
map_draw_visible(0, 0);
}map_mark_dirty
收到有效複合圖塊座標時,將可視區域標記為需要重繪。
語法
void map_mark_dirty(u8 tx, u8 ty);參數
tx複合圖塊的 X 座標。
ty複合圖塊的 Y 座標。
回傳值
無傳回值。
使用條件與限制
設定一個共用髒旗標,而非逐格排入更新。忽略地圖外座標。呼叫端應先另行修改 ID 或定義,再標記為需要重繪。
使用範例
ids[1]=1;map_mark_dirty(1,0);result[10]=*((u8*)0x9800);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
修改 RAM 中的複合圖塊 ID、標記變更,再提交。相機 (1,0) 會在左上角顯示綠色 16×16 正方形。範例明確將調色盤中繼資料套用到 CGB 屬性;DMG 顯示黑色正方形。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_metatile.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_metatile.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/rpg.h:319
Mark the viewport for a full redraw when a valid metatile cell changes. The coordinate is validated but no per-cell dirty list is retained.
kitaqgb/lib/map.c:246
void map_mark_dirty(u8 tx, u8 ty)
{
if (map_meta_loaded == 0) return;
if (tx >= map_meta_current.width || ty >= map_meta_current.height) return;
map_dirty = 1;
}map_trigger_at
檢查格子是否有事件,但不執行事件。
語法
u8 map_trigger_at(u8 x, u8 y);參數
x格子的 X 座標。
y格子的 Y 座標。
回傳值
有事件時傳回 1,否則為 0;不傳回儲存的事件位元組或複合圖塊事件 ID。
使用條件與限制
座標指向目前地圖中的格子:一般圖塊為 8×8 像素,複合圖塊為 16×16 像素。
使用範例
result[7]=map_trigger_at(5,4);result[8]=map_trigger_at(6,4);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側格線顯示三步內的移動成本,右側顯示從 S 到 G 的最短路徑。綠色星號標出繞過紅色三格牆的九步路徑,藍色數字表示成本。DMG 使用相同配置但以黑色顯示。RAM 檢查也示範攻擊遮罩會忽略牆壁。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_map_path.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_map_path.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/rpg.h:293
Report whether an event exists at the cell. Ordinary maps expose a Boolean byte-presence test; metatile maps reduce their event ID to a Boolean here.
kitaqgb/lib/map.c:87
u8 map_trigger_at(u8 x, u8 y)
{
u16 index;
u8 value;
if (map_meta_loaded != 0) return (u8)(map_get_event(x, y) != 0);
if (map_loaded == 0) return 0;
if (x >= map_current.width || y >= map_current.height) return 0;
if (map_current.events == 0) return 0;
index = __map_index(x, y, map_current.width);
value = __farpeek8(map_bank, ((const u8*)map_current.events) + index);
return (u8)((value != 0) ? 1 : 0);
}path_find_bfs
尋找上下左右移動的最短路徑,並依起點至終點順序寫入方向。
語法
u8 path_find_bfs(u8 sx, u8 sy, u8 gx, u8 gy, u8* out_path, u8 max_len);參數
sx地圖內起始格子的 X 座標。
sy起始格子的 Y 座標。
gx目標格子的 X;若目標受阻且不等於起點,會被拒絕。
gy目標格子的 Y。
out_path至少 max_len 位元組的可寫入陣列;0=上、1=右、2=下、3=左。
max_len輸出容量;路徑過長時會失敗,不會截斷路徑。
回傳值
傳回路徑長度;零表示無法到達、座標無效、max_len 不足,或已位於目標。
使用條件與限制
座標指向目前地圖中的格子:一般圖塊為 8×8 像素,複合圖塊為 16×16 像素。
搜尋使用約 4 KiB 的共用工作區,且不可重入。地圖最多 1024 格,探索距離最多 254。距離 0xFF 表示未到達,因此無法表示 255 步的路徑。成本/遮罩輸出需要 width*height 個可寫入位元組。
max_len 限制輸出長度,不限制搜尋半徑。失敗後不可將輸出當作新路徑使用。
使用範例
result[49]=path_find_bfs(0,2,5,2,route,30);x=0;y=2;for(i=0;i<result[49];i++){if(route[i]==0)y--;if(route[i]==1)x++;if(route[i]==2)y++;if(route[i]==3)x--;}result[50]=x;result[51]=y;result[52]=path_find_bfs(0,2,5,2,route,2);result[53]=path_find_bfs(0,2,2,2,route,30);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側格線顯示三步內的移動成本,右側顯示從 S 到 G 的最短路徑。綠色星號標出繞過紅色三格牆的九步路徑,藍色數字表示成本。DMG 使用相同配置但以黑色顯示。RAM 檢查也示範攻擊遮罩會忽略牆壁。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_map_path.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_map_path.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/rpg.h:361
Find a shortest cardinal path with BFS and write direction codes 0=up, 1=right, 2=down, 3=left. Return its byte length, or zero for failure or an already-reached goal. The caller supplies max_len output bytes and respects the shared workspace/distance limits; excessive paths are not truncated.
kitaqgb/lib/slg_path.c:78
u8 path_find_bfs(u8 sx, u8 sy, u8 gx, u8 gy, u8* out_path, u8 max_len)
{
u8 w = map_current_width();
u8 h = map_current_height();
u16 total;
u16 head = 0;
u16 tail = 0;
u16 start;
u16 goal;
u8 found = 0;
if (w == 0 || h == 0) return 0;
if (sx >= w || sy >= h || gx >= w || gy >= h) return 0;
if ((sx != gx || sy != gy) && map_is_blocked(gx, gy) != 0) return 0;
total = (u16)((u16)w * (u16)h);
__memset(path_dist, 0xFF, total);
start = __map_index(sx, sy, w);
goal = __map_index(gx, gy, w);
path_dist[start] = 0;
path_queue[tail++] = start;
while (head < tail) {
u16 cur = path_queue[head++];
u8 cost = path_dist[cur];
u8 y = (u8)(cur / w);
u8 x = (u8)(cur - ((u16)y * (u16)w));
if (cur == goal) {
found = 1;
break;
}
if (y > 0) {
u16 next = (u16)(cur - w);
if (path_dist[next] == 0xFF && map_is_blocked(x, (u8)(y - 1)) == 0) {
path_dist[next] = (u8)(cost + 1);
path_queue[tail++] = next;
}
}
if ((u8)(x + 1) < w) {
u16 next = (u16)(cur + 1);
if (path_dist[next] == 0xFF && map_is_blocked((u8)(x + 1), y) == 0) {
path_dist[next] = (u8)(cost + 1);
path_queue[tail++] = next;
}
}
if ((u8)(y + 1) < h) {
u16 next = (u16)(cur + w);
if (path_dist[next] == 0xFF && map_is_blocked(x, (u8)(y + 1)) == 0) {
path_dist[next] = (u8)(cost + 1);
path_queue[tail++] = next;
}
}
if (x > 0) {
u16 next = (u16)(cur - 1);
if (path_dist[next] == 0xFF && map_is_blocked((u8)(x - 1), y) == 0) {
path_dist[next] = (u8)(cost + 1);
path_queue[tail++] = next;
}
}
}
// Reject unreachable or oversized paths before reconstructing output.
if (found == 0) return 0;
if (path_dist[goal] > max_len) return 0;
{
// Walk backward through decreasing costs, recording forward directions in
// reverse order. The fixed neighbor order makes tied routes deterministic.
u8 len = 0;
u16 cur = goal;
while (cur != start) {
u8 cur_cost = path_dist[cur];
u8 y = (u8)(cur / w);
u8 x = (u8)(cur - ((u16)y * (u16)w));
if (y > 0 && path_dist[(u16)(cur - w)] == (u8)(cur_cost - 1)) {
path_rev[len++] = 2;
cur = (u16)(cur - w);
continue;
}
if ((u8)(x + 1) < w && path_dist[(u16)(cur + 1)] == (u8)(cur_cost - 1)) {
path_rev[len++] = 3;
cur = (u16)(cur + 1);
continue;
}
if ((u8)(y + 1) < h && path_dist[(u16)(cur + w)] == (u8)(cur_cost - 1)) {
path_rev[len++] = 0;
cur = (u16)(cur + w);
continue;
}
if (x > 0 && path_dist[(u16)(cur - 1)] == (u8)(cur_cost - 1)) {
path_rev[len++] = 1;
cur = (u16)(cur - 1);
continue;
}
return 0;
}
// Reverse the recovered directions so the first output step starts at the origin.
while (len != 0) {
len--;
out_path[path_dist[goal] - 1 - len] = path_rev[len];
}
return path_dist[goal];
}
}quest_set_state
取代一個任務的整個狀態位元組。各值的意義由遊戲定義,例如 1 代表已接受、3 代表已完成。函式不會檢查此轉換是否允許,也不會觸發獎勵或回呼。
語法
void quest_set_state(u8 quest_id, u8 state);參數
quest_id任務編號 0~63,以 u8 傳入。直接索引 64 個狀態位元組之一;這是遊戲定義的 ID,不是指標或已完成任務數。
state新的 u8 狀態值,範圍為 0~255。全部八個位元取代原值。函式庫未內建各值的意義,也不保留 0 或 255。
回傳值
無(void)。
使用條件與限制
函式不會驗證 ID。旗標 ID 須小於 2048,任務 ID 須小於 64;超出範圍可能讀取或覆寫無關 RAM。範例明確初始化,不依賴啟動時的內容。
flags.c 在 RAM 中擁有 256 位元組旗標儲存區及獨立的 64 位元組任務儲存區。這些函式不存取卡匣存檔 RAM,資料也不會在關機後保留。若要保存進度,遊戲須透過存檔系統序列化旗標與任務值,並於載入時還原。
請包含 rpg.h,並將 lib/flags.c 與遊戲一同編譯。陣列僅供該原始檔內部使用,請透過旗標/任務 API 存取。所有呼叫端共用儲存空間,因此須自行協調主迴圈與中斷處理常式的寫入。
使用範例
quest_set_state(2,1); // In this game, 1 means accepted.
started=quest_state(2);
quest_set_state(2,3); // In this game, 3 means completed; replace the whole byte.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例先為任務 2 儲存 1,再以 3 覆寫。ACCEPTED 顯示第一次觀察值 001,COMPLETED 顯示取代後的 003。在最後有效項目任務 ID 63 儲存 255 後,LAST QUEST 為 255。
完整程式在白底上顯示十進位結果:DMG 為黑字,CGB 為藍字。FAILED 必須為 000。擷取畫面只呈現 RAM 狀態行為,並非遊戲存檔示範。
DMG 模擬器驗證涵蓋旗標 ID 0~2047 全部、重複設定/清除、相鄰項目,以及 64 個任務各自的全部 256 種狀態值。最後將 256 位元組旗標圖樣及 64 個任務位元組與預期資料比較。兩個教學畫面皆於 240 影格後檢查。未測試實機或存檔持久性。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\flags_quests.c .\kitaqgb\lib\flags.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\flags_quests.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:377
Replace a quest-state byte without validating its game-specific meaning. The caller must keep quest_id below 64.
kitaqgb/lib/flags.c:34
void quest_set_state(u8 quest_id, u8 state)
{
quest_states[quest_id] = state;
}quest_state
讀取一個任務儲存的位元組。與單位元旗標不同,任務位元組可區分尚未開始、已接受、已完成等多個階段。函式只讀取儲存值,不執行任務邏輯或推進階段。
語法
u8 quest_state(u8 quest_id);參數
quest_id任務編號 0~63,以 u8 傳入。直接索引 64 個狀態位元組之一;這是遊戲定義的 ID,不是指標或已完成任務數。
回傳值
儲存的 u8 值,範圍為 0~255。這是完整狀態位元組,不是正規化布林值;請與遊戲定義的階段值比較。
使用條件與限制
函式不會驗證 ID。旗標 ID 須小於 2048,任務 ID 須小於 64;超出範圍可能讀取或覆寫無關 RAM。範例明確初始化,不依賴啟動時的內容。
flags.c 在 RAM 中擁有 256 位元組旗標儲存區及獨立的 64 位元組任務儲存區。這些函式不存取卡匣存檔 RAM,資料也不會在關機後保留。若要保存進度,遊戲須透過存檔系統序列化旗標與任務值,並於載入時還原。
請包含 rpg.h,並將 lib/flags.c 與遊戲一同編譯。陣列僅供該原始檔內部使用,請透過旗標/任務 API 存取。所有呼叫端共用儲存空間,因此須自行協調主迴圈與中斷處理常式的寫入。
使用範例
finished=quest_state(2); // Read back 3 without advancing any quest logic.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例在遊戲明確將任務 2 的狀態從 1 改為 3 後讀取。ACCEPTED 顯示 001,COMPLETED 顯示 003。名稱與階段意義由範例選定,並非函式庫強制規定。
完整程式在白底上顯示十進位結果:DMG 為黑字,CGB 為藍字。FAILED 必須為 000。擷取畫面只呈現 RAM 狀態行為,並非遊戲存檔示範。
DMG 模擬器驗證涵蓋旗標 ID 0~2047 全部、重複設定/清除、相鄰項目,以及 64 個任務各自的全部 256 種狀態值。最後將 256 位元組旗標圖樣及 64 個任務位元組與預期資料比較。兩個教學畫面皆於 240 影格後檢查。未測試實機或存檔持久性。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\flags_quests.c .\kitaqgb\lib\flags.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\flags_quests.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:374
Read a quest-state byte; quest_id must be below 64.
kitaqgb/lib/flags.c:27
u8 quest_state(u8 quest_id)
{
return quest_states[quest_id];
}rand_range
以 rng8() % max 選出從零開始、小於 max 的值。例如上限 10 可得到 0 至 9 的索引。上限為零時立即傳回零,不取值。
語法
u8 rand_range(u8 max);參數
max不含端點的上限,型別 u8(0–255)。max > 0 時結果小於 max。此參數無法表示 256;若要完整位元組範圍且不取餘數,請用 rng8。
回傳值
max > 0 時,取值一次後傳回 0 至 max−1 的 u8。max == 0 時不取值,直接傳回零。即使 max == 1 的結果永遠為零,仍會消耗一次取值。
使用條件與限制
輸入範圍無法被上限整除時,取餘數可能偏向部分結果。底層產生器也未必均勻。請將有界結果與機率門檻視為遊戲用近似,而非精確機率。
這些呼叫共用持續保留的狀態。重現需要相同平台、種子與呼叫順序,包括其他輔助函式發出的呼叫。請在同一執行環境中設定種子與取值;這些檢查未證明從中斷處理常式並行使用的安全性。
GB 與 FC 使用不同演算法,不保證相同種子產生相同序列。它們是確定性的遊戲用產生器,不是密碼學亂數來源;測試檢查實作行為,不檢查統計品質或週期。
使用函式庫函式時,請引入 rpg.h,並隨遊戲編譯 lib/rng.c。__rng_seed 與 __rng8 內建函式由編譯器產生;只使用這兩者的程式不需要 rng.c 目的檔。
使用範例
rng_seed(0x1234);
bounded=rand_range(10); // An index from 0 through 9; this seed yields 2.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例選擇小於 10 的索引。種子 0x1234 的第一個位元組為 2,因此 RANGE 10 顯示 00002。ZERO BOUND 為 00000,接下來 NEXT BYTE 仍為 00002,確認零上限呼叫沒有取值。
完整程式在白底上顯示十進位結果:DMG 為黑字,CGB 為藍字。FAILED 必須為 00000。圖片為此範例實際的模擬器輸出。
驗證將每個案例的 32 個輸出與後續 8 次位元組取值,和獨立主機模型比對:GB 93 例、FC 18 例,涵蓋常數/執行期種子及 GB 範圍、機率、權重邊界。教學畫面在模擬器 240 影格後檢查。未測試實機與統計品質。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\rng_choices.c .\kitaqgb\lib\rng.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\rng_choices.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:199
Reduce a random byte modulo max; zero returns zero without consuming randomness. Modulo reduction is biased unless max divides the generator range.
kitaqgb/lib/rng.c:37
u8 rand_range(u8 max)
{
if (max == 0) return 0;
return (u8)(rng8() % max);
}range_fill_move
以每步成本一對上下左右相鄰格進行廣度優先搜尋,建立移動成本。
語法
void range_fill_move(u8 sx, u8 sy, u8 move, u8* out_costmap);參數
sx地圖內起始格子的 X 座標。
sy起始格子的 Y 座標。
move移動上限為 0..254;零表示僅到達起點。
out_costmap可寫入的 width*height 成本陣列:255 表示未到達,起點為零。
回傳值
無傳回值。
使用條件與限制
座標指向目前地圖中的格子:一般圖塊為 8×8 像素,複合圖塊為 16×16 像素。
搜尋使用約 4 KiB 的共用工作區,且不可重入。地圖最多 1024 格,探索距離最多 254。距離 0xFF 表示未到達,因此無法表示 255 步的路徑。成本/遮罩輸出需要 width*height 個可寫入位元組。
沒有地圖或起點無效時,輸出維持不變。不會進入受阻的目的格子。
使用範例
range_fill_move(0,2,3,costs);for(i=0;i<30;i++)result[13+i]=costs[i];這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側格線顯示三步內的移動成本,右側顯示從 S 到 G 的最短路徑。綠色星號標出繞過紅色三格牆的九步路徑,藍色數字表示成本。DMG 使用相同配置但以黑色顯示。RAM 檢查也示範攻擊遮罩會忽略牆壁。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_map_path.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_map_path.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/rpg.h:365
Flood cardinal neighbors at unit cost, stopping expansion at the movement limit and rejecting blocked destinations. Initialize output to 0xFF only after validating the map and origin; invalid input leaves output unchanged.
kitaqgb/lib/slg_path.c:14
void range_fill_move(u8 sx, u8 sy, u8 move, u8* out_costmap)
{
u8 w = map_current_width();
u8 h = map_current_height();
u16 total;
u16 head = 0;
u16 tail = 0;
u16 start;
if (w == 0 || h == 0) return;
if (sx >= w || sy >= h) return;
total = (u16)((u16)w * (u16)h);
__memset(out_costmap, 0xFF, total);
start = __map_index(sx, sy, w);
out_costmap[start] = 0;
path_queue[tail++] = start;
while (head < tail) {
u16 cur = path_queue[head++];
u8 cost = out_costmap[cur];
u8 y = (u8)(cur / w);
u8 x = (u8)(cur - ((u16)y * (u16)w));
if (cost >= move) continue;
if (y > 0) {
u16 next = (u16)(cur - w);
if (out_costmap[next] == 0xFF && map_is_blocked(x, (u8)(y - 1)) == 0) {
out_costmap[next] = (u8)(cost + 1);
path_queue[tail++] = next;
}
}
if ((u8)(x + 1) < w) {
u16 next = (u16)(cur + 1);
if (out_costmap[next] == 0xFF && map_is_blocked((u8)(x + 1), y) == 0) {
out_costmap[next] = (u8)(cost + 1);
path_queue[tail++] = next;
}
}
if ((u8)(y + 1) < h) {
u16 next = (u16)(cur + w);
if (out_costmap[next] == 0xFF && map_is_blocked(x, (u8)(y + 1)) == 0) {
out_costmap[next] = (u8)(cost + 1);
path_queue[tail++] = next;
}
}
if (x > 0) {
u16 next = (u16)(cur - 1);
if (out_costmap[next] == 0xFF && map_is_blocked((u8)(x - 1), y) == 0) {
out_costmap[next] = (u8)(cost + 1);
path_queue[tail++] = next;
}
}
}
}rle_decode
將行程長度編碼的位元組串流解壓至一般可寫入 RAM。每個 count/value 配對將一個位元組重複 count 次;count 為零表示串流結束。壓縮資料可由一般指標讀取,且希望上傳前檢查或修改解壓資料時,可使用此方式。
語法
u16 rle_decode(void* dst, const void* src);參數
dst指向足以容納整個解壓串流的可寫入 RAM。函式不接收容量參數。輸出須與編碼來源分開,避免覆寫尚未讀取的配對。
src可讀指標,指向以零 count 結尾的 count/value 位元組配對。一般重複的 count 為 1–255,value 可為包含零在內的任何位元組。結尾的零後面沒有 value 位元組。整個呼叫期間,該指標在目前映射下都必須可讀。
回傳值
以 u16 傳回已寫入位元組數。一開始就是零 count 時,不輸出任何資料並傳回 0。終止符不會複製。解壓長度須能以 u16 表示;回傳值沒有獨立錯誤碼,也不是圖塊數。
使用條件與限制
此編碼以位元組為單位,不是文字。例如 {3, 0x12, 2, 0xA5, 0} 會解壓為五個位元組:12 12 12 A5 A5。此輸出列以十六進位表示。count 非零的配對中,value 為零仍是一般資料,不是結束標記。
沒有編碼大小、輸出容量或畸形資料處理參數。請在建立或載入資產時驗證,提供結尾零,並在解碼前計算解壓大小。無效或未終止的串流可能讀出來源範圍,並寫出目的範圍。
RAM 解碼器使用一般寫入,不與 LCD 存取時段同步,目的地應保持在 RAM。若要顯示結果,請使用適當的 VRAM 複製 API 另行上傳;範例是在 LCD 停止時上傳。
指定記憶體庫的讀取進行中,中斷常式不可改變 ROM 映射或重用遠端複製輔助函式,因為這些函式共用記憶體庫管理狀態。一般指標解碼器與來源須放在相容映射中;切換至函式的記憶體庫時,不得使一般來源指標失去可讀性。
rle_decode 與 rle_decode_far 宣告於 rpg.h,實作於 lib/rle.c。請隨遊戲編譯該實作一次。完整範例在 #pragma bank 0 之後引入 rle.c,讓呼叫端與解碼器留在共用記憶體庫;此範例不可再將 rle.c 作為獨立輸入。__rle_decode_vram 內建函式本身不需要函式庫實作檔。
使用範例
near_count=rle_decode(near_buffer+1,local_rle); // 48 bytes in writable RAM.
__vram_copy(0x8800,near_buffer+1,near_count); // Upload those bytes while the LCD is off.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例將 9 個編碼位元組解壓至帶保護區的 RAM 緩衝區,再將 48 位元組結果複製至圖塊資料位址 0x8800。RLE TO RAM 顯示 048。最上列在 CGB 上為紅色,展示經一般指標路徑解壓的三個圖塊。
每列由左至右為填滿的 8×8 正方形、邊框厚一像素的 8×8 方框,以及占 8×8 圖塊左半部的實心 4×8 矩形。圖塊欄為 2、5、8(像素 x = 16、40、64);三列起始像素 y 為 32、72、112。DMG 圖形為黑色;CGB 各列依序為紅、綠、藍。FAILED 必須為 000。數字代表位元組數:三個各 16 位元組的 GB 圖塊需要解壓 48 位元組。
驗證矩陣包含 42 個案例:空串流、單位元組重複、零值資料、255 位元組重複、跨目的分頁的 510 位元組輸出,以及跨來源分頁的編碼資料。比對全部 528 個觀察到的目的/保護位元組、輸出長度及還原的 ROM 映射。直接 VRAM 案例涵蓋 DMG、CGB 的 LCD 開/關,以及 CGB VBK 1。兩個教學畫面在模擬器執行 240 影格後檢查。不涵蓋無效資產、並行中斷使用或實體硬體。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\rle_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\rle_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:382
Expand count/value byte pairs until a zero count terminates the stream. The caller must provide a valid terminator and sufficient destination storage; there are no source or destination bounds parameters. Return the 16-bit byte count.
kitaqgb/lib/rle.c:8
u16 rle_decode(void* dst, const void* src)
{
const u8* in = (const u8*)src;
u8* out = (u8*)dst;
u16 total = 0;
while (1) {
u8 count = *in++;
u8 value;
if (count == 0) break;
value = *in++;
while (count != 0) {
*out++ = value;
total++;
count--;
}
}
return total;
}rle_decode_far
將相同的 count/value 格式解壓至 RAM,但透過 __farpeek8 從指定 ROM 記憶體庫逐一讀取編碼位元組。適用於存放在可切換 ROM 記憶體庫的壓縮資產。目的地仍是一般 RAM 指標;bank 引數描述來源。
語法
u16 rle_decode_far(void* dst, u8 bank, const void* src);參數
dst指向足以容納整個解壓串流的可寫入 RAM。函式不接收容量參數。輸出須與編碼來源分開,避免覆寫尚未讀取的配對。
bank來源 ROM 記憶體庫編號,型別為 u8。記憶體庫與 CPU 位址須符合卡匣映射器及資產位置。每次讀取編碼位元組後都會還原記憶體庫選擇。它不是目的 VRAM 記憶體庫選擇,也無法表示 9 位元 MBC5 記憶體庫編號。
src指向指定記憶體庫內編碼串流的 CPU 指標。函式會遞增位址,但記憶體庫編號固定。包含結尾零在內的完整串流須位於可讀映射中;越過 0x7FFF 不會自動接續到下一個 ROM 記憶體庫。
回傳值
以 u16 傳回已寫入位元組數。一開始就是零 count 時,不輸出任何資料並傳回 0。終止符不會複製。解壓長度須能以 u16 表示;回傳值沒有獨立錯誤碼,也不是圖塊數。
使用條件與限制
此編碼以位元組為單位,不是文字。例如 {3, 0x12, 2, 0xA5, 0} 會解壓為五個位元組:12 12 12 A5 A5。此輸出列以十六進位表示。count 非零的配對中,value 為零仍是一般資料,不是結束標記。
沒有編碼大小、輸出容量或畸形資料處理參數。請在建立或載入資產時驗證,提供結尾零,並在解碼前計算解壓大小。無效或未終止的串流可能讀出來源範圍,並寫出目的範圍。
RAM 解碼器使用一般寫入,不與 LCD 存取時段同步,目的地應保持在 RAM。若要顯示結果,請使用適當的 VRAM 複製 API 另行上傳;範例是在 LCD 停止時上傳。
指定記憶體庫的讀取進行中,中斷常式不可改變 ROM 映射或重用遠端複製輔助函式,因為這些函式共用記憶體庫管理狀態。一般指標解碼器與來源須放在相容映射中;切換至函式的記憶體庫時,不得使一般來源指標失去可讀性。
rle_decode 與 rle_decode_far 宣告於 rpg.h,實作於 lib/rle.c。請隨遊戲編譯該實作一次。完整範例在 #pragma bank 0 之後引入 rle.c,讓呼叫端與解碼器留在共用記憶體庫;此範例不可再將 rle.c 作為獨立輸入。__rle_decode_vram 內建函式本身不需要函式庫實作檔。
使用範例
far_count=rle_decode_far(far_buffer+1,2,banked_rle); // Read encoded pairs from ROM bank 2.
if(*rle_bank_marker!=0xA1)failures++; // ROM bank 1 must be visible again.
__vram_copy(0x8830,far_buffer+1,far_count);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例從 ROM 記憶體庫 2 讀取編碼串流,解壓 48 位元組至 RAM,再上傳至 0x8830。BANKED RAM 顯示 048。中間列在 CGB 上為綠色。也會檢查 ROM 記憶體庫 1 的標記,確認呼叫端映射已還原。
每列由左至右為填滿的 8×8 正方形、邊框厚一像素的 8×8 方框,以及占 8×8 圖塊左半部的實心 4×8 矩形。圖塊欄為 2、5、8(像素 x = 16、40、64);三列起始像素 y 為 32、72、112。DMG 圖形為黑色;CGB 各列依序為紅、綠、藍。FAILED 必須為 000。數字代表位元組數:三個各 16 位元組的 GB 圖塊需要解壓 48 位元組。
驗證矩陣包含 42 個案例:空串流、單位元組重複、零值資料、255 位元組重複、跨目的分頁的 510 位元組輸出,以及跨來源分頁的編碼資料。比對全部 528 個觀察到的目的/保護位元組、輸出長度及還原的 ROM 映射。直接 VRAM 案例涵蓋 DMG、CGB 的 LCD 開/關,以及 CGB VBK 1。兩個教學畫面在模擬器執行 240 影格後檢查。不涵蓋無效資產、並行中斷使用或實體硬體。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\rle_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\rle_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:386
Decode the same count/value format using bank-qualified reads for every source byte. Keep the encoded stream within the supplied bank/address mapping and provide enough destination space; a zero count ends the stream.
kitaqgb/lib/rle.c:34
u16 rle_decode_far(void* dst, u8 bank, const void* src)
{
const u8* p = (const u8*)src;
u8* out = (u8*)dst;
u16 total = 0;
while (1) {
u8 count = __farpeek8(bank, p);
u8 value;
p++;
if (count == 0) break;
value = __farpeek8(bank, p);
p++;
while (count != 0) {
*out++ = value;
total++;
count--;
}
}
return total;
}rng16
以連續兩次 rng8 取值組成無號 16 位元值。第一個位元組放在位元 15–8,第二個放在 7–0。需要的數值範圍超過一個位元組時使用。
語法
u16 rng16();回傳值
以 (first_byte << 8) | second_byte 組成的 u16 結果(0–65535)。恰好消耗兩次位元組取值;這不代表全部 65536 個值均勻分布。
使用條件與限制
這些呼叫共用持續保留的狀態。重現需要相同平台、種子與呼叫順序,包括其他輔助函式發出的呼叫。請在同一執行環境中設定種子與取值;這些檢查未證明從中斷處理常式並行使用的安全性。
GB 與 FC 使用不同演算法,不保證相同種子產生相同序列。它們是確定性的遊戲用產生器,不是密碼學亂數來源;測試檢查實作行為,不檢查統計品質或週期。
使用函式庫函式時,請引入 rpg.h,並隨遊戲編譯 lib/rng.c。__rng_seed 與 __rng8 內建函式由編譯器產生;只使用這兩者的程式不需要 rng.c 目的檔。
使用範例
rng_seed(0x1234);
word=rng16(); // First draw 2 is high, second draw 34 is low: 0x0222 = 546.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例展示字組組合。重新設定種子 0x1234 後,位元組 2 與 34 組成 0x0222,因此 RNG16 顯示 00546。FIRST 與 SECOND 分別顯示對應位元組值。
完整程式在白底上顯示十進位結果:DMG 為黑字,CGB 為藍字。FAILED 必須為 00000。圖片為此範例實際的模擬器輸出。
驗證將每個案例的 32 個輸出與後續 8 次位元組取值,和獨立主機模型比對:GB 93 例、FC 18 例,涵蓋常數/執行期種子及 GB 範圍、機率、權重邊界。教學畫面在模擬器 240 影格後檢查。未測試實機與統計品質。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\rng_values.c .\kitaqgb\lib\rng.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\rng_values.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:196
Consume two generator bytes in high-byte/low-byte order to form a 16-bit value.
kitaqgb/lib/rng.c:22
u16 rng16()
{
u16 hi = (u16)rng8();
u16 lo = (u16)rng8();
return (u16)((hi << 8) | lo);
}rng8
透過 GB 函式庫取得一個偽亂數位元組。rng8 恰好呼叫 __rng8 一次,是 rng.c 其他輔助函式使用的基本取值操作。
語法
u8 rng8();回傳值
共用產生器推進一次後的 u8 結果(0–255)。這描述值的型別與範圍,不代表每個位元組等機率。
使用條件與限制
這些呼叫共用持續保留的狀態。重現需要相同平台、種子與呼叫順序,包括其他輔助函式發出的呼叫。請在同一執行環境中設定種子與取值;這些檢查未證明從中斷處理常式並行使用的安全性。
GB 與 FC 使用不同演算法,不保證相同種子產生相同序列。它們是確定性的遊戲用產生器,不是密碼學亂數來源;測試檢查實作行為,不檢查統計品質或週期。
使用函式庫函式時,請引入 rpg.h,並隨遊戲編譯 lib/rng.c。__rng_seed 與 __rng8 內建函式由編譯器產生;只使用這兩者的程式不需要 rng.c 目的檔。
使用範例
rng_seed(0x1234); // Reset the same generator used by the intrinsics.
wrapped=rng8(); // One byte draw: 2 after the preceding seed.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例比較函式庫與內建函式的位元組取值。rng_seed(0x1234) 之後,RNG8 顯示 00002,與 FIRST 相同。設定種子不會消耗第一次取值。
完整程式在白底上顯示十進位結果:DMG 為黑字,CGB 為藍字。FAILED 必須為 00000。圖片為此範例實際的模擬器輸出。
驗證將每個案例的 32 個輸出與後續 8 次位元組取值,和獨立主機模型比對:GB 93 例、FC 18 例,涵蓋常數/執行期種子及 GB 範圍、機率、權重邊界。教學畫面在模擬器 240 影格後檢查。未測試實機與統計品質。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\rng_values.c .\kitaqgb\lib\rng.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\rng_values.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:194
Advance the compiler-provided pseudorandom generator and return one byte.
kitaqgb/lib/rng.c:4
u8 rng8()
{
return __rng8();
}rng_chance
使用 rng_range(100) < percent 作是/否選擇,適合敵人是否掉落物品等近似遊戲機率。零永遠為假,100 以上永遠為真;這兩個端點情況都不消耗取值。
語法
u8 rng_chance(u8 percent);參數
percent以 u8 表示的期望機率。1–99 使用一次經取餘數的位元組;0 傳回假,100–255 傳回真。中間值只是近似門檻,不保證精確百分比。
回傳值
正規化布林值:假為 0,真為 1。門檻 1 至 99 的呼叫消耗一次位元組取值。
使用條件與限制
輸入範圍無法被上限整除時,取餘數可能偏向部分結果。底層產生器也未必均勻。請將有界結果與機率門檻視為遊戲用近似,而非精確機率。
這些呼叫共用持續保留的狀態。重現需要相同平台、種子與呼叫順序,包括其他輔助函式發出的呼叫。請在同一執行環境中設定種子與取值;這些檢查未證明從中斷處理常式並行使用的安全性。
GB 與 FC 使用不同演算法,不保證相同種子產生相同序列。它們是確定性的遊戲用產生器,不是密碼學亂數來源;測試檢查實作行為,不檢查統計品質或週期。
使用函式庫函式時,請引入 rpg.h,並隨遊戲編譯 lib/rng.c。__rng_seed 與 __rng8 內建函式由編譯器產生;只使用這兩者的程式不需要 rng.c 目的檔。
使用範例
rng_seed(0x1234);
chance=rng_chance(50); // Here 2 % 100 < 50, so the result is 1 (true).這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例執行一次近似 50% 判定。種子產生的位元組為 2,且 2 % 100 < 50 為真,因此 CHANCE 50 顯示 00001。一次成功取值不能證明長期成功率為 50%。
完整程式在白底上顯示十進位結果:DMG 為黑字,CGB 為藍字。FAILED 必須為 00000。圖片為此範例實際的模擬器輸出。
驗證將每個案例的 32 個輸出與後續 8 次位元組取值,和獨立主機模型比對:GB 93 例、FC 18 例,涵蓋常數/執行期種子及 GB 範圍、機率、權重邊界。教學畫面在模擬器 240 影格後檢查。未測試實機與統計品質。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\rng_choices.c .\kitaqgb\lib\rng.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\rng_choices.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:214
Return false for zero and true for values at least 100. Intermediate values use the modulo-based range generator, so percentages are approximate.
kitaqgb/lib/rng.c:51
u8 rng_chance(u8 percent)
{
if (percent == 0) return 0;
if (percent >= 100) return 1;
return (u8)(rng_range(100) < percent);
}rng_next16
傳回與 rng16 相同、由兩次取值組成的字組。這是函式庫別名,第一次取值為高位元組,第二次為低位元組;取值前不會額外跳過一個值。
語法
u16 rng_next16();回傳值
以 (first_byte << 8) | second_byte 組成的 u16 結果(0–65535)。恰好消耗兩次位元組取值;這不代表全部 65536 個值均勻分布。
使用條件與限制
這些呼叫共用持續保留的狀態。重現需要相同平台、種子與呼叫順序,包括其他輔助函式發出的呼叫。請在同一執行環境中設定種子與取值;這些檢查未證明從中斷處理常式並行使用的安全性。
GB 與 FC 使用不同演算法,不保證相同種子產生相同序列。它們是確定性的遊戲用產生器,不是密碼學亂數來源;測試檢查實作行為,不檢查統計品質或週期。
使用函式庫函式時,請引入 rpg.h,並隨遊戲編譯 lib/rng.c。__rng_seed 與 __rng8 內建函式由編譯器產生;只使用這兩者的程式不需要 rng.c 目的檔。
使用範例
rng_seed(0x1234);
nextword=rng_next16(); // The same two-draw word: 546.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例在相同種子後比較字組別名與 rng16。NEXT16 與 RNG16 皆顯示 00546,代表依高/低順序組合的兩次位元組取值。
完整程式在白底上顯示十進位結果:DMG 為黑字,CGB 為藍字。FAILED 必須為 00000。圖片為此範例實際的模擬器輸出。
驗證將每個案例的 32 個輸出與後續 8 次位元組取值,和獨立主機模型比對:GB 93 例、FC 18 例,涵蓋常數/執行期種子及 GB 範圍、機率、權重邊界。教學畫面在模擬器 240 影格後檢查。未測試實機與統計品質。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\rng_values.c .\kitaqgb\lib\rng.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\rng_values.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:209
Alias the two-step 16-bit generator.
kitaqgb/lib/rng.c:30
u16 rng_next16()
{
return rng16();
}rng_next8
使用與 rng8 相同的操作取出下一個位元組。名稱強調推進序列;依序呼叫兩個名稱,會從同一共用產生器消耗連續兩次取值。
語法
u8 rng_next8();回傳值
共用產生器推進一次後的 u8 結果(0–255)。這描述值的型別與範圍,不代表每個位元組等機率。
使用條件與限制
這些呼叫共用持續保留的狀態。重現需要相同平台、種子與呼叫順序,包括其他輔助函式發出的呼叫。請在同一執行環境中設定種子與取值;這些檢查未證明從中斷處理常式並行使用的安全性。
GB 與 FC 使用不同演算法,不保證相同種子產生相同序列。它們是確定性的遊戲用產生器,不是密碼學亂數來源;測試檢查實作行為,不檢查統計品質或週期。
使用函式庫函式時,請引入 rpg.h,並隨遊戲編譯 lib/rng.c。__rng_seed 與 __rng8 內建函式由編譯器產生;只使用這兩者的程式不需要 rng.c 目的檔。
使用範例
rng_seed(0x1234);
nextbyte=rng_next8(); // One draw, just like rng8(): 2.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例在相同種子下檢查位元組別名。程式在每次比較前重新設定種子,因此 NEXT8 與 RNG8 皆顯示 00002;沒有這些重設時,兩者會消耗連續取值。
完整程式在白底上顯示十進位結果:DMG 為黑字,CGB 為藍字。FAILED 必須為 00000。圖片為此範例實際的模擬器輸出。
驗證將每個案例的 32 個輸出與後續 8 次位元組取值,和獨立主機模型比對:GB 93 例、FC 18 例,涵蓋常數/執行期種子及 GB 範圍、機率、權重邊界。教學畫面在模擬器 240 影格後檢查。未測試實機與統計品質。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\rng_values.c .\kitaqgb\lib\rng.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\rng_values.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:207
Alias the byte generator; this consumes one generator step.
kitaqgb/lib/rng.c:16
u8 rng_next8()
{
return rng8();
}rng_range
以相同的不含端點上限呼叫 rand_range。此名稱將有界選擇歸入其他 rng_ 函式,使用相同的位元組取值與取餘數運算;上限為零時同樣不取值。
語法
u8 rng_range(u8 max);參數
max不含端點的上限,型別 u8(0–255)。max > 0 時結果小於 max。此參數無法表示 256;若要完整位元組範圍且不取餘數,請用 rng8。
回傳值
max > 0 時,取值一次後傳回 0 至 max−1 的 u8。max == 0 時不取值,直接傳回零。即使 max == 1 的結果永遠為零,仍會消耗一次取值。
使用條件與限制
輸入範圍無法被上限整除時,取餘數可能偏向部分結果。底層產生器也未必均勻。請將有界結果與機率門檻視為遊戲用近似,而非精確機率。
這些呼叫共用持續保留的狀態。重現需要相同平台、種子與呼叫順序,包括其他輔助函式發出的呼叫。請在同一執行環境中設定種子與取值;這些檢查未證明從中斷處理常式並行使用的安全性。
GB 與 FC 使用不同演算法,不保證相同種子產生相同序列。它們是確定性的遊戲用產生器,不是密碼學亂數來源;測試檢查實作行為,不檢查統計品質或週期。
使用函式庫函式時,請引入 rpg.h,並隨遊戲編譯 lib/rng.c。__rng_seed 與 __rng8 內建函式由編譯器產生;只使用這兩者的程式不需要 rng.c 目的檔。
使用範例
rng_seed(0x1234);
alias=rng_range(10); // The same exclusive upper bound and result, 2.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例比較有界選擇的兩種名稱。每次呼叫前重新設定種子,使 ALIAS 10 與 RANGE 10 皆顯示 00002。上限 10 本身不包含在結果內。
完整程式在白底上顯示十進位結果:DMG 為黑字,CGB 為藍字。FAILED 必須為 00000。圖片為此範例實際的模擬器輸出。
驗證將每個案例的 32 個輸出與後續 8 次位元組取值,和獨立主機模型比對:GB 93 例、FC 18 例,涵蓋常數/執行期種子及 GB 範圍、機率、權重邊界。教學畫面在模擬器 240 影格後檢查。未測試實機與統計品質。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\rng_choices.c .\kitaqgb\lib\rng.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\rng_choices.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:211
Alias rand_range and return a value in [0,max), or zero when max is zero.
kitaqgb/lib/rng.c:44
u8 rng_range(u8 max)
{
return rand_range(max);
}rng_seed
透過 GB 函式庫介面設定種子。這是 __rng_seed 的包裝函式,會重設 rng8、rng16 與選擇輔助函式使用的同一共用狀態,不會建立獨立產生器。
語法
void rng_seed(u16 seed);參數
seed無號 16 位元種子,範圍 0–65535。兩個位元組照原值儲存。請在要重現的遊戲取值序列開始前選好並記錄種子。
回傳值
無(void)。
使用條件與限制
接受零狀態。下一次取位元組時,GB 產生器會在推進前替換為 0x5AA5,因此 __rng_seed(0) 之後呼叫 __rng8() 會傳回 122。反覆設定種子會重啟序列,不會增加隨機性。
這些呼叫共用持續保留的狀態。重現需要相同平台、種子與呼叫順序,包括其他輔助函式發出的呼叫。請在同一執行環境中設定種子與取值;這些檢查未證明從中斷處理常式並行使用的安全性。
GB 與 FC 使用不同演算法,不保證相同種子產生相同序列。它們是確定性的遊戲用產生器,不是密碼學亂數來源;測試檢查實作行為,不檢查統計品質或週期。
使用函式庫函式時,請引入 rpg.h,並隨遊戲編譯 lib/rng.c。__rng_seed 與 __rng8 內建函式由編譯器產生;只使用這兩者的程式不需要 rng.c 目的檔。
使用範例
rng_seed(0x1234); // Reset the same generator used by the intrinsics.
wrapped=rng8(); // One byte draw: 2 after the preceding seed.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例比較函式庫與內建函式的位元組取值。rng_seed(0x1234) 之後,RNG8 顯示 00002,與 FIRST 相同。設定種子不會消耗第一次取值。
完整程式在白底上顯示十進位結果:DMG 為黑字,CGB 為藍字。FAILED 必須為 00000。圖片為此範例實際的模擬器輸出。
驗證將每個案例的 32 個輸出與後續 8 次位元組取值,和獨立主機模型比對:GB 93 例、FC 18 例,涵蓋常數/執行期種子及 GB 範圍、機率、權重邊界。教學畫面在模擬器 240 影格後檢查。未測試實機與統計品質。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\rng_values.c .\kitaqgb\lib\rng.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\rng_values.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:205
Replace the generator seed so subsequent calls can reproduce a sequence.
kitaqgb/lib/rng.c:10
void rng_seed(u16 seed)
{
__rng_seed(seed);
}save_check
執行與 save_exists 相同的完整性檢查,但不取出資料。
語法
u8 save_check(u8 slot);參數
slot插槽編號 0..3。
回傳值
有效時傳回 1,否則為 0。長度為零的存檔也可能有效。
使用條件與限制
預設為四個 512 位元組插槽,每個含六位元組標頭及最多 506 位元組資料。範例使用搭配 8 KiB SRAM 的 MBC5。呼叫結束時會停用 RAM,不還原先前的記憶體庫或啟用狀態。
使用範例
result[4]=save_check(0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
儲存 7/42/255 三個位元組,再測試長度不符、無效插槽及損壞的檢查碼。成功載入時中間位元組為 42;讀取失敗時目的值 77 維持不變;清除後驗證傳回 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_save.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_save.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=8k實作與原始碼
kitaqgb/lib/rpg.h:341
Alias save_exists, including its header and checksum validation.
kitaqgb/lib/save.c:175
u8 save_check(u8 slot)
{
return save_exists(slot);
}save_clear
將插槽全部 512 位元組歸零,使其存檔失效。
語法
void save_clear(u8 slot);參數
slot插槽編號 0..3。
回傳值
無傳回值。
使用條件與限制
預設為四個 512 位元組插槽,每個含六位元組標頭及最多 506 位元組資料。範例使用搭配 8 KiB SRAM 的 MBC5。呼叫結束時會停用 RAM,不還原先前的記憶體庫或啟用狀態。
忽略 0..3 以外的插槽,其他插槽保持不變。
使用範例
save_clear(0);result[16]=save_check(0);result[17]=save_write(3,payload,0);result[18]=save_exists(3);save_clear(3);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
儲存 7/42/255 三個位元組,再測試長度不符、無效插槽及損壞的檢查碼。成功載入時中間位元組為 42;讀取失敗時目的值 77 維持不變;清除後驗證傳回 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_save.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_save.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=8k實作與原始碼
kitaqgb/lib/rpg.h:344
Zero the complete selected slot, including header and payload; invalid slot IDs are ignored. Cartridge RAM is disabled when clearing finishes.
kitaqgb/lib/save.c:225
void save_clear(u8 slot)
{
u16 base;
u16 i;
if (slot >= SAVE_SLOT_COUNT) return;
base = save_slot_base(slot);
save_enable();
i = 0;
while (i < SAVE_SLOT_SIZE) {
save_write_abs((u16)(base + i), 0);
i++;
}
save_disable();
}save_exists
驗證插槽的標頭、長度及檢查碼,確認是否有可用的存檔。
語法
u8 save_exists(u8 slot);參數
slot插槽編號 0..3。
回傳值
有效時傳回 1,否則為 0。長度為零的存檔也可能有效。
使用條件與限制
預設為四個 512 位元組插槽,每個含六位元組標頭及最多 506 位元組資料。範例使用搭配 8 KiB SRAM 的 MBC5。呼叫結束時會停用 RAM,不還原先前的記憶體庫或啟用狀態。
使用範例
result[0]=save_exists(0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
儲存 7/42/255 三個位元組,再測試長度不符、無效插槽及損壞的檢查碼。成功載入時中間位元組為 42;讀取失敗時目的值 77 維持不變;清除後驗證傳回 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_save.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_save.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=8k實作與原始碼
kitaqgb/lib/rpg.h:334
Validate a slot's header, payload bounds and checksum without copying the payload out. A nonzero result means the stored record passes these checks.
kitaqgb/lib/save.c:182
u8 save_exists(u8 slot)
{
u16 base;
u16 stored_len;
u8 stored_sum;
if (slot >= SAVE_SLOT_COUNT) return 0;
base = save_slot_base(slot);
save_enable();
if (save_read_abs(base + 0) != SAVE_MAGIC0) {
save_disable();
return 0;
}
if (save_read_abs(base + 1) != SAVE_MAGIC1) {
save_disable();
return 0;
}
if (save_read_abs(base + 2) != SAVE_VERSION) {
save_disable();
return 0;
}
stored_len = (u16)save_read_abs(base + 3);
stored_len |= (u16)((u16)save_read_abs(base + 4) << 8);
stored_sum = save_read_abs(base + 5);
if (stored_len > (u16)(SAVE_SLOT_SIZE - SAVE_HEADER_SIZE)) {
save_disable();
return 0;
}
if (save_checksum_ram((u16)(base + SAVE_HEADER_SIZE), stored_len) != stored_sum) {
save_disable();
return 0;
}
save_disable();
return 1;
}save_init
選取 RAM 記憶體庫零,短暫啟用後再停用。
語法
void save_init();回傳值
無傳回值。
使用條件與限制
預設為四個 512 位元組插槽,每個含六位元組標頭及最多 506 位元組資料。範例使用搭配 8 KiB SRAM 的 MBC5。呼叫結束時會停用 RAM,不還原先前的記憶體庫或啟用狀態。
不會清除存檔、偵測卡匣硬體或格式化插槽。
使用範例
save_init();save_clear(0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
儲存 7/42/255 三個位元組,再測試長度不符、無效插槽及損壞的檢查碼。成功載入時中間位元組為 42;讀取失敗時目的值 77 維持不變;清除後驗證傳回 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_save.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_save.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=8k實作與原始碼
kitaqgb/lib/rpg.h:337
Initialize the expected RAM access state and leave cartridge RAM disabled. Existing slot contents are preserved.
kitaqgb/lib/save.c:70
void save_init()
{
save_enable();
save_disable();
}save_load
以與 save_read 相同的驗證方式載入儲存資料。
語法
u8 save_load(u8 slot, void* data, u16 len);參數
slot插槽編號 0..3。
data可寫入 len 個位元組的目的地。
len資料長度為 0..506 位元組;讀取時必須與儲存的長度完全一致。
回傳值
載入成功時傳回 1,否則為 0;要求長度必須與儲存長度一致。
使用條件與限制
預設為四個 512 位元組插槽,每個含六位元組標頭及最多 506 位元組資料。範例使用搭配 8 KiB SRAM 的 MBC5。呼叫結束時會停用 RAM,不還原先前的記憶體庫或啟用狀態。
八位元加總檢查碼無法偵測所有損壞。斷電時不保證寫入的原子性;僅收到成功結果,不能保證資料已實際持久保存。
使用範例
readback[1]=0;result[10]=save_load(0,readback,3);result[11]=readback[1];這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
儲存 7/42/255 三個位元組,再測試長度不符、無效插槽及損壞的檢查碼。成功載入時中間位元組為 42;讀取失敗時目的值 77 維持不變;清除後驗證傳回 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_save.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_save.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=8k實作與原始碼
kitaqgb/lib/rpg.h:339
Alias the checked save_read operation.
kitaqgb/lib/save.c:114
u8 save_load(u8 slot, void* data, u16 len)
{
return save_read(slot, data, len);
}save_read
驗證標頭、精確長度及檢查碼;只有驗證成功後才複製資料。
語法
u8 save_read(u8 slot, void* data, u16 len);參數
slot插槽編號 0..3。
data可寫入 len 個位元組的目的地。
len資料長度為 0..506 位元組;讀取時必須與儲存的長度完全一致。
回傳值
成功時傳回 1,驗證失敗時傳回 0;失敗不改變目的資料。
使用條件與限制
預設為四個 512 位元組插槽,每個含六位元組標頭及最多 506 位元組資料。範例使用搭配 8 KiB SRAM 的 MBC5。呼叫結束時會停用 RAM,不還原先前的記憶體庫或啟用狀態。
八位元加總檢查碼無法偵測所有損壞。斷電時不保證寫入的原子性;僅收到成功結果,不能保證資料已實際持久保存。
使用範例
readback[0]=99;result[5]=save_read(0,readback,2);result[6]=readback[0];result[7]=save_read(0,readback,3);result[8]=readback[0];result[9]=readback[2];這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
儲存 7/42/255 三個位元組,再測試長度不符、無效插槽及損壞的檢查碼。成功載入時中間位元組為 42;讀取失敗時目的值 77 維持不變;清除後驗證傳回 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_save.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_save.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=8k實作與原始碼
kitaqgb/lib/rpg.h:331
Require matching magic/version, exact requested length and a valid checksum before copying data into the destination. Validation failure leaves the destination unchanged. An invalid slot returns before touching RAM control; validation failures after enabling RAM disable it before returning zero.
kitaqgb/lib/save.c:125
u8 save_read(u8 slot, void* data, u16 len)
{
u8* dst = (u8*)data;
u16 base;
u16 stored_len;
u8 stored_sum;
u16 i;
if (slot >= SAVE_SLOT_COUNT) return 0;
base = save_slot_base(slot);
save_enable();
if (save_read_abs(base + 0) != SAVE_MAGIC0) {
save_disable();
return 0;
}
if (save_read_abs(base + 1) != SAVE_MAGIC1) {
save_disable();
return 0;
}
if (save_read_abs(base + 2) != SAVE_VERSION) {
save_disable();
return 0;
}
stored_len = (u16)save_read_abs(base + 3);
stored_len |= (u16)((u16)save_read_abs(base + 4) << 8);
stored_sum = save_read_abs(base + 5);
if (stored_len != len || stored_len > (u16)(SAVE_SLOT_SIZE - SAVE_HEADER_SIZE)) {
save_disable();
return 0;
}
if (save_checksum_ram((u16)(base + SAVE_HEADER_SIZE), stored_len) != stored_sum) {
save_disable();
return 0;
}
i = 0;
while (i < stored_len) {
dst[i] = save_read_abs((u16)(base + SAVE_HEADER_SIZE + i));
i++;
}
save_disable();
return 1;
}save_write
將資料、長度與檢查碼寫入插槽。
語法
u8 save_write(u8 slot, const void* data, u16 len);參數
slot插槽編號 0..3。
data含 len 個位元組的可讀取來源。
len資料長度為 0..506 位元組;讀取時必須與儲存的長度完全一致。
回傳值
引數有效時傳回 1,插槽或長度無效時傳回 0;不會讀回驗證。
使用條件與限制
預設為四個 512 位元組插槽,每個含六位元組標頭及最多 506 位元組資料。範例使用搭配 8 KiB SRAM 的 MBC5。呼叫結束時會停用 RAM,不還原先前的記憶體庫或啟用狀態。
八位元加總檢查碼無法偵測所有損壞。斷電時不保證寫入的原子性;僅收到成功結果,不能保證資料已實際持久保存。
使用範例
payload[0]=7;payload[1]=42;payload[2]=255;result[1]=save_write(0,payload,3);result[2]=save_write(4,payload,3);result[3]=save_write(0,payload,507);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
儲存 7/42/255 三個位元組,再測試長度不符、無效插槽及損壞的檢查碼。成功載入時中間位元組為 42;讀取失敗時目的值 77 維持不變;清除後驗證傳回 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_save.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_save.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=8k實作與原始碼
kitaqgb/lib/rpg.h:326
Validate slot and payload length, write payload bytes, then write the header and checksum. Return one after completing the writes; interruption can leave a partially replaced slot, so this is not transactional save storage.
kitaqgb/lib/save.c:81
u8 save_write(u8 slot, const void* data, u16 len)
{
const u8* src = (const u8*)data;
u16 base;
u16 i;
u8 sum = 0;
if (slot >= SAVE_SLOT_COUNT) return 0;
if (len > (u16)(SAVE_SLOT_SIZE - SAVE_HEADER_SIZE)) return 0;
base = save_slot_base(slot);
save_enable();
i = 0;
while (i < len) {
u8 v = src[i];
save_write_abs((u16)(base + SAVE_HEADER_SIZE + i), v);
sum = (u8)(sum + v);
i++;
}
save_write_abs(base + 0, SAVE_MAGIC0);
save_write_abs(base + 1, SAVE_MAGIC1);
save_write_abs(base + 2, SAVE_VERSION);
save_write_abs(base + 3, (u8)(len & 0xFF));
save_write_abs(base + 4, (u8)(len >> 8));
save_write_abs(base + 5, sum);
save_disable();
return 1;
}script_run
選取腳本,重設等待次數、選擇結果及已儲存的返回位置。
語法
void script_run(u8 bank, const u8* script);參數
bank指令串流的 ROM 記憶體庫。
script具有終止指令的有效串流起點;此呼叫僅準備串流,不執行命令。
回傳值
無傳回值。
使用條件與限制
操作碼:00 END;01 TEXT(bank,ptr16);02 SET_FLAG(id16);03 CLEAR_FLAG(id16);04 JUMP(bank,ptr16);05 IF_FLAG(id16,bank,ptr16);06 CHOICE(count,table16);07 WAIT(n);08 CALL_EVENT(bank,ptr16)。雙位元組值採小端序。字串、指標表與指令須維持可讀取,且不得超出其映射記憶體庫。
使用範例
flag_clear(19);script_run(1,(const u8*)&entry);result[0]=flag_get(19);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
從記憶體庫 1 跳到 2、設定旗標 19 並等待。最初兩次等待呼叫傳回 1,目標旗標變成 1,WAIT 之後完成時傳回 2。該旗標可證明控制流程已到達另一個記憶體庫。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_script.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_script.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/rpg.h:250
Replace the active script and clear wait, choice and saved-return state.
kitaqgb/lib/script.c:105
void script_run(u8 bank, const u8* script)
{
script_active = 1;
script_bank = bank;
script_pc = script;
script_wait = 0;
script_last_choice = 0xFF;
script_return_active = 0;
}script_step
持續執行命令,直到輸出、選擇、等待或完成時讓出控制權。
語法
u8 script_step();回傳值
0=TEXT/CHOICE 讓出控制權;1=等待中;2=完成或未啟用。未知操作碼也會以 2 終止。
使用條件與限制
操作碼:00 END;01 TEXT(bank,ptr16);02 SET_FLAG(id16);03 CLEAR_FLAG(id16);04 JUMP(bank,ptr16);05 IF_FLAG(id16,bank,ptr16);06 CHOICE(count,table16);07 WAIT(n);08 CALL_EVENT(bank,ptr16)。雙位元組值採小端序。字串、指標表與指令須維持可讀取,且不得超出其映射記憶體庫。
WAIT n 解碼時傳回 1,之後再等待 n 次呼叫。CALL_EVENT 只有一個返回位置儲存欄位。CHOICE 的數量不可為零,且會在內部阻塞直到完成選擇。不讓出控制權的跳躍迴圈會阻塞遊戲迴圈,請確保執行能到達終止或讓出控制權的命令。
使用範例
result[3]=script_step();result[4]=flag_get(19);result[5]=script_step();result[6]=script_step();result[7]=script_step();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
從記憶體庫 1 跳到 2、設定旗標 19 並等待。最初兩次等待呼叫傳回 1,目標旗標變成 1,WAIT 之後完成時傳回 2。該旗標可證明控制流程已到達另一個記憶體庫。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_script.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_script.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/rpg.h:254
Execute commands until an output/choice yields (0), a wait yields (1), or execution ends (2). Control/flag commands continue within the same call, so a script loop without a yielding command can block the game loop indefinitely.
kitaqgb/lib/script.c:125
u8 script_step()
{
if (script_active == 0) return 2;
if (script_wait != 0) {
script_wait--;
return 1;
}
while (script_active != 0) {
u8 op = script_read8();
// An END returns to the one saved caller when present; otherwise it ends the script.
if (op == SCRIPT_OP_END) {
if (script_return_active != 0) {
script_bank = script_return_bank;
script_pc = script_return_pc;
script_return_active = 0;
continue;
}
script_active = 0;
return 2;
}
if (op == SCRIPT_OP_TEXT) {
u8 bank = script_read8();
u16 ptr = script_read16();
text_print_far(bank, (const u8*)ptr);
return 0;
}
if (op == SCRIPT_OP_SET_FLAG) {
u16 id = script_read16();
flag_set(id);
continue;
}
if (op == SCRIPT_OP_CLEAR_FLAG) {
u16 id = script_read16();
flag_clear(id);
continue;
}
if (op == SCRIPT_OP_JUMP) {
// Read all operands in the source bank before installing the destination.
u8 bank = script_read8();
u16 ptr = script_read16();
script_bank = bank;
script_pc = (const u8*)ptr;
continue;
}
// Read all branch operands before switching bank/address so an untaken branch
// still consumes the full instruction.
if (op == SCRIPT_OP_IF_FLAG) {
u16 id = script_read16();
u8 bank = script_read8();
u16 ptr = script_read16();
if (flag_get(id) != 0) {
script_bank = bank;
script_pc = (const u8*)ptr;
}
continue;
}
if (op == SCRIPT_OP_CHOICE) {
u8 count = script_read8();
u16 table = script_read16();
script_last_choice = script_choice(script_bank, (const u8*)table, count);
return 0;
}
if (op == SCRIPT_OP_WAIT) {
script_wait = script_read8();
return 1;
}
// Save the continuation only when the single return slot is empty. Nested
// calls replace the current script but do not push another return address.
if (op == SCRIPT_OP_CALL_EVENT) {
u8 bank = script_read8();
u16 ptr = script_read16();
if (script_return_active == 0) {
script_return_active = 1;
script_return_bank = script_bank;
script_return_pc = script_pc;
}
script_bank = bank;
script_pc = (const u8*)ptr;
continue;
}
// Unknown opcodes terminate with the same return code as END; there is no distinct malformed-stream error.
script_active = 0;
return 2;
}
return 2;
}script_wait_frames
讓接下來指定次數的 script_step 呼叫等待。
語法
void script_wait_frames(u8 n);參數
n等待呼叫次數 0..255;零會清除等待。
回傳值
無傳回值。
使用條件與限制
只有每影格呼叫一次 script_step 時,此數值才代表影格數;函式本身不會等待 VBlank。
使用範例
script_wait_frames(2);result[1]=script_step();result[2]=script_step();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
從記憶體庫 1 跳到 2、設定旗標 19 並等待。最初兩次等待呼叫傳回 1,目標旗標變成 1,WAIT 之後完成時傳回 2。該旗標可證明控制流程已到達另一個記憶體庫。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_script.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_script.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/rpg.h:257
Set the number of subsequent script_step calls to spend waiting. Frame-based timing requires the application to call script_step once per frame.
kitaqgb/lib/script.c:117
void script_wait_frames(u8 n)
{
script_wait = n;
}text_choice
在作用中的文字區域繪製垂直清單並等待選擇。UP/DOWN 移動游標並於兩端循環,A 確認、B 取消。迴圈會重繪選項,在等待 VBlank 後輪詢一次。傳回從零起算的索引;取消或空清單傳回 255。
語法
u8 text_choice(const u8* const* choices, u8 count);參數
choices指向含 count 個可讀取字串指標的陣列。各字串以零結尾,內容是原始圖塊 ID;選項文字不解讀對話控制碼。選擇完成前,指標表與字串都須維持映射。
count選項數量。零會立即傳回 255,不讀取指標表。非空清單須提供至少 count 個內部列,寬度須能容納一格游標加上最長選項文字。不裁切或捲動。
回傳值
按 A 確認時傳回 0 到 count−1 的索引。255 表示按 B 取消或 count 為零;需要區分時請由呼叫端處理。不會關閉文字區域或清除清單。
使用條件與限制
請使用有效的 BG 映射矩形,先載入字型與邊框圖塊。軟體文字區域使用 LCDC 位元 3 選定的 BG 映射表,不會啟用硬體 Window 圖層。CGB 的圖塊編號請使用 VBK 0,色彩屬性另行設定。範例提供對應 ASCII 的字型、邊框、游標及換頁指示圖塊。對話和選項文字使用單位元組圖塊 ID,不解碼 UTF-8。若需顯示字型以外的字元,請提供字形圖塊並以其 ID 編碼文字,同時保留對話控制位元組值。
呼叫前請開啟區域並設定大小。選擇函式使用儲存位置,不檢查是否已開啟。文字從左邊緣內兩欄、上邊緣下一列開始;游標佔用文字左側緊鄰的一格。選項輸出不使用對話字元速度設定。
輸入迴圈回應新按下的按鍵,先處理 UP 再處理 DOWN,先 A 再 B。長按方向不連續移動,須放開再按。先前按鍵遮罩從零開始,因此進入時已按住的按鍵可能立即作用。同時移動並按 A 會傳回移動後的索引,但最後繪製的游標可能仍在前一位置。
這些是阻塞式輔助函式,等待期間不會呼叫遊戲更新、音樂服務或繪圖迴圈。LCD 關閉時 __wait_vblank 立即返回,因此字元速度與 WAIT 不會產生影格延遲。需要定時對話及按影格輪詢輸入時,請保持 LCD 啟用。對話中若須同時推進其他工作,請由遊戲端使用狀態機。
底層安全圖塊寫入會在 LCD 開啟時等待可寫入模式,並在寫入前後使用 DI/EI。可能開啟中斷,而不保留原本停用的狀態。不可從中斷處理常式呼叫這些阻塞式函式,也不可依賴它們保留該狀態。
每個完整範例都已包含一次 text.c。建置時加入函式庫與手冊範例的 include 目錄,不要再把 lib/text.c 當作另一個來源輸入。遠端串流範例使用 MBC5 與 64 KiB ROM,以容納記憶體庫 2 的資料。
使用範例
selected=text_choice(dialogue_choices,3);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
先按一次 DOWN,再按 A。擷取結果中,向右游標在圖塊 (2,4) 的 SHIELD 旁,SELECTED 顯示 1。三個選項從 (3,3)、(3,4)、(3,5) 開始。CGB 的邊框、游標、選項為綠色,DMG 為黑色;結果與操作提示維持黑色。
模擬器檢查會比對完整 BG 映射內容及四張範例圖片。額外執行涵蓋開關狀態、一般與跨記憶體庫控制串流、定時等待、明確與自動換頁等待、A/B/START 換頁、長按、循環選擇、空清單及同時輸入優先權。以腳本輸入前後檢查點驗證換頁等待確實阻塞。尚未測試實機及中斷並行。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dialogue_choice.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dialogue_choice.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:231
Redraw choices and block for edge-triggered navigation: UP/DOWN wrap, A accepts, and B returns 0xFF. Zero choices also returns 0xFF. Choice strings use raw tile bytes, and the caller must fit them inside the available rows.
kitaqgb/lib/text.c:316
u8 text_choice(const u8* const* choices, u8 count)
{
u8 cursor;
u8 prev;
if (count == 0) return 0xFF;
cursor = 0;
prev = 0;
while (1) {
u8 i;
for (i = 0; i < count; i++) {
u8 py = (u8)(text_y + 1 + i);
__settile_xy((u8)(text_x + 1), py, (i == cursor) ? TEXT_TILE_CURSOR : TEXT_TILE_FILL);
text_draw_string_at((u8)(text_x + 2), py, choices[i]);
}
__wait_vblank();
{
u16 kt = __readpadex(prev);
u8 trigger;
prev = (u8)kt;
trigger = (u8)(kt >> 8);
if ((trigger & PAD_KEY_UP) != 0) {
if (cursor == 0) cursor = (u8)(count - 1);
else cursor--;
}
if ((trigger & PAD_KEY_DOWN) != 0) {
cursor++;
if (cursor >= count) cursor = 0;
}
if ((trigger & PAD_KEY_A) != 0) return cursor;
if ((trigger & PAD_KEY_B) != 0) return 0xFF;
}
}
}text_clear_rect
以 TEXT_TILE_FILL 填滿背景圖塊地圖的矩形區域,可用於擦除標籤、清空數值欄位或面板的一部分。不移動目前文字游標,也不關閉文字區域或改變其尺寸。
語法
void text_clear_rect(u8 x, u8 y, u8 w, u8 h);參數
x起始欄,以 8×8 背景地圖格為單位。完整輸出須位於第 0–31 欄內。背景未捲動時,可見範圍為第 0–19 欄。
y起始列,以 8×8 背景地圖格為單位,範圍 0–31。背景未捲動時,可見第 0–17 列。矩形在垂直方向也必須完整容納於地圖內。
w寬度,以圖塊格為單位。text_window 包含左右邊框兩欄,內部剩 max(w−2, 0) 欄。text_clear_rect 則表示每列要填滿的格數。
h高度,以圖塊格為單位。text_window 包含上下邊框,內部剩 max(h−2, 0) 列。text_clear_rect 則表示要填滿的列數。
回傳值
無傳回值。函式在返回前寫入圖塊地圖格,不傳回字元數或狀態碼。
使用條件與限制
這些函式繪製到 LCDC 位元 3 選定的 BG 地圖。文字視窗是該地圖上的軟體文字區域,並非硬體 Window 圖層。寫入圖塊編號時須保持 CGB VBK=0;這些呼叫不設定色彩屬性、調色盤或捲動。
繪製前須載入字型與邊框圖形。預設邊框 ID 為 1–6,填滿圖塊為 0,十進位數字從 ASCII 0(圖塊 48)開始;減號使用 ASCII -(圖塊 45)。範例提供六個邊框圖塊,以及字形 ID 與 ASCII 對應的手冊字型。
矩形與文字須完整位於 32×32 地圖內。矩形填滿不會依地圖邊界裁切寬度或高度。寬度或高度為零時不填入任何內容;text_window 仍將該區域記錄為已開啟,但沒有可用的內部空間。
公開的數值函式只使用新值所需的寬度,不會擦除右側殘留的格子。在同一位置用 7 覆寫 12345,會顯示 72345。若只要顯示 7,須先以 text_clear_rect 清空預留的五格欄位。有號 16 位元欄位應預留六格。
圖塊寫入內建函式會檢查 LCD 狀態:LCD 關閉時立即寫入;開啟時等待可寫入的 LCD 模式,並在寫入前後使用 DI/EI。此路徑返回時可能啟用中斷,因此不可假設會保留中斷停用狀態。本節範例與位元組層級測試均在 LCD 關閉時寫入。
完整範例引入 text.c 一次,讓函式庫實作與程式一同編譯。此範例不可再將 lib/text.c 當作獨立輸入。若要自訂 TEXT_* 圖塊常數,須在引入 rpg.h 與實作前定義,並在所有編譯該函式庫的地方使用相同定義。
使用範例
text_clear_rect(7,5,5,1);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
邊框內最初在第 5 列顯示 KEEP ERASE KEEP。從 (7,5) 清除五格後,ERASE 消失,兩個 KEEP 標籤與邊框則保留。CLEAN 列也先清空五格數值欄位,再寫入 7。
驗證會比較兩個範例畫面的每個可見像素,以及全部 1024 個 BG 地圖位元組。另以 DMG/CGB ROM 檢查全部 256 個無號位元組值、十進位位數邊界與有號極值,並保留各數值輸出旁的點作為邊界哨兵。版面檢查包含空矩形、窄矩形、地圖邊緣位置、直接使用控制碼數值的圖塊位元組,以及絕對位置寫入後的視窗游標。這些是模擬器測試,並非實機測試。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\text_layout.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\text_layout.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:237
Fill the supplied tile rectangle without changing the active text window or cursor.
kitaqgb/lib/text.c:220
void text_clear_rect(u8 x, u8 y, u8 w, u8 h)
{
__settile_rect(x, y, w, h, TEXT_TILE_FILL);
}text_close
以 TEXT_TILE_FILL 清除作用中的文字區域及邊框,並標記為已關閉。已關閉時再次呼叫不執行任何動作。不會還原開啟區域前的背景圖塊。
語法
void text_close();回傳值
無傳回值。任何繪圖或阻塞等待都在函式返回前完成。
使用條件與限制
請使用有效的 BG 映射矩形,先載入字型與邊框圖塊。軟體文字區域使用 LCDC 位元 3 選定的 BG 映射表,不會啟用硬體 Window 圖層。CGB 的圖塊編號請使用 VBK 0,色彩屬性另行設定。範例提供對應 ASCII 的字型、邊框、游標及換頁指示圖塊。對話和選項文字使用單位元組圖塊 ID,不解碼 UTF-8。若需顯示字型以外的字元,請提供字形圖塊並以其 ID 編碼文字,同時保留對話控制位元組值。
區域關閉或沒有可用內部空間時,一般字元會被忽略。但控制位元組仍會解讀:WAIT 仍可能阻塞,換頁控制仍可能等待或清除儲存的區域。因此對已關閉區域呼叫 text_print,並不保證完全無作用。
這些是阻塞式輔助函式,等待期間不會呼叫遊戲更新、音樂服務或繪圖迴圈。LCD 關閉時 __wait_vblank 立即返回,因此字元速度與 WAIT 不會產生影格延遲。需要定時對話及按影格輪詢輸入時,請保持 LCD 啟用。對話中若須同時推進其他工作,請由遊戲端使用狀態機。
底層安全圖塊寫入會在 LCD 開啟時等待可寫入模式,並在寫入前後使用 DI/EI。可能開啟中斷,而不保留原本停用的狀態。不可從中斷處理常式呼叫這些阻塞式函式,也不可依賴它們保留該狀態。
每個完整範例都已包含一次 text.c。建置時加入函式庫與手冊範例的 include 目錄,不要再把 lib/text.c 當作另一個來源輸入。遠端串流範例使用 MBC5 與 64 KiB ROM,以容納記憶體庫 2 的資料。
使用範例
text_close();
text_print("HIDDEN"); // With the area closed, ordinary characters are not drawn.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例在 (1,9) 開啟 18×3 格區域,寫入 ERASE ME,關閉後再嘗試寫入 HIDDEN。CLOSED AREA 下方 x=1–18、y=9–11 的格子應為空白,文字與邊框皆不應殘留。上方藍色對話仍可見。
模擬器檢查會比對完整 BG 映射內容及四張範例圖片。額外執行涵蓋開關狀態、一般與跨記憶體庫控制串流、定時等待、明確與自動換頁等待、A/B/START 換頁、長按、循環選擇、空清單及同時輸入優先權。以腳本輸入前後檢查點驗證換頁等待確實阻塞。尚未測試實機及中斷並行。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dialogue_flow.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dialogue_flow.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:220
Erase the open window with the fill tile and disable windowed character output.
kitaqgb/lib/text.c:200
void text_close()
{
if (text_opened == 0) return;
__settile_rect(text_x, text_y, text_w, text_h, TEXT_TILE_FILL);
text_opened = 0;
}text_open
在背景映射表開啟軟體文字區域。儲存位置與尺寸、將字元游標重設到第一個內部格子,再繪製邊框並清空內部。開啟另一區域會改變作用中的游標與區域,但不會清除映射表其他位置已繪製的區域。
語法
void text_open(u8 x, u8 y, u8 w, u8 h);參數
x區域最左欄,以 8×8 BG 映射格為單位。整個寬度須位於第 0–31 欄內。
y區域最上列,以 8×8 BG 映射格為單位。整個高度須位於第 0–31 列內。
w包含左右邊框的總寬度,以格子計算。要有一欄內部文字,至少需要三格。
h包含上下邊框的總高度,以格子計算。要有一列內部文字,至少需要三格。
回傳值
無傳回值。任何繪圖或阻塞等待都在函式返回前完成。
使用條件與限制
請使用有效的 BG 映射矩形,先載入字型與邊框圖塊。軟體文字區域使用 LCDC 位元 3 選定的 BG 映射表,不會啟用硬體 Window 圖層。CGB 的圖塊編號請使用 VBK 0,色彩屬性另行設定。範例提供對應 ASCII 的字型、邊框、游標及換頁指示圖塊。對話和選項文字使用單位元組圖塊 ID,不解碼 UTF-8。若需顯示字型以外的字元,請提供字形圖塊並以其 ID 編碼文字,同時保留對話控制位元組值。
這些是阻塞式輔助函式,等待期間不會呼叫遊戲更新、音樂服務或繪圖迴圈。LCD 關閉時 __wait_vblank 立即返回,因此字元速度與 WAIT 不會產生影格延遲。需要定時對話及按影格輪詢輸入時,請保持 LCD 啟用。對話中若須同時推進其他工作,請由遊戲端使用狀態機。
底層安全圖塊寫入會在 LCD 開啟時等待可寫入模式,並在寫入前後使用 DI/EI。可能開啟中斷,而不保留原本停用的狀態。不可從中斷處理常式呼叫這些阻塞式函式,也不可依賴它們保留該狀態。
每個完整範例都已包含一次 text.c。建置時加入函式庫與手冊範例的 include 目錄,不要再把 lib/text.c 當作另一個來源輸入。遠端串流範例使用 MBC5 與 64 KiB ROM,以容納記憶體庫 2 的資料。
使用範例
text_open(1,2,18,5);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
DIALOGUE FLOW 在 (1,2) 開啟 18×5 格外框,內部為 16×3 格。NEAR、READY、BANK 2 各佔一列。可見框線範圍為像素 x=11–147、y=19–51。CGB 的外框與文字為藍色,DMG 為黑色。之後開啟清除測試區域時,此框仍保留。
模擬器檢查會比對完整 BG 映射內容及四張範例圖片。額外執行涵蓋開關狀態、一般與跨記憶體庫控制串流、定時等待、明確與自動換頁等待、A/B/START 換頁、長按、循環選擇、空清單及同時輸入優先權。以腳本輸入前後檢查點驗證換頁等待確實阻塞。尚未測試實機及中斷並行。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dialogue_flow.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dialogue_flow.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:218
Set the tile-space window, reset its cursor and redraw it immediately. Opening does not reset the existing character speed or load font tiles.
kitaqgb/lib/text.c:187
void text_open(u8 x, u8 y, u8 w, u8 h)
{
text_x = x;
text_y = y;
text_w = w;
text_h = h;
text_opened = 1;
text_reset_cursor();
text_draw_frame();
text_clear_inside();
}text_print
透過一般指標讀取控制串流,在作用中視窗游標位置寫入字元圖塊。會解讀換行、定時等待及換頁等待,並在內部寬度處自動換行。只有到達 END 才返回,因此換頁等待可能阻塞到按鍵按下為止。
語法
void text_print(const u8* str);參數
str指向以 TEXT_CTRL_END(0)結尾之串流的可讀取指標。阻塞等待期間,包含 WAIT 後運算元在內的整個串流都須維持映射。不提供緩衝區長度或有效性檢查。
回傳值
無傳回值。任何繪圖或阻塞等待都在函式返回前完成。
使用條件與限制
請使用有效的 BG 映射矩形,先載入字型與邊框圖塊。軟體文字區域使用 LCDC 位元 3 選定的 BG 映射表,不會啟用硬體 Window 圖層。CGB 的圖塊編號請使用 VBK 0,色彩屬性另行設定。範例提供對應 ASCII 的字型、邊框、游標及換頁指示圖塊。對話和選項文字使用單位元組圖塊 ID,不解碼 UTF-8。若需顯示字型以外的字元,請提供字形圖塊並以其 ID 編碼文字,同時保留對話控制位元組值。
控制位元組:0x00 結束串流;0x0A 移到下一內部列;0x01 將下一位元組當作 VBlank 等待次數,包含零;0x02 等待換頁、清空內部並重設游標。其他位元組是圖塊 ID。WAIT 的零運算元不是 END 標記。
換行或自動換行超過最後一個內部列時,會顯示換頁等待標記,等待 A、B 或 START,清空內部,再從第一格繼續。這會替換整頁,不是逐列捲動。明確的 0x02 會等待但不加標記。換頁輪詢開始時不記憶先前按鍵,因此等待開始時已按住的按鍵也可能換頁。
區域關閉或沒有可用內部空間時,一般字元會被忽略。但控制位元組仍會解讀:WAIT 仍可能阻塞,換頁控制仍可能等待或清除儲存的區域。因此對已關閉區域呼叫 text_print,並不保證完全無作用。
這些是阻塞式輔助函式,等待期間不會呼叫遊戲更新、音樂服務或繪圖迴圈。LCD 關閉時 __wait_vblank 立即返回,因此字元速度與 WAIT 不會產生影格延遲。需要定時對話及按影格輪詢輸入時,請保持 LCD 啟用。對話中若須同時推進其他工作,請由遊戲端使用狀態機。
底層安全圖塊寫入會在 LCD 開啟時等待可寫入模式,並在寫入前後使用 DI/EI。可能開啟中斷,而不保留原本停用的狀態。不可從中斷處理常式呼叫這些阻塞式函式,也不可依賴它們保留該狀態。
每個完整範例都已包含一次 text.c。建置時加入函式庫與手冊範例的 include 目錄,不要再把 lib/text.c 當作另一個來源輸入。遠端串流範例使用 MBC5 與 64 KiB ROM,以容納記憶體庫 2 的資料。
使用範例
text_print(dialogue_near);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
一般串流依序寫入 NEAR、換行、READY、十二次等待命令,最後 END。NEAR 從圖塊 (2,3) 開始,READY 從 (2,4) 開始。後續跨記憶體庫串流沿用同一游標,因此其開頭換行會將 BANK 2 放在內部第三列。
模擬器檢查會比對完整 BG 映射內容及四張範例圖片。額外執行涵蓋開關狀態、一般與跨記憶體庫控制串流、定時等待、明確與自動換頁等待、A/B/START 換頁、長按、循環選擇、空清單及同時輸入優先權。以腳本輸入前後檢查點驗證換頁等待確實阻塞。尚未測試實機及中斷並行。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dialogue_flow.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dialogue_flow.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:224
Decode an END-terminated stream of tile bytes and newline/wait/page controls. WAIT consumes a following frame-count byte. The source must remain readable through blocking waits; the routine does not validate stream length.
kitaqgb/lib/text.c:261
void text_print(const u8* str)
{
while (*str != TEXT_CTRL_END) {
u8 c = *str++;
if (c == TEXT_CTRL_NEWLINE) {
text_newline();
continue;
}
if (c == TEXT_CTRL_WAIT) {
u8 frames = *str++;
text_delay_frames(frames);
continue;
}
if (c == TEXT_CTRL_PAGE_WAIT) {
text_wait_advance();
text_clear_inside();
text_reset_cursor();
continue;
}
text_put_tile(c);
}
}text_print_far
以 __farpeek8 從指定 ROM 記憶體庫逐位元組讀取,解讀相同的對話控制串流。適用於目前來源映射之外的對話。字元位置、速度、換行及換頁控制與 text_print 相同。
語法
void text_print_far(u8 bank, const u8* str);參數
bank無號 8 位元來源 ROM 記憶體庫編號。範例將串流放在記憶體庫 2,並檢查輸出後呼叫端仍可讀取記憶體庫 1 的標記。
str指定記憶體庫內串流的 CPU 位址。位址會遞增,但記憶體庫編號固定;跨越可切換 ROM 視窗時,不會自動接續下一個記憶體庫。
回傳值
無傳回值。任何繪圖或阻塞等待都在函式返回前完成。
使用條件與限制
請使用有效的 BG 映射矩形,先載入字型與邊框圖塊。軟體文字區域使用 LCDC 位元 3 選定的 BG 映射表,不會啟用硬體 Window 圖層。CGB 的圖塊編號請使用 VBK 0,色彩屬性另行設定。範例提供對應 ASCII 的字型、邊框、游標及換頁指示圖塊。對話和選項文字使用單位元組圖塊 ID,不解碼 UTF-8。若需顯示字型以外的字元,請提供字形圖塊並以其 ID 編碼文字,同時保留對話控制位元組值。
控制位元組:0x00 結束串流;0x0A 移到下一內部列;0x01 將下一位元組當作 VBlank 等待次數,包含零;0x02 等待換頁、清空內部並重設游標。其他位元組是圖塊 ID。WAIT 的零運算元不是 END 標記。
換行或自動換行超過最後一個內部列時,會顯示換頁等待標記,等待 A、B 或 START,清空內部,再從第一格繼續。這會替換整頁,不是逐列捲動。明確的 0x02 會等待但不加標記。換頁輪詢開始時不記憶先前按鍵,因此等待開始時已按住的按鍵也可能換頁。
區域關閉或沒有可用內部空間時,一般字元會被忽略。但控制位元組仍會解讀:WAIT 仍可能阻塞,換頁控制仍可能等待或清除儲存的區域。因此對已關閉區域呼叫 text_print,並不保證完全無作用。
這些是阻塞式輔助函式,等待期間不會呼叫遊戲更新、音樂服務或繪圖迴圈。LCD 關閉時 __wait_vblank 立即返回,因此字元速度與 WAIT 不會產生影格延遲。需要定時對話及按影格輪詢輸入時,請保持 LCD 啟用。對話中若須同時推進其他工作,請由遊戲端使用狀態機。
底層安全圖塊寫入會在 LCD 開啟時等待可寫入模式,並在寫入前後使用 DI/EI。可能開啟中斷,而不保留原本停用的狀態。不可從中斷處理常式呼叫這些阻塞式函式,也不可依賴它們保留該狀態。
每個完整範例都已包含一次 text.c。建置時加入函式庫與手冊範例的 include 目錄,不要再把 lib/text.c 當作另一個來源輸入。遠端串流範例使用 MBC5 與 64 KiB ROM,以容納記憶體庫 2 的資料。
使用範例
text_print_far(2,dialogue_far);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例從 ROM 記憶體庫 2 讀取換行與 BANK 2。之後讀取呼叫端記憶體庫 1 的標記,在 BANK RESTORED 顯示 161。BANK 2 列從圖塊 (2,5) 開始,還原確認數值位於 (16,14)。
模擬器檢查會比對完整 BG 映射內容及四張範例圖片。額外執行涵蓋開關狀態、一般與跨記憶體庫控制串流、定時等待、明確與自動換頁等待、A/B/START 換頁、長按、循環選擇、空清單及同時輸入優先權。以腳本輸入前後檢查點驗證換頁等待確實阻塞。尚未測試實機及中斷並行。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dialogue_flow.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dialogue_flow.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:227
Decode the same text controls while fetching each byte from the specified ROM bank. The pointer advances within that bank; it does not roll into the next bank.
kitaqgb/lib/text.c:286
void text_print_far(u8 bank, const u8* str)
{
const u8* p = str;
while (1) {
u8 c = __farpeek8(bank, p);
p++;
if (c == TEXT_CTRL_END) return;
if (c == TEXT_CTRL_NEWLINE) {
text_newline();
continue;
}
if (c == TEXT_CTRL_WAIT) {
u8 frames = __farpeek8(bank, p);
p++;
text_delay_frames(frames);
continue;
}
if (c == TEXT_CTRL_PAGE_WAIT) {
text_wait_advance();
text_clear_inside();
text_reset_cursor();
continue;
}
text_put_tile(c);
}
}text_print_s16
以十進位繪製有號 16 位元值。負值先顯示減號圖塊,再顯示其絕對值;零與正值不加符號。最長的輸出為 -32768,占六格。
語法
void text_print_s16(u8 x, u8 y, s16 value);參數
x起始欄,以 8×8 背景地圖格為單位。完整輸出須位於第 0–31 欄內。背景未捲動時,可見範圍為第 0–19 欄。
y起始列,以 8×8 背景地圖格為單位,範圍 0–31。背景未捲動時,可見第 0–17 列。矩形在垂直方向也必須完整容納於地圖內。
value−32768 至 32767 的有號值。範例將 16 位元模式 32768(0x8000)轉型為 s16,以顯示 −32768。
回傳值
無傳回值。函式在返回前寫入圖塊地圖格,不傳回字元數或狀態碼。
使用條件與限制
這些函式繪製到 LCDC 位元 3 選定的 BG 地圖。文字視窗是該地圖上的軟體文字區域,並非硬體 Window 圖層。寫入圖塊編號時須保持 CGB VBK=0;這些呼叫不設定色彩屬性、調色盤或捲動。
繪製前須載入字型與邊框圖形。預設邊框 ID 為 1–6,填滿圖塊為 0,十進位數字從 ASCII 0(圖塊 48)開始;減號使用 ASCII -(圖塊 45)。範例提供六個邊框圖塊,以及字形 ID 與 ASCII 對應的手冊字型。
矩形與文字須完整位於 32×32 地圖內。矩形填滿不會依地圖邊界裁切寬度或高度。寬度或高度為零時不填入任何內容;text_window 仍將該區域記錄為已開啟,但沒有可用的內部空間。
公開的數值函式只使用新值所需的寬度,不會擦除右側殘留的格子。在同一位置用 7 覆寫 12345,會顯示 72345。若只要顯示 7,須先以 text_clear_rect 清空預留的五格欄位。有號 16 位元欄位應預留六格。
圖塊寫入內建函式會檢查 LCD 狀態:LCD 關閉時立即寫入;開啟時等待可寫入的 LCD 模式,並在寫入前後使用 DI/EI。此路徑返回時可能啟用中斷,因此不可假設會保留中斷停用狀態。本節範例與位元組層級測試均在 LCD 關閉時寫入。
完整範例引入 text.c 一次,讓函式庫實作與程式一同編譯。此範例不可再將 lib/text.c 當作獨立輸入。若要自訂 TEXT_* 圖塊常數,須在引入 rpg.h 與實作前定義,並在所有編譯該函式庫的地方使用相同定義。
使用範例
text_print_s16(11,12,(s16)32768);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
S16 列從 (11,12) 開始顯示 -32768,連同減號占六格,在 CGB 上為綠色。這用來測試有號 16 位元的最小值,其正的絕對值無法以 s16 表示。
驗證會比較兩個範例畫面的每個可見像素,以及全部 1024 個 BG 地圖位元組。另以 DMG/CGB ROM 檢查全部 256 個無號位元組值、十進位位數邊界與有號極值,並保留各數值輸出旁的點作為邊界哨兵。版面檢查包含空矩形、窄矩形、地圖邊緣位置、直接使用控制碼數值的圖塊位元組,以及絕對位置寫入後的視窗游標。這些是模擬器測試,並非實機測試。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\text_layout.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\text_layout.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:247
Print a minus tile for negative values, followed by the unsigned magnitude. Positive values use the unsigned decimal path; no plus sign is emitted.
kitaqgb/lib/text.c:246
void text_print_s16(u8 x, u8 y, s16 value)
{
u16 magnitude;
if (value < 0) {
__settile_xy(x, y, (u8)'-');
magnitude = (u16)((s16)0 - value);
text_print_u16_width((u8)(x + 1), y, magnitude, text_dec_digits_u16(magnitude));
return;
}
text_print_u16(x, y, (u16)value);
}text_print_u16
從指定圖塊位置開始,以十進位數字繪製無號 16 位元值。不補前導零,占一至五格。適合分數或道具數量等可能超過 255 的值。
語法
void text_print_u16(u8 x, u8 y, u16 value);參數
x起始欄,以 8×8 背景地圖格為單位。完整輸出須位於第 0–31 欄內。背景未捲動時,可見範圍為第 0–19 欄。
y起始列,以 8×8 背景地圖格為單位,範圍 0–31。背景未捲動時,可見第 0–17 列。矩形在垂直方向也必須完整容納於地圖內。
value0 至 65535 的無號值。
回傳值
無傳回值。函式在返回前寫入圖塊地圖格,不傳回字元數或狀態碼。
使用條件與限制
這些函式繪製到 LCDC 位元 3 選定的 BG 地圖。文字視窗是該地圖上的軟體文字區域,並非硬體 Window 圖層。寫入圖塊編號時須保持 CGB VBK=0;這些呼叫不設定色彩屬性、調色盤或捲動。
繪製前須載入字型與邊框圖形。預設邊框 ID 為 1–6,填滿圖塊為 0,十進位數字從 ASCII 0(圖塊 48)開始;減號使用 ASCII -(圖塊 45)。範例提供六個邊框圖塊,以及字形 ID 與 ASCII 對應的手冊字型。
矩形與文字須完整位於 32×32 地圖內。矩形填滿不會依地圖邊界裁切寬度或高度。寬度或高度為零時不填入任何內容;text_window 仍將該區域記錄為已開啟,但沒有可用的內部空間。
公開的數值函式只使用新值所需的寬度,不會擦除右側殘留的格子。在同一位置用 7 覆寫 12345,會顯示 72345。若只要顯示 7,須先以 text_clear_rect 清空預留的五格欄位。有號 16 位元欄位應預留六格。
圖塊寫入內建函式會檢查 LCD 狀態:LCD 關閉時立即寫入;開啟時等待可寫入的 LCD 模式,並在寫入前後使用 DI/EI。此路徑返回時可能啟用中斷,因此不可假設會保留中斷停用狀態。本節範例與位元組層級測試均在 LCD 關閉時寫入。
完整範例引入 text.c 一次,讓函式庫實作與程式一同編譯。此範例不可再將 lib/text.c 當作獨立輸入。若要自訂 TEXT_* 圖塊常數,須在引入 rpg.h 與實作前定義,並在所有編譯該函式庫的地方使用相同定義。
使用範例
text_print_u16(11,10,65535);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
U16 列在 (11,10) 顯示 65535,占五格,在 CGB 上為藍色。OVERWRITE 未先清空五格欄位,直接以 7 覆寫 12345,因此顯示 72345。
驗證會比較兩個範例畫面的每個可見像素,以及全部 1024 個 BG 地圖位元組。另以 DMG/CGB ROM 檢查全部 256 個無號位元組值、十進位位數邊界與有號極值,並保留各數值輸出旁的點作為邊界哨兵。版面檢查包含空矩形、窄矩形、地圖邊緣位置、直接使用控制碼數值的圖塊位元組,以及絕對位置寫入後的視窗游標。這些是模擬器測試,並非實機測試。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\text_layout.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\text_layout.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:244
Print an unsigned word in decimal using only the required number of cells.
kitaqgb/lib/text.c:239
void text_print_u16(u8 x, u8 y, u16 value)
{
text_print_u16_width(x, y, value, text_dec_digits_u16(value));
}text_print_u8
從指定圖塊位置開始,以十進位數字繪製無號 8 位元值。不補前導零,占一至三格;零占一格。適合顯示生命數、彈藥數等小型計數器。
語法
void text_print_u8(u8 x, u8 y, u8 value);參數
x起始欄,以 8×8 背景地圖格為單位。完整輸出須位於第 0–31 欄內。背景未捲動時,可見範圍為第 0–19 欄。
y起始列,以 8×8 背景地圖格為單位,範圍 0–31。背景未捲動時,可見第 0–17 列。矩形在垂直方向也必須完整容納於地圖內。
value0 至 255 的無號值。較寬型別的運算式會透過函式參數轉換為 u8。
回傳值
無傳回值。函式在返回前寫入圖塊地圖格,不傳回字元數或狀態碼。
使用條件與限制
這些函式繪製到 LCDC 位元 3 選定的 BG 地圖。文字視窗是該地圖上的軟體文字區域,並非硬體 Window 圖層。寫入圖塊編號時須保持 CGB VBK=0;這些呼叫不設定色彩屬性、調色盤或捲動。
繪製前須載入字型與邊框圖形。預設邊框 ID 為 1–6,填滿圖塊為 0,十進位數字從 ASCII 0(圖塊 48)開始;減號使用 ASCII -(圖塊 45)。範例提供六個邊框圖塊,以及字形 ID 與 ASCII 對應的手冊字型。
矩形與文字須完整位於 32×32 地圖內。矩形填滿不會依地圖邊界裁切寬度或高度。寬度或高度為零時不填入任何內容;text_window 仍將該區域記錄為已開啟,但沒有可用的內部空間。
公開的數值函式只使用新值所需的寬度,不會擦除右側殘留的格子。在同一位置用 7 覆寫 12345,會顯示 72345。若只要顯示 7,須先以 text_clear_rect 清空預留的五格欄位。有號 16 位元欄位應預留六格。
圖塊寫入內建函式會檢查 LCD 狀態:LCD 關閉時立即寫入;開啟時等待可寫入的 LCD 模式,並在寫入前後使用 DI/EI。此路徑返回時可能啟用中斷,因此不可假設會保留中斷停用狀態。本節範例與位元組層級測試均在 LCD 關閉時寫入。
完整範例引入 text.c 一次,讓函式庫實作與程式一同編譯。此範例不可再將 lib/text.c 當作獨立輸入。若要自訂 TEXT_* 圖塊常數,須在引入 rpg.h 與實作前定義,並在所有編譯該函式庫的地方使用相同定義。
使用範例
text_print_u8(11,8,255);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
U8 列從 (11,8) 開始顯示 255,恰好占三格,在 CGB 上為藍色。OVERWRITE 與 CLEAN 列說明為何換成較短的值時,必須明確清空欄位。
驗證會比較兩個範例畫面的每個可見像素,以及全部 1024 個 BG 地圖位元組。另以 DMG/CGB ROM 檢查全部 256 個無號位元組值、十進位位數邊界與有號極值,並保留各數值輸出旁的點作為邊界哨兵。版面檢查包含空矩形、窄矩形、地圖邊緣位置、直接使用控制碼數值的圖塊位元組,以及絕對位置寫入後的視窗游標。這些是模擬器測試,並非實機測試。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\text_layout.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\text_layout.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:242
Print an unsigned byte in decimal using only the required number of cells.
kitaqgb/lib/text.c:233
void text_print_u8(u8 x, u8 y, u8 value)
{
text_print_u16_width(x, y, (u16)value, text_dec_digits_u16((u16)value));
}text_print_xy
從背景地圖的絕對位置開始,水平繪製以 0 結尾的圖塊編號序列。不依視窗裁切、不自動換行、不解讀文字控制碼,也沒有逐字延遲。不移動 text_print 使用的游標。
語法
void text_print_xy(u8 x, u8 y, const u8* str);參數
x起始欄,以 8×8 背景地圖格為單位。完整輸出須位於第 0–31 欄內。背景未捲動時,可見範圍為第 0–19 欄。
y起始列,以 8×8 背景地圖格為單位,範圍 0–31。背景未捲動時,可見第 0–17 列。矩形在垂直方向也必須完整容納於地圖內。
str指向以 0 結尾之圖塊位元組序列的可讀指標。每個位元組直接用作圖塊編號。只有對應字形位於相應圖塊 ID 時,ASCII 字串才會顯示成文字。來源在呼叫返回前須持續映射且可讀。這些函式不解碼 UTF-8,也不載入字形。多位元組文字須先準備遊戲自訂編碼及對應圖塊資料,才能顯示。
回傳值
無傳回值。函式在返回前寫入圖塊地圖格,不傳回字元數或狀態碼。
使用條件與限制
這些函式繪製到 LCDC 位元 3 選定的 BG 地圖。文字視窗是該地圖上的軟體文字區域,並非硬體 Window 圖層。寫入圖塊編號時須保持 CGB VBK=0;這些呼叫不設定色彩屬性、調色盤或捲動。
繪製前須載入字型與邊框圖形。預設邊框 ID 為 1–6,填滿圖塊為 0,十進位數字從 ASCII 0(圖塊 48)開始;減號使用 ASCII -(圖塊 45)。範例提供六個邊框圖塊,以及字形 ID 與 ASCII 對應的手冊字型。
矩形與文字須完整位於 32×32 地圖內。矩形填滿不會依地圖邊界裁切寬度或高度。寬度或高度為零時不填入任何內容;text_window 仍將該區域記錄為已開啟,但沒有可用的內部空間。
圖塊寫入內建函式會檢查 LCD 狀態:LCD 關閉時立即寫入;開啟時等待可寫入的 LCD 模式,並在寫入前後使用 DI/EI。此路徑返回時可能啟用中斷,因此不可假設會保留中斷停用狀態。本節範例與位元組層級測試均在 LCD 關閉時寫入。
完整範例引入 text.c 一次,讓函式庫實作與程式一同編譯。此範例不可再將 lib/text.c 當作獨立輸入。若要自訂 TEXT_* 圖塊常數,須在引入 rpg.h 與實作前定義,並在所有編譯該函式庫的地方使用相同定義。
使用範例
text_print_xy(2,3,"HELLO!");這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
HELLO! 從 CGB 紅色邊框內的圖塊 (2,3)、像素 (16,24) 開始。這是 BG 地圖上的絕對位置:開啟文字區域不會為 x 或 y 加上偏移。
驗證會比較兩個範例畫面的每個可見像素,以及全部 1024 個 BG 地圖位元組。另以 DMG/CGB ROM 檢查全部 256 個無號位元組值、十進位位數邊界與有號極值,並保留各數值輸出旁的點作為邊界哨兵。版面檢查包含空矩形、窄矩形、地圖邊緣位置、直接使用控制碼數值的圖塊位元組,以及絕對位置寫入後的視窗游標。這些是模擬器測試,並非實機測試。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\text_layout.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\text_layout.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:240
Draw a zero-terminated tile string at absolute tile coordinates, without window clipping, control codes or the windowed printing delay.
kitaqgb/lib/text.c:227
void text_print_xy(u8 x, u8 y, const u8* str)
{
text_draw_string_at(x, y, str);
}text_set_speed
設定 text_print 或 text_print_far 每寫入一個一般字元後的 VBlank 等待次數。零表示取消逐字等待。開啟或關閉區域不會重設此設定。即使字元速度為零,明確指定的 WAIT 命令仍會等待。
語法
void text_set_speed(u8 speed);參數
speed每個字元顯示後的 VBlank 等待次數,0–255。這是等待次數,不是毫秒。設定不影響 text_print_xy、數字輔助函式或選項清單。
回傳值
無傳回值。任何繪圖或阻塞等待都在函式返回前完成。
使用條件與限制
請使用有效的 BG 映射矩形,先載入字型與邊框圖塊。軟體文字區域使用 LCDC 位元 3 選定的 BG 映射表,不會啟用硬體 Window 圖層。CGB 的圖塊編號請使用 VBK 0,色彩屬性另行設定。範例提供對應 ASCII 的字型、邊框、游標及換頁指示圖塊。對話和選項文字使用單位元組圖塊 ID,不解碼 UTF-8。若需顯示字型以外的字元,請提供字形圖塊並以其 ID 編碼文字,同時保留對話控制位元組值。
這些是阻塞式輔助函式,等待期間不會呼叫遊戲更新、音樂服務或繪圖迴圈。LCD 關閉時 __wait_vblank 立即返回,因此字元速度與 WAIT 不會產生影格延遲。需要定時對話及按影格輪詢輸入時,請保持 LCD 啟用。對話中若須同時推進其他工作,請由遊戲端使用狀態機。
底層安全圖塊寫入會在 LCD 開啟時等待可寫入模式,並在寫入前後使用 DI/EI。可能開啟中斷,而不保留原本停用的狀態。不可從中斷處理常式呼叫這些阻塞式函式,也不可依賴它們保留該狀態。
每個完整範例都已包含一次 text.c。建置時加入函式庫與手冊範例的 include 目錄,不要再把 lib/text.c 當作另一個來源輸入。遠端串流範例使用 MBC5 與 64 KiB ROM,以容納記憶體庫 2 的資料。
使用範例
text_set_speed(2);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
流程範例對一般與跨記憶體庫對話使用速度 2,並包含運算元為 12 的 WAIT。完成圖顯示等待後的文字;另以影格追蹤檢查速度 3、明確的五次等待命令,以及關閉狀態下的四次等待。時序驗證不只依賴最後截圖。
模擬器檢查會比對完整 BG 映射內容及四張範例圖片。額外執行涵蓋開關狀態、一般與跨記憶體庫控制串流、定時等待、明確與自動換頁等待、A/B/START 換頁、長按、循環選擇、空清單及同時輸入優先權。以腳本輸入前後檢查點驗證換頁等待確實阻塞。尚未測試實機及中斷並行。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dialogue_flow.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dialogue_flow.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:233
Set VBlank waits per windowed character; zero prints without character delays.
kitaqgb/lib/text.c:208
void text_set_speed(u8 speed)
{
text_speed = speed;
}text_window
在背景圖塊地圖上繪製帶框的文字區域,並將其設為視窗文字輸出的作用區域。這是 text_open 的別名:將視窗游標重設至內部第一格、重繪邊框並清空內部。保留目前的逐字延遲設定。
語法
void text_window(u8 x, u8 y, u8 w, u8 h);參數
x起始欄,以 8×8 背景地圖格為單位。完整輸出須位於第 0–31 欄內。背景未捲動時,可見範圍為第 0–19 欄。
y起始列,以 8×8 背景地圖格為單位,範圍 0–31。背景未捲動時,可見第 0–17 列。矩形在垂直方向也必須完整容納於地圖內。
w寬度,以圖塊格為單位。text_window 包含左右邊框兩欄,內部剩 max(w−2, 0) 欄。text_clear_rect 則表示每列要填滿的格數。
h高度,以圖塊格為單位。text_window 包含上下邊框,內部剩 max(h−2, 0) 列。text_clear_rect 則表示要填滿的列數。
回傳值
無傳回值。函式在返回前寫入圖塊地圖格,不傳回字元數或狀態碼。
使用條件與限制
這些函式繪製到 LCDC 位元 3 選定的 BG 地圖。文字視窗是該地圖上的軟體文字區域,並非硬體 Window 圖層。寫入圖塊編號時須保持 CGB VBK=0;這些呼叫不設定色彩屬性、調色盤或捲動。
繪製前須載入字型與邊框圖形。預設邊框 ID 為 1–6,填滿圖塊為 0,十進位數字從 ASCII 0(圖塊 48)開始;減號使用 ASCII -(圖塊 45)。範例提供六個邊框圖塊,以及字形 ID 與 ASCII 對應的手冊字型。
矩形與文字須完整位於 32×32 地圖內。矩形填滿不會依地圖邊界裁切寬度或高度。寬度或高度為零時不填入任何內容;text_window 仍將該區域記錄為已開啟,但沒有可用的內部空間。
圖塊寫入內建函式會檢查 LCD 狀態:LCD 關閉時立即寫入;開啟時等待可寫入的 LCD 模式,並在寫入前後使用 DI/EI。此路徑返回時可能啟用中斷,因此不可假設會保留中斷停用狀態。本節範例與位元組層級測試均在 LCD 關閉時寫入。
完整範例引入 text.c 一次,讓函式庫實作與程式一同編譯。此範例不可再將 lib/text.c 當作獨立輸入。若要自訂 TEXT_* 圖塊常數,須在引入 rpg.h 與實作前定義,並在所有編譯該函式庫的地方使用相同定義。
使用範例
text_window(1,2,18,5);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例在 (1,2) 開啟 18×5 格的區域,內部為 16×3 格。提供的邊框線寬為一像素;外側可見線條的範圍為 x=11 至 147、y=19 至 51 像素。CGB 上為紅色,DMG 上為黑色。
驗證會比較兩個範例畫面的每個可見像素,以及全部 1024 個 BG 地圖位元組。另以 DMG/CGB ROM 檢查全部 256 個無號位元組值、十進位位數邊界與有號極值,並保留各數值輸出旁的點作為邊界哨兵。版面檢查包含空矩形、窄矩形、地圖邊緣位置、直接使用控制碼數值的圖塊位元組,以及絕對位置寫入後的視窗游標。這些是模擬器測試,並非實機測試。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\text_layout.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\text_layout.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:235
Open and redraw a window using the same tile-space arguments as text_open.
kitaqgb/lib/text.c:214
void text_window(u8 x, u8 y, u8 w, u8 h)
{
text_open(x, y, w, h);
}unit_attack_range
標記曼哈頓距離位於 atk_min 到 atk_max 之間的格子,包含兩端。
語法
u8 unit_attack_range(unit_t* u, u8* out_mask);參數
u有效的 unit_t,包含格子位置、以步數表示的 move、含兩端的 atk_min/atk_max 範圍,以及判斷可否行動的 hp 與 acted。
out_maskwidth*height 個可寫入位元組;每格寫入零或一。
回傳值
地圖可用時傳回 1,尺寸為零時傳回 0。
使用條件與限制
座標指向目前地圖中的格子:一般圖塊為 8×8 像素,複合圖塊為 16×16 像素。
忽略障礙物、視線與友軍單位。評估距離最多 255。最小射程大於最大射程時,所有格子皆為零。
使用範例
result[46]=unit_attack_range(&hero,mask);result[47]=mask[12];result[48]=mask[14];這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側格線顯示三步內的移動成本,右側顯示從 S 到 G 的最短路徑。綠色星號標出繞過紅色三格牆的九步路徑,藍色數字表示成本。DMG 使用相同配置但以黑色顯示。RAM 檢查也示範攻擊遮罩會忽略牆壁。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_map_path.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_map_path.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/rpg.h:352
Mark cells whose Manhattan distance falls within the inclusive attack range. This geometric mask does not test obstacles, line of sight or other units.
kitaqgb/lib/slg_unit.c:38
u8 unit_attack_range(unit_t* u, u8* out_mask)
{
u8 w = map_current_width();
u8 h = map_current_height();
u8 y;
if (w == 0 || h == 0) return 0;
__memset(out_mask, 0, (u16)((u16)w * (u16)h));
y = 0;
while (y < h) {
u8 x = 0;
while (x < w) {
u8 dist = __manhattan(u->x, u->y, x, y);
if (dist >= u->atk_min && dist <= u->atk_max) {
out_mask[__map_index(x, y, w)] = 1;
}
x++;
}
y++;
}
return 1;
}unit_can_act
檢查單位是否仍有 HP 且尚未行動。
語法
u8 unit_can_act(const unit_t* u);參數
u有效的 unit_t,包含格子位置、以步數表示的 move、含兩端的 atk_min/atk_max 範圍,以及判斷可否行動的 hp 與 acted。
回傳值
hp 非零且 acted 為零時傳回 1,否則傳回 0。不修改單位。
使用範例
result[11]=unit_can_act(&hero);hero.acted=1;result[12]=unit_can_act(&hero);hero.acted=0;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側格線顯示三步內的移動成本,右側顯示從 S 到 G 的最短路徑。綠色星號標出繞過紅色三格牆的九步路徑,藍色數字表示成本。DMG 使用相同配置但以黑色顯示。RAM 檢查也示範攻擊遮罩會忽略牆壁。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_map_path.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_map_path.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/rpg.h:355
A unit can act only while HP is nonzero and its acted flag is clear. The unit pointer must refer to a valid record.
kitaqgb/lib/slg_unit.c:5
u8 unit_can_act(const unit_t* u)
{
if (u->hp == 0) return 0;
if (u->acted != 0) return 0;
return 1;
}unit_move_range
建立單位移動額度內可到達格子的遮罩。
語法
u8 unit_move_range(unit_t* u, u8* out_mask);參數
u有效的 unit_t,包含格子位置、以步數表示的 move、含兩端的 atk_min/atk_max 範圍,以及判斷可否行動的 hp 與 acted。
out_maskwidth*height 個可寫入位元組;每格寫入零或一。
回傳值
地圖可用時傳回 1,尺寸為零時傳回 0。單位起點必須位於地圖內。
使用條件與限制
座標指向目前地圖中的格子:一般圖塊為 8×8 像素,複合圖塊為 16×16 像素。
搜尋使用約 4 KiB 的共用工作區,且不可重入。地圖最多 1024 格,探索距離最多 254。距離 0xFF 表示未到達,因此無法表示 255 步的路徑。成本/遮罩輸出需要 width*height 個可寫入位元組。
起點即使受阻也會初始化為可到達。HP、acted 與其他單位不影響移動遮罩。
使用範例
result[43]=unit_move_range(&hero,mask);result[44]=mask[12];result[45]=mask[14];這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
左側格線顯示三步內的移動成本,右側顯示從 S 到 G 的最短路徑。綠色星號標出繞過紅色三格牆的九步路徑,藍色數字表示成本。DMG 使用相同配置但以黑色顯示。RAM 檢查也示範攻擊遮罩會忽略牆壁。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_map_path.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_map_path.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none實作與原始碼
kitaqgb/lib/rpg.h:349
Build movement costs, then convert reachable cells to one and unreachable 0xFF cells to zero. The caller provides one output byte per current-map cell and a valid unit origin; path-search workspace limits also apply.
kitaqgb/lib/slg_unit.c:15
u8 unit_move_range(unit_t* u, u8* out_mask)
{
u8 w = map_current_width();
u8 h = map_current_height();
u16 total;
u16 i;
if (w == 0 || h == 0) return 0;
// A valid origin is required: the fill leaves storage unchanged on invalid origins, but this loop still converts it.
range_fill_move(u->x, u->y, u->move, out_mask);
total = (u16)((u16)w * (u16)h);
i = 0;
while (i < total) {
out_mask[i] = (u8)((out_mask[i] == 0xFF) ? 0 : 1);
i++;
}
return 1;
}weighted_choice
從相對位元組權重清單選出項目索引。函式先加總權重,再將一次 rng16 取值對總和取餘數,找出包含結果的第一個累積區間。權重為 [1, 3, 6] 時,索引 0、1、2 分別對應區間 0、1–3、4–9。
語法
u8 weighted_choice(const u8* weights, u8 count);參數
weights指向 count 個可讀 u8 權重。陣列不會修改。總和為正時,略過零權重項目。count == 0 時不讀取指標,可為 null;否則須提供有效陣列。
count權重數量,範圍 0–255。最多 255 個權重各為 255,總和 65025 可放入函式的 u16 累加器。函式先掃描清單計算總和,再掃描至選中的區間。
回傳值
總和為正時,消耗兩次位元組取值,傳回 0 至 count−1 的索引。count 為零或所有權重皆零時,不取值而傳回零。此後備值無法與合法選中索引 0 區分;需要區分時,請自行檢查空清單或全零清單。
使用條件與限制
權重定義相對區間大小,不保證觀察到的百分比。rng16 輸出分布與對總和取餘數都會影響實際頻率。只要總和為正,即使只有一個非零權重項目,仍固定消耗兩次位元組取值。
這些呼叫共用持續保留的狀態。重現需要相同平台、種子與呼叫順序,包括其他輔助函式發出的呼叫。請在同一執行環境中設定種子與取值;這些檢查未證明從中斷處理常式並行使用的安全性。
GB 與 FC 使用不同演算法,不保證相同種子產生相同序列。它們是確定性的遊戲用產生器,不是密碼學亂數來源;測試檢查實作行為,不檢查統計品質或週期。
使用函式庫函式時,請引入 rpg.h,並隨遊戲編譯 lib/rng.c。__rng_seed 與 __rng8 內建函式由編譯器產生;只使用這兩者的程式不需要 rng.c 目的檔。
使用範例
weights[0]=1;weights[1]=3;weights[2]=6;
rng_seed(0x1234);
chosen=weighted_choice(weights,3); // 546 % 10 = 6 selects index 2.
empty=weighted_choice((const u8*)0,0); // No items: 0 is a fallback, not a chosen item.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例為三個項目指定權重 1、3、6。種子產生字組 546,餘數 6 位於索引 2 的區間 4–9,因此 WEIGHT INDEX 顯示 00002。EMPTY LIST 的 00000 是空清單後備值,不是成功選中項目 0。
完整程式在白底上顯示十進位結果:DMG 為黑字,CGB 為藍字。FAILED 必須為 00000。圖片為此範例實際的模擬器輸出。
驗證將每個案例的 32 個輸出與後續 8 次位元組取值,和獨立主機模型比對:GB 93 例、FC 18 例,涵蓋常數/執行期種子及 GB 範圍、機率、權重邊界。教學畫面在模擬器 240 影格後檢查。未測試實機與統計品質。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\rng_choices.c .\kitaqgb\lib\rng.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\rng_choices.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/rpg.h:203
Select an index from cumulative byte weights using a 16-bit random draw. A zero total, including an empty list, returns zero; callers must distinguish that case from a valid index. Modulo reduction can introduce a small bias.
kitaqgb/lib/rng.c:61
u8 weighted_choice(const u8* weights, u8 count)
{
u8 i;
u16 total;
u16 pick;
u16 acc;
// At most 255 byte weights sum to 65025, so this accumulator fits u16.
// A nonempty list requires count readable weight bytes.
total = 0;
i = 0;
while (i < count) {
total = (u16)(total + (u16)weights[i]);
i++;
}
if (total == 0) return 0;
pick = (u16)(rng16() % total);
acc = 0;
i = 0;
while (i < count) {
acc = (u16)(acc + (u16)weights[i]);
if (pick < acc) return i;
i++;
}
return (u8)(count - 1);
}scene.h — 場景註冊、切換與更新
透過呼叫場景表中的 enter、update、draw、exit 處理函式,切換標題畫面、遊戲畫面等場景。
scene_change
離開目前作用中的場景(若有),再進入指定場景。
語法
void scene_change(u8 scene_id);參數
scene_id要進入的場景索引,範圍為 0 到 count−1。
回傳值
無傳回值。
使用條件與限制
超出範圍的 ID 會被忽略。有效切換會依序執行 exit、儲存新 ID 並設定切換旗標,再執行 enter。即使選擇相同 ID,也會執行 exit 與 enter。 場景表由呼叫端持有。使用期間,請確保場景表及其一般函式指標指向的函式持續有效。空回呼會略過。不可在 enter/exit 回呼內遞迴切換場景或替換場景表。
請以預設 Legacy ABI 建置此完整範例。回呼使用函式指標呼叫,而編譯器在 --abi=stack 下會以不支援為由拒絕。使用別名時也有相同限制。
使用範例
scene_change(0);scene_change(9);result[11]=events;result[12]=scene_was_changed();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
程式啟用場景 0、忽略無效 ID 9,再執行 0→1 切換與 1→1 重新進入,以檢查回呼順序。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scene.h:20
Ignore invalid IDs; otherwise exit the current scene and enter the requested one. Selecting the current ID still performs exit/enter. Callbacks run synchronously.
kitaqgb/lib/scene.c:27
void scene_change(u8 scene_id)
{
SceneFunc fn;
if (scene_id >= scene_count) return;
// Exit/enter handlers must not recursively change scenes or replace this shared table.
if (scene_has_current != 0) {
fn = scene_table[(__safe_index u8)scene_current].exit;
if (fn != 0) fn();
}
scene_current = scene_id;
scene_has_current = 1;
scene_changed = 1;
fn = scene_table[(__safe_index u8)scene_current].enter;
if (fn != 0) fn();
}scene_draw
呼叫作用中場景的 draw 回呼一次。
語法
void scene_draw();回傳值
無傳回值。
使用條件與限制
沒有作用中的場景或 draw 回呼為空時,不執行任何動作。不會清除切換旗標。請在回呼或外層遊戲迴圈中安排顯示資料傳輸與影格時序。 場景表由呼叫端持有。使用期間,請確保場景表及其一般函式指標指向的函式持續有效。空回呼會略過。不可在 enter/exit 回呼內遞迴切換場景或替換場景表。
請以預設 Legacy ABI 建置此完整範例。回呼使用函式指標呼叫,而編譯器在 --abi=stack 下會以不支援為由拒絕。使用別名時也有相同限制。
使用範例
scene_draw();result[15]=events;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
事件序列包含場景 0 的 draw 所記錄的 12,以及場景 1 的 draw 所記錄的 22。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scene.h:25
Call the active scene's draw handler if one exists; no current scene is a no-op.
kitaqgb/lib/scene.c:60
void scene_draw()
{
SceneFunc fn;
if (scene_has_current == 0) return;
fn = scene_table[(__safe_index u8)scene_current].draw;
if (fn != 0) fn();
}scene_get_current
讀取儲存的目前場景 ID。
語法
u8 scene_get_current();回傳值
傳回儲存的 8 位元 ID;初始化後此值也為零。
使用條件與限制
僅憑傳回值為零,無法判斷場景 0 是否已啟用。請另行記錄初始化後是否已首次呼叫 scene_change()。
請以預設 Legacy ABI 建置此完整範例。回呼使用函式指標呼叫,而編譯器在 --abi=stack 下會以不支援為由拒絕。使用別名時也有相同限制。
使用範例
result[16]=scene_get_current();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例在啟用場景 0 後讀到零,切換至場景 1 後讀到一。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scene.h:27
Return the stored scene ID; zero is also returned before the first transition.
kitaqgb/lib/scene.c:70
u8 scene_get_current()
{
return scene_current;
}scene_init
註冊場景表,但尚不啟用任何場景。
語法
void scene_init(const SceneDef* scenes, u8 count);參數
scenes由
SceneDef項目組成的陣列,各項目包含 enter、update、draw 和 exit 回呼。count項目數量;為零時沒有有效的場景 ID。
回傳值
無傳回值。
使用條件與限制
將儲存的 ID 與切換旗標歸零。不會呼叫 enter;請使用 scene_change() 啟用場景。 場景表由呼叫端持有。使用期間,請確保場景表及其一般函式指標指向的函式持續有效。空回呼會略過。不可在 enter/exit 回呼內遞迴切換場景或替換場景表。
請以預設 Legacy ABI 建置此完整範例。回呼使用函式指標呼叫,而編譯器在 --abi=stack 下會以不支援為由拒絕。使用別名時也有相同限制。
使用範例
scene_init(scenes,2);scene_update();scene_draw();result[9]=events;result[10]=scene_was_changed();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
範例註冊兩個場景,確認啟用場景前呼叫 update 與 draw 不會產生事件。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scene.h:15
Attach the caller-owned scene table and clear current-scene state without invoking callbacks.
kitaqgb/lib/scene.c:10
void scene_init(const SceneDef* scenes, u8 count)
{
scene_table = scenes;
scene_count = count;
scene_current = 0;
scene_changed = 0;
scene_has_current = 0;
}scene_set_table
替換場景表,並清除作用中的場景。
語法
void scene_set_table(const SceneDef* scenes, u8 count);參數
scenes由
SceneDef項目組成的陣列,各項目包含 enter、update、draw 和 exit 回呼。count項目數量;為零時沒有有效的場景 ID。
回傳值
無傳回值。
使用條件與限制
像 scene_init() 一樣重設狀態,既不呼叫原場景的 exit 回呼,也不呼叫新場景的 enter 回呼。 場景表由呼叫端持有。使用期間,請確保場景表及其一般函式指標指向的函式持續有效。空回呼會略過。不可在 enter/exit 回呼內遞迴切換場景或替換場景表。
請以預設 Legacy ABI 建置此完整範例。回呼使用函式指標呼叫,而編譯器在 --abi=stack 下會以不支援為由拒絕。使用別名時也有相同限制。
使用範例
scene_set_table(scenes,2);result[23]=events;result[24]=scene_was_changed();scene_draw();result[25]=events;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
九個事件發生後替換場景表,事件數仍為九;切換旗標歸零,接著呼叫 draw 不會執行任何動作。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scene.h:17
Replace the table by resetting scene state; this does not call the old scene's exit handler.
kitaqgb/lib/scene.c:20
void scene_set_table(const SceneDef* scenes, u8 count)
{
scene_init(scenes, count);
}scene_update
呼叫作用中場景的 update 回呼一次。
語法
void scene_update();回傳值
無傳回值。
使用條件與限制
沒有作用中的場景時不執行任何動作。否則會在呼叫回呼前清除切換旗標,因此 update 內發生的切換仍可在回呼結束後透過旗標得知。 場景表由呼叫端持有。使用期間,請確保場景表及其一般函式指標指向的函式持續有效。空回呼會略過。不可在 enter/exit 回呼內遞迴切換場景或替換場景表。
請以預設 Legacy ABI 建置此完整範例。回呼使用函式指標呼叫,而編譯器在 --abi=stack 下會以不支援為由拒絕。使用別名時也有相同限制。
使用範例
scene_update();result[13]=events;result[14]=scene_was_changed();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
場景 0 的 update 會記錄事件 11。這次一般更新結束後,原本為 1 的切換旗標會變成 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scene.h:23
Clear the change flag before calling the active scene's update handler, so a transition made during that handler is visible afterward.
kitaqgb/lib/scene.c:49
void scene_update()
{
SceneFunc fn;
if (scene_has_current == 0) return;
scene_changed = 0;
fn = scene_table[(__safe_index u8)scene_current].update;
if (fn != 0) fn();
}scene_was_changed
讀取目前是否記錄了場景切換。
語法
u8 scene_was_changed();回傳值
切換旗標已設定時傳回 1,否則傳回 0。
使用條件與限制
讀取不會清除旗標。初始化、替換場景表,以及開始更新作用中場景時會清除旗標;無效的場景 ID 不會改變它。
請以預設 Legacy ABI 建置此完整範例。回呼使用函式指標呼叫,而編譯器在 --abi=stack 下會以不支援為由拒絕。使用別名時也有相同限制。
使用範例
result[17]=scene_was_changed();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
檢查切換後立即讀到 1、一般更新後讀到 0,以及替換場景表後讀到 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scene.h:29
Read the transition flag, which is cleared at the start of an active scene update.
kitaqgb/lib/scene.c:76
u8 scene_was_changed()
{
return scene_changed;
}scroll.h — 背景、視窗與分割捲動
控制背景/視窗的立即與緩衝捲動,以及最多八個光柵分割。請區分 getter 管理的目前值、即時硬體暫存器與待套用值。
Scroll_BgAdd
將帶正負號的位移加到追蹤中的背景座標,並立即套用。
語法
void Scroll_BgAdd(s8 dx, s8 dy);參數
dx帶正負號的水平像素位移,範圍為 −128 到 127。
dy帶正負號的垂直像素位移,範圍為 −128 到 127。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
不會等待。立即設定或加算操作會將受影響的待套用座標對同步為目前值,並清除其待更新旗標。即使只立即設定一個軸,也會取消同一座標對中另一軸的待套用值。 結果以 256 為模數回捲。加算以追蹤中的目前值為起點,不使用待套用值或暫時的光柵暫存器值。 此函式包裝 __scroll_bg_add。
使用範例
Scroll_BgAdd(-20,3);result[22]=M_SCX;result[23]=M_SCY;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
使用 Scroll 函式學習立即更新、暫存、提交、加算與顯示控制。提交會讓 BG X 從 250 變成 16,WX 從 23 變成 39。顯示後的視窗位元值為 32,隱藏後為 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scroll.h:73
Apply signed deltas to the byte-sized background-scroll coordinates.
kitaqgb/lib/scroll.c:41
void Scroll_BgAdd(s8 dx, s8 dy) { __scroll_bg_add(dx, dy); }Scroll_Flush
將待更新的背景及視窗座標套用至追蹤狀態與硬體,再清除待更新旗標。
語法
void Scroll_Flush();回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
沒有變更的座標對維持不變。不會遮罩中斷或等待 VBlank;請由呼叫端安排所需時序。 此函式包裝 __scroll_flush。
使用範例
Scroll_Flush();result[18]=M_SCX;result[19]=M_SCY;result[20]=M_WX;result[21]=M_WY;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
使用 Scroll 函式學習立即更新、暫存、提交、加算與顯示控制。提交會讓 BG X 從 250 變成 16,WX 從 23 變成 39。顯示後的視窗位元值為 32,隱藏後為 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scroll.h:70
Apply the buffered scroll/window state through the compiler runtime.
kitaqgb/lib/scroll.c:38
void Scroll_Flush() { __scroll_flush(); }Scroll_GetBgX
讀取程式追蹤中的目前背景水平捲動值。
語法
u8 Scroll_GetBgX();回傳值
傳回追蹤中的目前位元組值,範圍為 0–255。WX 包含硬體的七像素偏移。
使用條件與限制
這不是讀取硬體暫存器的操作。不包含尚未提交的緩衝值、直接寫入暫存器的值,以及光柵分割暫時套用的值。 此函式包裝 __scroll_bg_x_get。
使用範例
result[6]=Scroll_GetBgX();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
使用 Scroll 函式學習立即更新、暫存、提交、加算與顯示控制。提交會讓 BG X 從 250 變成 16,WX 從 23 變成 39。顯示後的視窗位元值為 32,隱藏後為 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scroll.h:50
Read the tracked current background X; this is not a direct SCX register read.
kitaqgb/lib/scroll.c:18
u8 Scroll_GetBgX() { return __scroll_bg_x_get(); }Scroll_GetBgY
讀取程式追蹤中的目前背景垂直捲動值。
語法
u8 Scroll_GetBgY();回傳值
傳回追蹤中的目前位元組值,範圍為 0–255。WX 包含硬體的七像素偏移。
使用條件與限制
這不是讀取硬體暫存器的操作。不包含尚未提交的緩衝值、直接寫入暫存器的值,以及光柵分割暫時套用的值。 此函式包裝 __scroll_bg_y_get。
使用範例
result[7]=Scroll_GetBgY();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
使用 Scroll 函式學習立即更新、暫存、提交、加算與顯示控制。提交會讓 BG X 從 250 變成 16,WX 從 23 變成 39。顯示後的視窗位元值為 32,隱藏後為 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scroll.h:52
Read the tracked current background Y; pending and raster-only values are excluded.
kitaqgb/lib/scroll.c:20
u8 Scroll_GetBgY() { return __scroll_bg_y_get(); }Scroll_GetWindowX
讀取程式追蹤中的目前視窗 WX 值。
語法
u8 Scroll_GetWindowX();回傳值
傳回追蹤中的目前位元組值,範圍為 0–255。WX 包含硬體的七像素偏移。
使用條件與限制
這不是讀取硬體暫存器的操作。不包含尚未提交的緩衝值、直接寫入暫存器的值,以及光柵分割暫時套用的值。 此函式包裝 __scroll_win_x_get。
使用範例
result[12]=Scroll_GetWindowX();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
使用 Scroll 函式學習立即更新、暫存、提交、加算與顯示控制。提交會讓 BG X 從 250 變成 16,WX 從 23 變成 39。顯示後的視窗位元值為 32,隱藏後為 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scroll.h:61
Read tracked current WX, including its seven-pixel offset; not a live hardware read.
kitaqgb/lib/scroll.c:29
u8 Scroll_GetWindowX() { return __scroll_win_x_get(); }Scroll_GetWindowY
讀取程式追蹤中的目前視窗 WY 值。
語法
u8 Scroll_GetWindowY();回傳值
傳回追蹤中的目前位元組值,範圍為 0–255。WX 包含硬體的七像素偏移。
使用條件與限制
這不是讀取硬體暫存器的操作。不包含尚未提交的緩衝值、直接寫入暫存器的值,以及光柵分割暫時套用的值。 此函式包裝 __scroll_win_y_get。
使用範例
result[13]=Scroll_GetWindowY();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
使用 Scroll 函式學習立即更新、暫存、提交、加算與顯示控制。提交會讓 BG X 從 250 變成 16,WX 從 23 變成 39。顯示後的視窗位元值為 32,隱藏後為 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scroll.h:63
Read tracked current WY; pending and raster-only values are excluded.
kitaqgb/lib/scroll.c:31
u8 Scroll_GetWindowY() { return __scroll_win_y_get(); }Scroll_Init
將背景捲動初始化為 (0,0),視窗位置初始化為 WX=7、WY=0。
語法
void Scroll_Init();回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
同步目前座標與待套用座標;不重設視窗顯示狀態或分割表。
使用範例
Scroll_Init();result[0]=M_SCX;result[1]=M_SCY;result[2]=M_WX;result[3]=M_WY;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
使用 Scroll 函式學習立即更新、暫存、提交、加算與顯示控制。提交會讓 BG X 從 250 變成 16,WX 從 23 變成 39。顯示後的視窗位元值為 32,隱藏後為 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scroll.h:42
Reset background scroll to zero and place the window at screen origin using hardware WX=7 and WY=0.
kitaqgb/lib/scroll.c:5
void Scroll_Init()
{
__scroll_bg_set(0, 0);
__scroll_win_set(7, 0);
}Scroll_SetBg
立即設定背景的兩個捲動座標。
語法
void Scroll_SetBg(u8 scx, u8 scy);參數
scx背景水平捲動量,為 0–255 像素;數值增加時背景向左移動。
scy背景垂直捲動量,為 0–255 像素;數值增加時背景向上移動。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
包裝 __scroll_bg_set:同步目前值、待套用值與硬體值,清除 BG 待更新旗標,且不等待 VBlank。
使用範例
Scroll_SetBg(8,16);result[28]=M_SCX;result[29]=M_SCY;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
使用 Scroll 函式學習立即更新、暫存、提交、加算與顯示控制。提交會讓 BG X 從 250 變成 16,WX 從 23 變成 39。顯示後的視窗位元值為 32,隱藏後為 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scroll.h:44
Write both hardware background-scroll bytes immediately.
kitaqgb/lib/scroll.c:12
void Scroll_SetBg(u8 scx, u8 scy) { __scroll_bg_set(scx, scy); }Scroll_SetBgBuffered
將背景的兩個捲動座標存為待提交值。
語法
void Scroll_SetBgBuffered(u8 scx, u8 scy);參數
scx背景水平捲動量,為 0–255 像素;數值增加時背景向左移動。
scy背景垂直捲動量,為 0–255 像素;數值增加時背景向上移動。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
不改變追蹤中的目前值或暫存器。請以 __scroll_flush 或 Scroll_Flush 套用;暫存待套用值本身不會等待 VBlank。 此函式包裝 __scroll_bg_set_buffered。
使用範例
Scroll_SetBgBuffered(16,24);result[14]=M_SCX;result[15]=Scroll_GetBgX();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
使用 Scroll 函式學習立即更新、暫存、提交、加算與顯示控制。提交會讓 BG X 從 250 變成 16,WX 從 23 變成 39。顯示後的視窗位元值為 32,隱藏後為 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scroll.h:66
Stage background-scroll values in the intrinsic buffer for a later flush.
kitaqgb/lib/scroll.c:34
void Scroll_SetBgBuffered(u8 scx, u8 scy) { __scroll_bg_set_buffered(scx, scy); }Scroll_SetBgX
立即設定背景水平捲動。
語法
void Scroll_SetBgX(u8 scx);參數
scx背景水平捲動量,為 0–255 像素;數值增加時背景向左移動。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
不會等待。立即設定或加算操作會將受影響的待套用座標對同步為目前值,並清除其待更新旗標。即使只立即設定一個軸,也會取消同一座標對中另一軸的待套用值。 此函式包裝 __scroll_bg_x_set。
使用範例
Scroll_SetBgX(250);result[4]=M_SCX;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
使用 Scroll 函式學習立即更新、暫存、提交、加算與顯示控制。提交會讓 BG X 從 250 變成 16,WX 從 23 變成 39。顯示後的視窗位元值為 32,隱藏後為 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scroll.h:46
Write horizontal background scroll while leaving vertical scroll unchanged.
kitaqgb/lib/scroll.c:14
void Scroll_SetBgX(u8 scx) { __scroll_bg_x_set(scx); }Scroll_SetBgY
立即設定背景垂直捲動。
語法
void Scroll_SetBgY(u8 scy);參數
scy背景垂直捲動量,為 0–255 像素;數值增加時背景向上移動。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
不會等待。立即設定或加算操作會將受影響的待套用座標對同步為目前值,並清除其待更新旗標。即使只立即設定一個軸,也會取消同一座標對中另一軸的待套用值。 此函式包裝 __scroll_bg_y_set。
使用範例
Scroll_SetBgY(2);result[5]=M_SCY;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
使用 Scroll 函式學習立即更新、暫存、提交、加算與顯示控制。提交會讓 BG X 從 250 變成 16,WX 從 23 變成 39。顯示後的視窗位元值為 32,隱藏後為 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scroll.h:48
Write vertical background scroll while leaving horizontal scroll unchanged.
kitaqgb/lib/scroll.c:16
void Scroll_SetBgY(u8 scy) { __scroll_bg_y_set(scy); }Scroll_SetWindow
立即設定視窗的 WX 與 WY。
語法
void Scroll_SetWindow(u8 wx, u8 wy);參數
wx原始 WX 位元組,範圍為 0–255;將所需畫面 X 座標加上 7。左邊緣使用 7。
wy視窗頂端的畫面 Y 像素位置,範圍為 0–255;可見的掃描列為 0–143。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
不會等待。立即設定或加算操作會將受影響的待套用座標對同步為目前值,並清除其待更新旗標。即使只立即設定一個軸,也會取消同一座標對中另一軸的待套用值。 此函式包裝 __scroll_win_set。
使用範例
Scroll_SetWindow(15,8);result[8]=M_WX;result[9]=M_WY;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
使用 Scroll 函式學習立即更新、暫存、提交、加算與顯示控制。提交會讓 BG X 從 250 變成 16,WX 從 23 變成 39。顯示後的視窗位元值為 32,隱藏後為 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scroll.h:55
Write raw hardware WX/WY values; callers add seven to a screen-space window X.
kitaqgb/lib/scroll.c:23
void Scroll_SetWindow(u8 wx, u8 wy) { __scroll_win_set(wx, wy); }Scroll_SetWindowBuffered
將視窗的兩個座標存為待提交值。
語法
void Scroll_SetWindowBuffered(u8 wx, u8 wy);參數
wx原始 WX 位元組,範圍為 0–255;將所需畫面 X 座標加上 7。左邊緣使用 7。
wy視窗頂端的畫面 Y 像素位置,範圍為 0–255;可見的掃描列為 0–143。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
不改變追蹤中的目前值或暫存器。請以 __scroll_flush 或 Scroll_Flush 套用;暫存待套用值本身不會等待 VBlank。 此函式包裝 __scroll_win_set_buffered。
使用範例
Scroll_SetWindowBuffered(39,32);result[16]=M_WX;result[17]=Scroll_GetWindowX();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
使用 Scroll 函式學習立即更新、暫存、提交、加算與顯示控制。提交會讓 BG X 從 250 變成 16,WX 從 23 變成 39。顯示後的視窗位元值為 32,隱藏後為 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scroll.h:68
Stage raw window-coordinate values for a later flush.
kitaqgb/lib/scroll.c:36
void Scroll_SetWindowBuffered(u8 wx, u8 wy) { __scroll_win_set_buffered(wx, wy); }Scroll_SetWindowX
僅立即設定視窗的原始 WX 座標。
語法
void Scroll_SetWindowX(u8 wx);參數
wx原始 WX 位元組,範圍為 0–255;將所需畫面 X 座標加上 7。左邊緣使用 7。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
不會等待。立即設定或加算操作會將受影響的待套用座標對同步為目前值,並清除其待更新旗標。即使只立即設定一個軸,也會取消同一座標對中另一軸的待套用值。 此函式包裝 __scroll_win_x_set。
使用範例
Scroll_SetWindowX(23);result[10]=M_WX;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
使用 Scroll 函式學習立即更新、暫存、提交、加算與顯示控制。提交會讓 BG X 從 250 變成 16,WX 從 23 變成 39。顯示後的視窗位元值為 32,隱藏後為 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scroll.h:57
Write raw hardware WX without converting a screen-space X coordinate.
kitaqgb/lib/scroll.c:25
void Scroll_SetWindowX(u8 wx) { __scroll_win_x_set(wx); }Scroll_SetWindowY
僅立即設定視窗的 WY 座標。
語法
void Scroll_SetWindowY(u8 wy);參數
wy視窗頂端的畫面 Y 像素位置,範圍為 0–255;可見的掃描列為 0–143。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
不會等待。立即設定或加算操作會將受影響的待套用座標對同步為目前值,並清除其待更新旗標。即使只立即設定一個軸,也會取消同一座標對中另一軸的待套用值。 此函式包裝 __scroll_win_y_set。
使用範例
Scroll_SetWindowY(16);result[11]=M_WY;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
使用 Scroll 函式學習立即更新、暫存、提交、加算與顯示控制。提交會讓 BG X 從 250 變成 16,WX 從 23 變成 39。顯示後的視窗位元值為 32,隱藏後為 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scroll.h:59
Write the window Y coordinate through the intrinsic.
kitaqgb/lib/scroll.c:27
void Scroll_SetWindowY(u8 wy) { __scroll_win_y_set(wy); }Scroll_SplitCommit
保存基本視窗顯示狀態,並啟動分割表中的第一個掃描線事件。
語法
void Scroll_SplitCommit();回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
共用表格可容納八筆項目。新增時不會立即套用或排序,超出容量的項目會被忽略。請在安全的影格邊界以 reset→push→commit 順序重建,並在事件間保留足夠間隔,讓處理函式能完成。中斷延遲會使排定的掃描線與第一個受影響像素不一定一致。 表格非空時,會在 IE 啟用 VBlank/STAT 並執行 EI。空表格會停用 LYC 來源,但不還原 IE 或 CPU 中斷狀態。 此函式包裝 __scroll_split_commit。
使用範例
Scroll_SplitCommit();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
使用 Scroll 包裝函式建立三個背景捲動帶。LY=64 與 104 的事件將 X 改為 8 與 16,使 24×16 矩形分別位於 (32,16)、(24,80)、(16,112)。圖片呈現各帶的位移差異。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_split_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_split_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scroll.h:92
Publish the pending split configuration through the compiler runtime.
kitaqgb/lib/scroll.c:66
void Scroll_SplitCommit() { __scroll_split_commit(); }Scroll_SplitPush
新增一筆在指定掃描線事件時改變背景捲動的分割項目。
語法
void Scroll_SplitPush(u8 ly, u8 scx, u8 scy);參數
ly掃描線事件編號;可見範圍使用 0–143,並須以遞增順序新增。若第一筆為零,會在 VBlank 期間套用。
scx背景水平捲動量,為 0–255 像素;數值增加時背景向左移動。
scy背景垂直捲動量,為 0–255 像素;數值增加時背景向上移動。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
共用表格可容納八筆項目。新增時不會立即套用或排序,超出容量的項目會被忽略。請在安全的影格邊界以 reset→push→commit 順序重建,並在事件間保留足夠間隔,讓處理函式能完成。中斷延遲會使排定的掃描線與第一個受影響像素不一定一致。 此函式包裝 __scroll_split_push。
使用範例
Scroll_SplitPush(64,8,0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
使用 Scroll 包裝函式建立三個背景捲動帶。LY=64 與 104 的事件將 X 改為 8 與 16,使 24×16 矩形分別位於 (32,16)、(24,80)、(16,112)。圖片呈現各帶的位移差異。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_split_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_split_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scroll.h:85
Append a background-scroll split directly. Use Raster_Push when caller-side scanline ordering and capacity validation are desired.
kitaqgb/lib/scroll.c:53
void Scroll_SplitPush(u8 ly, u8 scx, u8 scy) { __scroll_split_push(ly, scx, scy); }Scroll_SplitPushBgColor0
新增改變 CGB 背景調色盤 0 中色彩 0 的事件。
語法
void Scroll_SplitPushBgColor0(u8 ly, u16 rgb15);參數
ly掃描線事件編號;可見範圍使用 0–143,並須以遞增順序新增。若第一筆為零,會在 VBlank 期間套用。
rgb1515 位元 RGB555 色彩:紅色位於位元 0–4,綠色位於 5–9,藍色位於 10–14。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
僅限 CGB。透過擴充分割操作,使用八格分割表中的一格。調色盤寫入會等待可存取 PPU 的時段。在這個一般速度 CGB 範例中,LY=64/112 事件的效果從第 66/114 列開始可見。不可將事件所在列視為第一個顯示效果的列。
使用範例
Scroll_SplitPushBgColor0(0,0x7C00);Scroll_SplitPushBgColor0(64,0x001F);Scroll_SplitPushBgColor0(112,0x03E0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
在影格途中改變 CGB 背景色彩 0。一般速度下,此範例將第 0–65 列畫為藍色、66–113 列畫為紅色、114–143 列畫為綠色。事件排定於 0、64、112;中斷處理與調色盤存取會增加延遲。DMG 不提供這些彩色調色盤。

建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_split_color.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_split_color.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scroll.h:90
Reuse the two background-scroll fields to carry the low/high RGB15 bytes for a split whose operation flag selects background color zero.
kitaqgb/lib/scroll.c:61
void Scroll_SplitPushBgColor0(u8 ly, u16 rgb15)
{
__scroll_split_push_ex(ly, (u8)rgb15, (u8)(rgb15 >> 8), 0, 0, KQ_SCROLL_SPLIT_BG_COLOR0);
}Scroll_SplitPushEx
新增分割項目,以旗標選擇背景、視窗、顯示狀態或背景色彩 0 的操作。
語法
void Scroll_SplitPushEx(u8 ly, u8 scx, u8 scy, u8 wx, u8 wy, u8 flags);參數
ly掃描線事件編號;可見範圍使用 0–143,並須以遞增順序新增。若第一筆為零,會在 VBlank 期間套用。
scx背景水平捲動量,為 0–255 像素;數值增加時背景向左移動。
scy背景垂直捲動量,為 0–255 像素;數值增加時背景向上移動。
wx原始 WX 位元組,範圍為 0–255;將所需畫面 X 座標加上 7。左邊緣使用 7。
wy視窗頂端的畫面 Y 像素位置,範圍為 0–255;可見的掃描列為 0–143。
flags操作位元:BG=1、視窗位置=2、顯示=4、隱藏=8、CGB 背景調色盤 0/色彩 0=16。未知位元會被捨棄。色彩 0 模式將 scx/scy 改作 RGB15 的低位元組/高位元組。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
共用表格可容納八筆項目。新增時不會立即套用或排序,超出容量的項目會被忽略。請在安全的影格邊界以 reset→push→commit 順序重建,並在事件間保留足夠間隔,讓處理函式能完成。中斷延遲會使排定的掃描線與第一個受影響像素不一定一致。 顯示與隱藏位元同時設定時,以顯示為優先。色彩 0 功能僅限 CGB;與 BG 移動合用時,兩者共用相同的 scx/scy 位元組。 此函式包裝 __scroll_split_push_ex。
使用範例
Scroll_SplitPushEx(104,16,0,7,0,KQ_SCROLL_SPLIT_USE_BG|KQ_SCROLL_SPLIT_WIN_HIDE);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
使用 Scroll 包裝函式建立三個背景捲動帶。LY=64 與 104 的事件將 X 改為 8 與 16,使 24×16 矩形分別位於 (32,16)、(24,80)、(16,112)。圖片呈現各帶的位移差異。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_split_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_split_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scroll.h:87
Append an extended split with raw background/window fields and operation flags.
kitaqgb/lib/scroll.c:55
void Scroll_SplitPushEx(u8 ly, u8 scx, u8 scy, u8 wx, u8 wy, u8 flags)
{
__scroll_split_push_ex(ly, scx, scy, wx, wy, flags);
}Scroll_SplitReset
清除分割項目數與索引、停用分割處理,並清除 STAT 的 LYC 中斷啟用位元。
語法
void Scroll_SplitReset();回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
共用表格可容納八筆項目。新增時不會立即套用或排序,超出容量的項目會被忽略。請在安全的影格邊界以 reset→push→commit 順序重建,並在事件間保留足夠間隔,讓處理函式能完成。中斷延遲會使排定的掃描線與第一個受影響像素不一定一致。 不會清除表格中的位元組、清除 IE 或停用 CPU 中斷。 此函式包裝 __scroll_split_reset。
使用範例
Scroll_SplitReset();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
使用 Scroll 包裝函式建立三個背景捲動帶。LY=64 與 104 的事件將 X 改為 8 與 16,使 24×16 矩形分別位於 (32,16)、(24,80)、(16,112)。圖片呈現各帶的位移差異。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_split_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_split_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scroll.h:82
Clear the pending split table before building a new raster configuration.
kitaqgb/lib/scroll.c:50
void Scroll_SplitReset() { __scroll_split_reset(); }Scroll_WindowAdd
將帶正負號的位移加到追蹤中的視窗座標,並立即套用。
語法
void Scroll_WindowAdd(s8 dx, s8 dy);參數
dx帶正負號的水平像素位移,範圍為 −128 到 127。
dy帶正負號的垂直像素位移,範圍為 −128 到 127。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
不會等待。立即設定或加算操作會將受影響的待套用座標對同步為目前值,並清除其待更新旗標。即使只立即設定一個軸,也會取消同一座標對中另一軸的待套用值。 結果以 256 為模數回捲。加算以追蹤中的目前值為起點,不使用待套用值或暫時的光柵暫存器值。 此函式包裝 __scroll_win_add。
使用範例
Scroll_WindowAdd(4,-40);result[24]=M_WX;result[25]=M_WY;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
使用 Scroll 函式學習立即更新、暫存、提交、加算與顯示控制。提交會讓 BG X 從 250 變成 16,WX 從 23 變成 39。顯示後的視窗位元值為 32,隱藏後為 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scroll.h:75
Apply signed deltas to the byte-sized hardware window coordinates.
kitaqgb/lib/scroll.c:43
void Scroll_WindowAdd(s8 dx, s8 dy) { __scroll_win_add(dx, dy); }Scroll_WindowHide
清除 LCDC 的視窗位元,並將追蹤中的視窗顯示狀態設為隱藏。
語法
void Scroll_WindowHide();回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
不改變座標或圖塊映射選擇。要實際顯示,還需啟用 LCD 與背景/視窗功能,且視窗必須位於可見範圍內。 此函式包裝 __scroll_win_hide。
使用範例
Scroll_WindowHide();result[27]=M_LCDC&32;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
使用 Scroll 函式學習立即更新、暫存、提交、加算與顯示控制。提交會讓 BG X 從 250 變成 16,WX 從 23 變成 39。顯示後的視窗位元值為 32,隱藏後為 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scroll.h:79
Request that the window be hidden through the compiler intrinsic.
kitaqgb/lib/scroll.c:47
void Scroll_WindowHide() { __scroll_win_hide(); }Scroll_WindowShow
啟用 LCDC 的視窗位元,並將追蹤中的視窗顯示狀態設為顯示。
語法
void Scroll_WindowShow();回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
不改變座標或圖塊映射選擇。要實際顯示,還需啟用 LCD 與背景/視窗功能,且視窗必須位於可見範圍內。 此函式包裝 __scroll_win_show。
使用範例
Scroll_WindowShow();result[26]=M_LCDC&32;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
使用 Scroll 函式學習立即更新、暫存、提交、加算與顯示控制。提交會讓 BG X 從 250 變成 16,WX 從 23 變成 39。顯示後的視窗位元值為 32,隱藏後為 0。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k使用範例
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
相機位於 (8,16) 時,紅色 32×24 矩形出現在畫面 (24,16)。視窗在 (96,80) 顯示藍色 64×64 外框,並在 (112,96) 顯示綠色 16×16 正方形。DMG 上所有圖形皆為黑色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/scroll.h:77
Request window visibility through the compiler intrinsic.
kitaqgb/lib/scroll.c:45
void Scroll_WindowShow() { __scroll_win_show(); }slg.h — 棋盤、行動清單與復原
提供以位元組存值的棋盤、容量有限的走步清單及復原記錄堆疊。遊戲需組合這些操作,才能將走步或復原記錄套用到棋盤。
slg_board_clear
以指定值填滿棋盤上的所有格子。
語法
void slg_board_clear(SLGBoard* board, u8 value);參數
board要操作的
SLGBoard;初始化需要非 NULL 的儲存空間。value要儲存的位元組值;其意義由遊戲定義,例如棋子或地形種類。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
儲存空間由呼叫端提供。初始化不會配置或清除空間。棋盤座標以格子為單位。
使用範例
slg_board_clear(&board,0);result[1]=cells[0];result[2]=cells[11];這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例說明棋盤、走步清單與復原記錄各自的職責。棋盤初始化保留值 9;容量為兩筆的清單第三次新增會傳回 0。僅取出復原記錄時,棋盤值仍為 8;明確套用取出的記錄後才恢復為 7。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_board.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_board.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/slg.h:33
Fill every cell with value; a null board is ignored. A valid board must own enough accessible cell storage for its declared dimensions.
kitaqgb/lib/slg_board.c:36
void slg_board_clear(SLGBoard* board, u8 value)
{
u16 total;
u16 i;
u8* p;
if (board == 0) return;
total = (u16)((u16)board->width * (u16)board->height);
i = 0;
p = board->cells;
while (i < total) {
*p = value;
p++;
i++;
}
}slg_board_get
讀取一個格子;棋盤為 NULL 或座標超出範圍時傳回零。
語法
u8 slg_board_get(const SLGBoard* board, u8 x, u8 y);參數
board要操作的
SLGBoard;初始化需要非 NULL 的儲存空間。x格子欄號,由左至右從零起算;記錄走步時不檢查棋盤邊界。
y格子列號,由上至下從零起算;記錄走步時不檢查棋盤邊界。
回傳值
格子的位元組值;查詢無效時為零。僅憑零值無法區分空格子與無效座標。
使用條件與限制
儲存空間由呼叫端提供。初始化不會配置或清除空間。棋盤座標以格子為單位。
使用範例
result[3]=slg_board_get(&board,1,1);result[4]=slg_board_get(&board,4,1);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例說明棋盤、走步清單與復原記錄各自的職責。棋盤初始化保留值 9;容量為兩筆的清單第三次新增會傳回 0。僅取出復原記錄時,棋盤值仍為 8;明確套用取出的記錄後才恢復為 7。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_board.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_board.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/slg.h:36
Return zero for a null board or out-of-range coordinate; otherwise read the cell. Zero therefore cannot distinguish an invalid lookup from an empty cell.
kitaqgb/lib/slg_board.c:54
u8 slg_board_get(const SLGBoard* board, u8 x, u8 y)
{
u8* p;
if (board == 0) return 0;
if (x >= board->width || y >= board->height) return 0;
p = slg_cell_ptr((SLGBoard*)board, x, y);
return *p;
}slg_board_init
設定棋盤尺寸並連結格子陣列,保留陣列既有內容。
語法
void slg_board_init(SLGBoard* board, u8 width, u8 height, u8* cells);參數
board要操作的
SLGBoard;初始化需要非 NULL 的儲存空間。width棋盤寬度,以格子為單位,也是每列的步幅。
height棋盤的列數。
cells可寫入的列優先陣列,至少包含
width*height個格子位元組。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
儲存空間由呼叫端提供。初始化不會配置或清除空間。棋盤座標以格子為單位。
使用範例
cells[0]=9;slg_board_init(&board,4,3,cells);result[0]=slg_board_get(&board,0,0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例說明棋盤、走步清單與復原記錄各自的職責。棋盤初始化保留值 9;容量為兩筆的清單第三次新增會傳回 0。僅取出復原記錄時,棋盤值仍為 8;明確套用取出的記錄後才恢復為 7。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_board.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_board.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/slg.h:30
Attach width * height bytes of caller-owned cell storage without clearing it.
kitaqgb/lib/slg_board.c:27
void slg_board_init(SLGBoard* board, u8 width, u8 height, u8* cells)
{
board->width = width;
board->height = height;
board->cells = cells;
}slg_board_set
寫入棋盤內的一個有效格子;棋盤為 NULL 或座標超出範圍時忽略操作。
語法
void slg_board_set(SLGBoard* board, u8 x, u8 y, u8 value);參數
board要操作的
SLGBoard;初始化需要非 NULL 的儲存空間。x格子欄號,由左至右從零起算;記錄走步時不檢查棋盤邊界。
y格子列號,由上至下從零起算;記錄走步時不檢查棋盤邊界。
value要儲存的位元組值;其意義由遊戲定義,例如棋子或地形種類。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
儲存空間由呼叫端提供。初始化不會配置或清除空間。棋盤座標以格子為單位。
使用範例
slg_board_set(&board,1,1,7);slg_board_set(&board,4,1,9);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例說明棋盤、走步清單與復原記錄各自的職責。棋盤初始化保留值 9;容量為兩筆的清單第三次新增會傳回 0。僅取出復原記錄時,棋盤值仍為 8;明確套用取出的記錄後才恢復為 7。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_board.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_board.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/slg.h:38
Write a cell only when the board and coordinate are valid.
kitaqgb/lib/slg_board.c:64
void slg_board_set(SLGBoard* board, u8 x, u8 y, u8 value)
{
u8* p;
if (board == 0) return;
if (x >= board->width || y >= board->height) return;
p = slg_cell_ptr(board, x, y);
*p = value;
}slg_move_list_clear
重設走步筆數,不清除已儲存的記錄。
語法
void slg_move_list_clear(SLGMoveList* list);參數
list要操作的走步清單;初始化需要非 NULL 指標。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
儲存空間由呼叫端提供。初始化不會配置或清除空間。棋盤座標以格子為單位。
使用範例
slg_move_list_clear(&moves);result[10]=moves.count;result[11]=move_data[0].value;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例說明棋盤、走步清單與復原記錄各自的職責。棋盤初始化保留值 9;容量為兩筆的清單第三次新增會傳回 0。僅取出復原記錄時,棋盤值仍為 8;明確套用取出的記錄後才恢復為 7。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_board.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_board.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/slg.h:42
Forget the moves without erasing their storage; a null list is ignored.
kitaqgb/lib/slg_board.c:83
void slg_move_list_clear(SLGMoveList* list)
{
if (list == 0) return;
list->count = 0;
}slg_move_list_init
連結走步記錄的儲存空間及容量,將筆數設為零。
語法
void slg_move_list_init(SLGMoveList* list, SLGMove* items, u8 capacity);參數
list要操作的走步清單;初始化需要非 NULL 指標。
items由呼叫端持有的陣列,至少能容納
capacity筆SLGMove記錄。capacity最大記錄筆數;為零時不可新增。每筆記錄包含三個位元組:x、y 和值。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
儲存空間由呼叫端提供。初始化不會配置或清除空間。棋盤座標以格子為單位。
使用範例
slg_move_list_init(&moves,move_data,2);result[5]=moves.count;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例說明棋盤、走步清單與復原記錄各自的職責。棋盤初始化保留值 9;容量為兩筆的清單第三次新增會傳回 0。僅取出復原記錄時,棋盤值仍為 8;明確套用取出的記錄後才恢復為 7。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_board.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_board.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/slg.h:40
Attach caller-owned move storage and reset the list length.
kitaqgb/lib/slg_board.c:75
void slg_move_list_init(SLGMoveList* list, SLGMove* items, u8 capacity)
{
list->items = items;
list->capacity = capacity;
list->count = 0;
}slg_move_list_push
將座標與值新增至走步清單,不修改棋盤。
語法
u8 slg_move_list_push(SLGMoveList* list, u8 x, u8 y, u8 value);參數
list要操作的走步清單;初始化需要非 NULL 指標。
x格子欄號,由左至右從零起算;記錄走步時不檢查棋盤邊界。
y格子列號,由上至下從零起算;記錄走步時不檢查棋盤邊界。
value要儲存的位元組值;其意義由遊戲定義,例如棋子或地形種類。
回傳值
新增成功為 1;傳入 NULL 或空間已滿時為 0。失敗不會改變筆數與既有記錄。
使用條件與限制
儲存空間由呼叫端提供。初始化不會配置或清除空間。棋盤座標以格子為單位。
使用範例
result[6]=slg_move_list_push(&moves,1,1,7);result[7]=slg_move_list_push(&moves,2,1,8);result[8]=slg_move_list_push(&moves,3,1,9);result[9]=moves.count;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例說明棋盤、走步清單與復原記錄各自的職責。棋盤初始化保留值 9;容量為兩筆的清單第三次新增會傳回 0。僅取出復原記錄時,棋盤值仍為 8;明確套用取出的記錄後才恢復為 7。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_board.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_board.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/slg.h:45
Append coordinates and a value to the bounded move list. Return zero on a null/full list without replacing any existing move.
kitaqgb/lib/slg_board.c:91
u8 slg_move_list_push(SLGMoveList* list, u8 x, u8 y, u8 value)
{
SLGMove* move;
if (list == 0) return 0;
if (list->count >= list->capacity) return 0;
move = &list->items[(__safe_index u8)list->count];
move->x = x;
move->y = y;
move->value = value;
list->count++;
return 1;
}slg_undo_init
連結復原記錄的儲存空間及容量,從空堆疊開始。
語法
void slg_undo_init(SLGUndoStack* stack, SLGMove* items, u8 capacity);參數
stack要操作的復原堆疊;初始化需要非 NULL 指標。
items由呼叫端持有的陣列,至少能容納
capacity筆SLGMove記錄。capacity最大記錄筆數;為零時不可新增。每筆記錄包含三個位元組:x、y 和值。
回傳值
無傳回值。本項說明受影響的狀態及其生效時機。
使用條件與限制
儲存空間由呼叫端提供。初始化不會配置或清除空間。棋盤座標以格子為單位。
使用範例
slg_undo_init(&undo,undo_data,2);result[12]=undo.count;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例說明棋盤、走步清單與復原記錄各自的職責。棋盤初始化保留值 9;容量為兩筆的清單第三次新增會傳回 0。僅取出復原記錄時,棋盤值仍為 8;明確套用取出的記錄後才恢復為 7。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_board.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_board.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/slg.h:47
Attach caller-owned undo records and initialize an empty stack.
kitaqgb/lib/slg_board.c:106
void slg_undo_init(SLGUndoStack* stack, SLGMove* items, u8 capacity)
{
stack->items = items;
stack->capacity = capacity;
stack->count = 0;
}slg_undo_pop
取出並移除最新的復原記錄;由呼叫端將其套用至棋盤。
語法
u8 slg_undo_pop(SLGUndoStack* stack, SLGMove* out_move);參數
stack要操作的復原堆疊;初始化需要非 NULL 指標。
out_move取出記錄的存放位置;為 NULL 時不複製,直接丟棄該記錄。
回傳值
成功取出記錄時為 1;堆疊為 NULL 或為空時為 0。空堆疊不會改變輸出內容。
使用條件與限制
儲存空間由呼叫端提供。初始化不會配置或清除空間。棋盤座標以格子為單位。
使用範例
result[15]=slg_undo_pop(&undo,&old);result[16]=old.value;result[17]=slg_board_get(&board,1,1);slg_undo_pop(&undo,&old);slg_board_set(&board,old.x,old.y,old.value);result[18]=slg_board_get(&board,1,1);result[19]=slg_undo_pop(&undo,&old);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例說明棋盤、走步清單與復原記錄各自的職責。棋盤初始化保留值 9;容量為兩筆的清單第三次新增會傳回 0。僅取出復原記錄時,棋盤值仍為 8;明確套用取出的記錄後才恢復為 7。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_board.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_board.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/slg.h:53
Remove the newest undo record and optionally copy it out. A null output still discards the record; a null or empty stack returns zero.
kitaqgb/lib/slg_board.c:128
u8 slg_undo_pop(SLGUndoStack* stack, SLGMove* out_move)
{
if (stack == 0) return 0;
if (stack->count == 0) return 0;
stack->count--;
if (out_move != 0) {
out_move->x = stack->items[stack->count].x;
out_move->y = stack->items[stack->count].y;
out_move->value = stack->items[stack->count].value;
}
return 1;
}slg_undo_push
將格子的先前值推入復原堆疊,不修改棋盤。
語法
u8 slg_undo_push(SLGUndoStack* stack, u8 x, u8 y, u8 old_value);參數
stack要操作的復原堆疊;初始化需要非 NULL 指標。
x格子欄號,由左至右從零起算;記錄走步時不檢查棋盤邊界。
y格子列號,由上至下從零起算;記錄走步時不檢查棋盤邊界。
old_value格子先前的位元組值;函式不會自動從棋盤讀取此值。
回傳值
新增成功為 1;傳入 NULL 或空間已滿時為 0。失敗不會改變筆數與既有記錄。
使用條件與限制
儲存空間由呼叫端提供。初始化不會配置或清除空間。棋盤座標以格子為單位。
使用範例
result[13]=slg_undo_push(&undo,1,1,slg_board_get(&board,1,1));slg_board_set(&board,1,1,8);slg_undo_push(&undo,1,1,8);result[14]=slg_undo_push(&undo,0,0,9);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
此範例說明棋盤、走步清單與復原記錄各自的職責。棋盤初始化保留值 9;容量為兩筆的清單第三次新增會傳回 0。僅取出復原記錄時,棋盤值仍為 8;明確套用取出的記錄後才恢復為 7。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_board.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_board.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/slg.h:50
Record a cell's previous value for later undo. Return zero if the stack is null or full; this function does not change the board itself.
kitaqgb/lib/slg_board.c:115
u8 slg_undo_push(SLGUndoStack* stack, u8 x, u8 y, u8 old_value)
{
if (stack == 0) return 0;
if (stack->count >= stack->capacity) return 0;
stack->items[stack->count].x = x;
stack->items[stack->count].y = y;
stack->items[stack->count].value = old_value;
stack->count++;
return 1;
}sprite.h — OBJ 配置、定位、組合精靈與動畫
精靈是可移動的硬體圖形,通常為 8×8 或 8×16 像素,由物件屬性記憶體 OAM 的項目描述。先分配欄位,在工作副本中設定位置、圖塊與屬性,再進行傳輸。複合精靈將多個欄位組成一個物件。GB 有 40 個欄位,每條掃描線最多 10 個;FC 有 64 個,每條掃描線最多 8 個。
GB 屬性:位元 4 選擇 DMG 的 OBP1;位元 5/6 控制 X/Y 翻轉;位元 7 將精靈置於非零背景色編號之後。CGB 的位元 0..2 選擇物件調色盤,位元 3 選擇圖塊資料 VRAM 區塊;DMG 調色盤選擇位元不用於原生 CGB 色彩。
範例使用完整的 GB 精靈函式庫。定義 KQ_SPRITE_MINIMAL_RUNTIME 後,sprite.c 不再包含 sprite_free、sprite_set_pos、sprite_count_used、兩個掃描線查詢函式、metasprite_draw 與 anim_update。需要這些函式時請勿定義該巨集。
anim_update
推進 SpriteAnim 計時器並傳回選取的圖塊編號。每呼叫 ticks_per_frame 次就切換到下一個連續圖塊,經過 frame_count 影格後回到首格。呼叫端透過 sprite_set_tile 套用傳回值。
語法
u8 anim_update(SpriteAnim* anim);參數
anim可寫入的 SpriteAnim 狀態,包含 first_tile、frame_count、frame、ticks 與 ticks_per_frame。計數非零時,frame 應小於 frame_count,ticks 應小於 ticks_per_frame。
回傳值
選取的 8 位元圖塊編號;狀態指標為空時傳回 0。函式不寫入 OAM。
使用條件與限制
frame_count 為零時不推進,直接傳回 first_tile;ticks_per_frame 為零時凍結目前影格。計時器依呼叫次數而非影像影格推進。圖塊編號在 256 處循環,8×16 模式下也不會隔一個編號遞增。
範例使用完整的 GB 精靈函式庫。定義 KQ_SPRITE_MINIMAL_RUNTIME 後,sprite.c 不再包含 sprite_free、sprite_set_pos、sprite_count_used、兩個掃描線查詢函式、metasprite_draw 與 anim_update。需要這些函式時請勿定義該巨集。
使用範例
sprite_example_animation.first_tile=128;sprite_example_animation.frame_count=2;
sprite_example_animation.frame=0;sprite_example_animation.ticks=0;
sprite_example_animation.ticks_per_frame=2;
sprite_example_expect(anim_update(&sprite_example_animation)==128);
tile=anim_update(&sprite_example_animation);
sprite_example_expect(tile==129);sprite_set_tile(5,tile);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
設定 first_tile=128、兩影格、每影格兩次呼叫後,第一次更新傳回箭頭圖塊 128,第二次傳回正方形圖塊 129。ANIMATION 旁的正方形可確認傳回值已套用至 OAM。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/sprite.h:86
Advance animation ticks/frame with wrapping frame selection and return the resulting tile. Zero ticks-per-frame freezes animation; null state returns zero.
kitaqgb/lib/sprite.c:211
u8 anim_update(SpriteAnim* anim)
{
if (anim == 0) return 0;
if (anim->frame_count == 0) return anim->first_tile;
if (anim->ticks_per_frame == 0) return (u8)(anim->first_tile + anim->frame);
anim->ticks++;
if (anim->ticks >= anim->ticks_per_frame) {
anim->ticks = 0;
anim->frame++;
if (anim->frame >= anim->frame_count) anim->frame = 0;
}
return (u8)(anim->first_tile + anim->frame);
}metasprite_draw
此 API 在本機版中的差異,請參閱 2026-10-03 差異與驗證。
將指定數量的精靈零件放入連續欄位。每個零件包含有號偏移、圖塊與屬性。函式啟用空閒欄位、覆寫已啟用欄位,並在欄位上限處停止。
語法
u8 metasprite_draw(u8 first_id, u8 x, u8 y, const MetaSpritePart* parts, u8 count);參數
first_id欄位編號,範圍為 0..SPRITE_MAX-1;預設 GB 為 0..39,FC 為 0..63。超出範圍的編號會被忽略。
x以像素為單位的橫向位置,使用無號位元組表示,並非圖塊座標。
y畫面 Y 座標,單位為像素。GB 包裝函式會加上 16 再寫入 OAM。
parts至少含有 count 個可讀 MetaSpritePart 的陣列。每個 4 位元組記錄依序為有號 dx/dy、圖塊與屬性,沒有結束標記。
count零件數量,以無號位元組表示。為零時不寫入;連續欄位達到 SPRITE_MAX 時,只寫入此前能容納的零件。
回傳值
傳回實際寫入的零件數,範圍為 0..count。可藉此判斷是否因欄位上限而截斷。
使用條件與限制
位置、圖塊、屬性與隱藏操作只修改工作副本,不會分配欄位,也不立即更新硬體 OAM。完成一影格的修改後,用 sprite_flush_oam 傳輸。
將有號位元組偏移加到基準座標後,結果以 8 位元循環。整個呼叫期間零件陣列必須可讀。已啟用的欄位也會被覆寫,函式不會保護其他物件使用的欄位。
範例使用完整的 GB 精靈函式庫。定義 KQ_SPRITE_MINIMAL_RUNTIME 後,sprite.c 不再包含 sprite_free、sprite_set_pos、sprite_count_used、兩個掃描線查詢函式、metasprite_draw 與 anim_update。需要這些函式時請勿定義該巨集。
使用範例
sprite_example_expect(metasprite_draw(10,88,SPRITE_EXAMPLE_Y(64),sprite_example_pair,2)==2);
sprite_example_expect(sprite_count_used()==9); // Sparse IDs count actual active slots.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
初始化後分配數為零。八次分配傳回編號 0..7。隱藏欄位 6 後仍為 8;兩次釋放欄位 7 後為 7;在 10 與 11 放置兩個零件後增至 9。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/sprite.h:83
Place consecutive parts, counting each newly activated slot once. Existing active slots are overwritten without increasing the allocation count. Return the number written; an invalid first slot or zero count writes nothing.
kitaqgb/lib/sprite.c:191
u8 metasprite_draw(u8 first_id, u8 x, u8 y, const MetaSpritePart* parts, u8 count)
{
u8 i = 0;
while (i < count) {
u8 id = (u8)(first_id + i);
if (id >= SPRITE_MAX) return i;
if (kq_sprite_active[id] == 0) {
kq_sprite_active[id] = 1;
kq_sprite_used = (u8)(kq_sprite_used + 1);
}
sprite_set_pos(id, (u8)(x + parts[i].dx), (u8)(y + parts[i].dy));
sprite_set_tile(id, parts[i].tile);
sprite_set_flags(id, parts[i].flags);
i++;
}
return count;
}sprite_alloc
分配第一個空閒精靈欄位,並先將其隱藏。隱藏不會解除分配;顯示前請設定位置、圖塊與屬性。
語法
u8 sprite_alloc();回傳值
傳回分配的欄位編號;全部已用時傳回 0xFF。
使用條件與限制
位置、圖塊、屬性與隱藏操作只修改工作副本,不會分配欄位,也不立即更新硬體 OAM。完成一影格的修改後,用 sprite_flush_oam 傳輸。
範例使用完整的 GB 精靈函式庫。定義 KQ_SPRITE_MINIMAL_RUNTIME 後,sprite.c 不再包含 sprite_free、sprite_set_pos、sprite_count_used、兩個掃描線查詢函式、metasprite_draw 與 anim_update。需要這些函式時請勿定義該巨集。
使用範例
for(i=0;i<8;i++) sprite_example_expect(sprite_alloc()==i);
sprite_example_expect(sprite_count_used()==8);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
初始化後分配數為零。八次分配傳回編號 0..7。隱藏欄位 6 後仍為 8;兩次釋放欄位 7 後為 7;在 10 與 11 放置兩個零件後增至 9。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/sprite.h:53
Claim the first free slot, hide it, and return its ID; return 0xFF when full. Previously stored tile/flag bytes are retained until the caller replaces them.
kitaqgb/lib/sprite.c:60
u8 sprite_alloc()
{
u8 i = 0;
while (i < SPRITE_MAX) {
if (kq_sprite_active[i] == 0) {
kq_sprite_active[i] = 1;
kq_sprite_used++;
sprite_hide(i);
return i;
}
i++;
}
return 0xFF;
}sprite_count_used
傳回已分配欄位數,包括隱藏的精靈與由 metasprite_draw 啟用的欄位。這是分配數量,並非畫面上的可見數量。
語法
u8 sprite_count_used();回傳值
0 到 SPRITE_MAX 之間的無號位元組。
使用條件與限制
範例使用完整的 GB 精靈函式庫。定義 KQ_SPRITE_MINIMAL_RUNTIME 後,sprite.c 不再包含 sprite_free、sprite_set_pos、sprite_count_used、兩個掃描線查詢函式、metasprite_draw 與 anim_update。需要這些函式時請勿定義該巨集。
使用範例
sprite_example_expect(sprite_count_used()==9); // After hiding, freeing and drawing the pair.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
初始化後分配數為零。八次分配傳回編號 0..7。隱藏欄位 6 後仍為 8;兩次釋放欄位 7 後為 7;在 10 與 11 放置兩個零件後增至 9。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/sprite.h:73
Return the number of active slots, including slots activated by metasprite_draw. Hidden allocated slots remain active until sprite_free releases them.
kitaqgb/lib/sprite.c:148
u8 sprite_count_used()
{
return kq_sprite_used;
}sprite_flush_oam
等待 VBlank,再透過 sprite_flush_oam_now 傳輸 OAM 工作副本。
語法
void sprite_flush_oam();回傳值
無(void)。
使用條件與限制
GB 常式在 HRAM 中執行 DMA 程式碼,從對齊的 OAM 工作副本複製 160 位元組。傳輸期間停用中斷,結束後一律啟用中斷,不會恢復呼叫前可能停用的狀態。
範例使用完整的 GB 精靈函式庫。定義 KQ_SPRITE_MINIMAL_RUNTIME 後,sprite.c 不再包含 sprite_free、sprite_set_pos、sprite_count_used、兩個掃描線查詢函式、metasprite_draw 與 anim_update。需要這些函式時請勿定義該巨集。
使用範例
while(1) { sprite_flush_oam(); } // Transfer prepared sprites at the next frame boundary.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/sprite.h:70
Wait for VBlank, then transfer shadow OAM using the immediate DMA routine.
kitaqgb/lib/sprite.c:139
void sprite_flush_oam()
{
__wait_vblank();
sprite_flush_oam_now();
}sprite_flush_oam_now
立即將 OAM 工作副本傳輸至硬體。函式不等待安全的顯示時段,呼叫端須安排執行時機。
語法
void sprite_flush_oam_now();回傳值
無(void)。
使用條件與限制
GB 常式在 HRAM 中執行 DMA 程式碼,從對齊的 OAM 工作副本複製 160 位元組。傳輸期間停用中斷,結束後一律啟用中斷,不會恢復呼叫前可能停用的狀態。
範例使用完整的 GB 精靈函式庫。定義 KQ_SPRITE_MINIMAL_RUNTIME 後,sprite.c 不再包含 sprite_free、sprite_set_pos、sprite_count_used、兩個掃描線查詢函式、metasprite_draw 與 anim_update。需要這些函式時請勿定義該巨集。
使用範例
// Rendering is disabled here; all shadow entries have been prepared.
sprite_flush_oam_now();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/sprite.h:68
Install the HRAM stub lazily and execute OAM DMA with interrupts disabled. This routine does not wait for VBlank and always enables interrupts afterward; it does not restore the caller's previous interrupt-enable state.
kitaqgb/lib/sprite.c:122
void sprite_flush_oam_now()
{
SpriteDmaRoutine dma;
if (kq_sprite_dma_ready == 0) {
sprite_install_dma_stub();
}
dma = (SpriteDmaRoutine)kq_sprite_dma_stub;
__asm {
DI
}
dma();
__asm {
EI
}
}sprite_free
釋放已分配的欄位、將其隱藏,並把使用數減一。編號超出範圍或欄位已空閒時不執行操作。
語法
void sprite_free(u8 id);參數
id欄位編號,範圍為 0..SPRITE_MAX-1;預設 GB 為 0..39,FC 為 0..63。超出範圍的編號會被忽略。
回傳值
無(void)。
使用條件與限制
位置、圖塊、屬性與隱藏操作只修改工作副本,不會分配欄位,也不立即更新硬體 OAM。完成一影格的修改後,用 sprite_flush_oam 傳輸。
範例使用完整的 GB 精靈函式庫。定義 KQ_SPRITE_MINIMAL_RUNTIME 後,sprite.c 不再包含 sprite_free、sprite_set_pos、sprite_count_used、兩個掃描線查詢函式、metasprite_draw 與 anim_update。需要這些函式時請勿定義該巨集。
使用範例
sprite_free(7);sprite_free(7);
sprite_example_expect(sprite_count_used()==7); // Repeated release is ignored.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
初始化後分配數為零。八次分配傳回編號 0..7。隱藏欄位 6 後仍為 8;兩次釋放欄位 7 後為 7;在 10 與 11 放置兩個零件後增至 9。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/sprite.h:55
Release an allocated valid slot and hide it. Repeated frees do not decrement the count.
kitaqgb/lib/sprite.c:78
void sprite_free(u8 id)
{
if (sprite_valid(id) == 0) return;
if (kq_sprite_active[id] == 0) return;
kq_sprite_active[id] = 0;
if (kq_sprite_used != 0) kq_sprite_used--;
sprite_hide(id);
}sprite_hide
藉由修改工作副本中的位置來隱藏精靈。分配狀態、圖塊與屬性維持不變,因此重新設定可見位置即可顯示,不必再次分配。
語法
void sprite_hide(u8 id);參數
id欄位編號,範圍為 0..SPRITE_MAX-1;預設 GB 為 0..39,FC 為 0..63。超出範圍的編號會被忽略。
回傳值
無(void)。
使用條件與限制
位置、圖塊、屬性與隱藏操作只修改工作副本,不會分配欄位,也不立即更新硬體 OAM。完成一影格的修改後,用 sprite_flush_oam 傳輸。
範例使用完整的 GB 精靈函式庫。定義 KQ_SPRITE_MINIMAL_RUNTIME 後,sprite.c 不再包含 sprite_free、sprite_set_pos、sprite_count_used、兩個掃描線查詢函式、metasprite_draw 與 anim_update。需要這些函式時請勿定義該巨集。
使用範例
sprite_hide(6);
sprite_example_expect(sprite_count_used()==8); // Hiding retains allocation.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
初始化後分配數為零。八次分配傳回編號 0..7。隱藏欄位 6 後仍為 8;兩次釋放欄位 7 後為 7;在 10 與 11 放置兩個零件後增至 9。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/sprite.h:64
Move a valid shadow slot off screen without freeing it.
kitaqgb/lib/sprite.c:112
void sprite_hide(u8 id)
{
if (sprite_valid(id) == 0) return;
kq_sprite_oam[id].y = 0;
kq_sprite_oam[id].x = 0;
}sprite_init
重設精靈分配狀態,並在 OAM 工作副本中隱藏所有欄位。軟體記錄的高度設為 8 像素;硬體精靈尺寸與 OAM 傳輸須另外設定。
語法
void sprite_init();回傳值
無(void)。
使用條件與限制
GB 初始化會清除每個工作項目的全部 4 位元組,並重設 HRAM DMA 常式的安裝狀態。除非自訂 DMA 來源仍提供完整的 160 位元組,否則請維持預設 SPRITE_MAX=40。
範例使用完整的 GB 精靈函式庫。定義 KQ_SPRITE_MINIMAL_RUNTIME 後,sprite.c 不再包含 sprite_free、sprite_set_pos、sprite_count_used、兩個掃描線查詢函式、metasprite_draw 與 anim_update。需要這些函式時請勿定義該巨集。
使用範例
sprite_init();
sprite_example_expect(sprite_count_used()==0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
初始化後分配數為零。八次分配傳回編號 0..7。隱藏欄位 6 後仍為 8;兩次釋放欄位 7 後為 7;在 10 與 11 放置兩個零件後增至 9。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/sprite.h:50
Clear allocation and shadow OAM state and reset the DMA-stub installation flag. The default height is eight pixels; the hardware display mode is configured elsewhere.
kitaqgb/lib/sprite.c:22
void sprite_init()
{
u8 i = 0;
kq_sprite_used = 0;
kq_sprite_height = 8;
kq_sprite_dma_ready = 0;
while (i < SPRITE_MAX) {
kq_sprite_active[i] = 0;
kq_sprite_oam[i].y = 0;
kq_sprite_oam[i].x = 0;
kq_sprite_oam[i].tile = 0;
kq_sprite_oam[i].flags = 0;
i++;
}
}sprite_max_scanline_count
根據記錄的縱向位置與 kq_sprite_height,估算可見範圍內同一掃描線上最多重疊多少個已啟用精靈。
語法
u8 sprite_max_scanline_count();回傳值
0 到 SPRITE_MAX 之間的無號位元組。
使用條件與限制
將 kq_sprite_height 設為硬體高度 8 或 16。估算不考慮透明像素、橫向可見範圍或硬體優先順序。FC 讀取函式庫記錄的座標,因此直接用 OAM 內建函式更改的位置不會反映在估算中。
範例使用完整的 GB 精靈函式庫。定義 KQ_SPRITE_MINIMAL_RUNTIME 後,sprite.c 不再包含 sprite_free、sprite_set_pos、sprite_count_used、兩個掃描線查詢函式、metasprite_draw 與 anim_update。需要這些函式時請勿定義該巨集。
使用範例
sprite_example_expect(sprite_max_scanline_count()==SPRITE_EXAMPLE_LINE_COUNT);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/sprite.h:79
Estimate the largest overlap of active, non-hidden shadow sprites across visible scanlines using the configured sprite height. This is a software overlap count, not a rendered-pixel or hardware-priority simulation.
kitaqgb/lib/sprite.c:158
u8 sprite_max_scanline_count()
{
u8 line = 0;
u8 best = 0;
while (line < 144) {
u8 i = 0;
u8 count = 0;
u8 ly_oam = (u8)(line + 16);
while (i < SPRITE_MAX) {
u8 sy = kq_sprite_oam[i].y;
if (kq_sprite_active[i] != 0 && sy != 0) {
if (ly_oam >= sy && ly_oam < (u8)(sy + kq_sprite_height)) {
count++;
}
}
i++;
}
if (count > best) best = count;
line++;
}
return best;
}sprite_set_flags
替換整個精靈屬性位元組。組合對應平台的旗標常數以選擇翻轉、調色盤與背景優先順序;未指定的位元會清零。
語法
void sprite_set_flags(u8 id, u8 flags);參數
id欄位編號,範圍為 0..SPRITE_MAX-1;預設 GB 為 0..39,FC 為 0..63。超出範圍的編號會被忽略。
flags使用本平台 SPRITE_FLAG_* 常數組成的完整屬性位元組。多個旗標透過位元 OR(|)組合。
回傳值
無(void)。
使用條件與限制
位置、圖塊、屬性與隱藏操作只修改工作副本,不會分配欄位,也不立即更新硬體 OAM。完成一影格的修改後,用 sprite_flush_oam 傳輸。
GB 屬性:位元 4 選擇 DMG 的 OBP1;位元 5/6 控制 X/Y 翻轉;位元 7 將精靈置於非零背景色編號之後。CGB 的位元 0..2 選擇物件調色盤,位元 3 選擇圖塊資料 VRAM 區塊;DMG 調色盤選擇位元不用於原生 CGB 色彩。
範例使用完整的 GB 精靈函式庫。定義 KQ_SPRITE_MINIMAL_RUNTIME 後,sprite.c 不再包含 sprite_free、sprite_set_pos、sprite_count_used、兩個掃描線查詢函式、metasprite_draw 與 anim_update。需要這些函式時請勿定義該巨集。
使用範例
sprite_set_flags(1,SPRITE_FLAG_XFLIP);
sprite_set_flags(2,SPRITE_FLAG_YFLIP);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/sprite.h:62
Replace a valid shadow slot's complete hardware attribute byte.
kitaqgb/lib/sprite.c:105
void sprite_set_flags(u8 id, u8 flags)
{
if (sprite_valid(id) == 0) return;
kq_sprite_oam[id].flags = flags;
}sprite_set_pos
以畫面像素座標修改 GB 精靈的 OAM 工作副本。函式會為 X 加 8、Y 加 16,轉換為硬體座標。
語法
void sprite_set_pos(u8 id, u8 x, u8 y);參數
id欄位編號,範圍為 0..SPRITE_MAX-1;預設 GB 為 0..39,FC 為 0..63。超出範圍的編號會被忽略。
x以像素為單位的橫向位置,使用無號位元組表示,並非圖塊座標。
y畫面 Y 座標,單位為像素。GB 包裝函式會加上 16 再寫入 OAM。
回傳值
無(void)。
使用條件與限制
位置、圖塊、屬性與隱藏操作只修改工作副本,不會分配欄位,也不立即更新硬體 OAM。完成一影格的修改後,用 sprite_flush_oam 傳輸。
座標加法採用 8 位元運算,超出後以 256 循環,不做畫面裁切。只要欄位編號有效,即使未分配也能修改。
範例使用完整的 GB 精靈函式庫。定義 KQ_SPRITE_MINIMAL_RUNTIME 後,sprite.c 不再包含 sprite_free、sprite_set_pos、sprite_count_used、兩個掃描線查詢函式、metasprite_draw 與 anim_update。需要這些函式時請勿定義該巨集。
使用範例
sprite_set_pos(0,88,SPRITE_EXAMPLE_Y(16)); // Visible top-left: (88,16).這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/sprite.h:58
Convert screen coordinates to OAM coordinates by adding X=8 and Y=16. The byte additions wrap; this updates shadow storage even for an unallocated slot.
kitaqgb/lib/sprite.c:89
void sprite_set_pos(u8 id, u8 x, u8 y)
{
if (sprite_valid(id) == 0) return;
kq_sprite_oam[id].x = (u8)(x + 8);
kq_sprite_oam[id].y = (u8)(y + 16);
}sprite_set_tile
替換一個 OAM 工作副本項目的圖塊編號。它只選取圖塊記憶體中已有的圖形,不上傳圖形,也不分配精靈。
語法
void sprite_set_tile(u8 id, u8 tile);參數
id欄位編號,範圍為 0..SPRITE_MAX-1;預設 GB 為 0..39,FC 為 0..63。超出範圍的編號會被忽略。
tile8 位元圖塊編號。須先載入圖形。8×16 精靈仍遵循硬體規則,函式不會自動調整成成對圖塊編號。
回傳值
無(void)。
使用條件與限制
位置、圖塊、屬性與隱藏操作只修改工作副本,不會分配欄位,也不立即更新硬體 OAM。完成一影格的修改後,用 sprite_flush_oam 傳輸。
範例使用完整的 GB 精靈函式庫。定義 KQ_SPRITE_MINIMAL_RUNTIME 後,sprite.c 不再包含 sprite_free、sprite_set_pos、sprite_count_used、兩個掃描線查詢函式、metasprite_draw 與 anim_update。需要這些函式時請勿定義該巨集。
使用範例
sprite_set_tile(5,129); // Select the green square beside ANIMATION.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
設定 first_tile=128、兩影格、每影格兩次呼叫後,第一次更新傳回箭頭圖塊 128,第二次傳回正方形圖塊 129。ANIMATION 旁的正方形可確認傳回值已套用至 OAM。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/sprite.h:60
Set a valid shadow slot's tile byte; allocation and hardware transfer are separate.
kitaqgb/lib/sprite.c:98
void sprite_set_tile(u8 id, u8 tile)
{
if (sprite_valid(id) == 0) return;
kq_sprite_oam[id].tile = tile;
}sprite_warn_scanline_overflow
將 sprite_max_scanline_count 與每條掃描線的精靈上限比較:GB 為 10,FC 為 8。它回報軟體估算結果,不讀取硬體溢位旗標。
語法
u8 sprite_warn_scanline_overflow();回傳值
估算值超過每條掃描線的上限時為 1,否則為 0。
使用條件與限制
將 kq_sprite_height 設為硬體高度 8 或 16。估算不考慮透明像素、橫向可見範圍或硬體優先順序。FC 讀取函式庫記錄的座標,因此直接用 OAM 內建函式更改的位置不會反映在估算中。
範例使用完整的 GB 精靈函式庫。定義 KQ_SPRITE_MINIMAL_RUNTIME 後,sprite.c 不再包含 sprite_free、sprite_set_pos、sprite_count_used、兩個掃描線查詢函式、metasprite_draw 與 anim_update。需要這些函式時請勿定義該巨集。
使用範例
sprite_example_expect(sprite_warn_scanline_overflow()==1);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
SCAN LIMIT 下方一行從 (8,128) 開始。程式在同一行提交 11 個 GB 精靈或 9 個 FC 精靈,刻意超出一個。GB 應顯示 10 個箭頭,FC 應顯示 8 個,最後提交的箭頭不出現。軟體峰值與警告檢查仍應分別得到 11/9 與 1。
本程式示範精靈分配、定位、翻轉、複合物件、重疊、動畫與掃描線上限。右上角兩位數字應為 00,表示程式內的檢查全部通過。每個箭頭與正方形皆占一個 8×8 圖塊。
NORMAL 在 (88,16) 顯示向右箭頭;FLIP X 在 (88,32) 向左;FLIP Y 在 (88,48) 上下翻轉。META 在 (88,64) 與 (96,64) 放置兩個箭頭。OVERLAP 中,(88,80) 的箭頭位於 (92,80) 的正方形之前,箭頭的透明像素會露出正方形。ANIMATION 在 (88,96) 顯示正方形。(120,16) 與 (120,32) 的欄位分別隱藏與釋放後,應保持空白。
CGB 與 FC 的箭頭採用綠色箭桿、紅色輪廓與藍色尖端細節,正方形為綠色。透明部分露出 GB 的白色背景或 FC 的黑色背景。DMG 以淺灰、深灰與黑色分別代替紅、綠、藍。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/sprite.h:75
Report whether the software overlap estimate exceeds ten sprites on a scanline.
kitaqgb/lib/sprite.c:182
u8 sprite_warn_scanline_overflow()
{
return (u8)(sprite_max_scanline_count() > 10);
}sprite_order.h — 依優先順序與輪替選取精靈
sprite_order 將重要物件排前面,並循環同優先物件的 OAM 順序。最多從 255 個候選輸出 40 個物件,協助管理每掃描線十物件限制。sprite 函式庫處理槽配置與 DMA;sprite_order 處理候選選取順序。
引入 sprite_order.h,並將 sprite_order.c 編譯一次。初始化後,每影格依序呼叫 begin、對每個候選呼叫 push,最後 build。排序函式庫本身不需要 sprite.c 或任何全域變數定義。
硬體依 OAM 順序選擇與各掃描線相交的前十個物件。較小優先值排前面,可在擁擠的線上保護重要物件。循環順序不保證同優先群組內顯示頻率相等。高優先物件若占滿十個位置,該線的低優先物件仍不可見。
SpriteOrderOamEntry 含 Y、X、tile、flags 四個位元組。若要使用 sprite.h 的 OAM 副本,請寫入 (SpriteOrderOamEntry*)kq_sprite_oam。維持標準 SPRITE_MAX 40,不要混用配置器管理的槽 ID 與重排輸出;build 不更新配置器記錄。
sprite_order_begin
清除新影格提交數量,保留儲存區、高度與循環相位。與每影格重新初始化不同,此操作讓循環持續。
語法
void sprite_order_begin(SpriteOrder* order);參數
order呼叫端持有的
SpriteOrder位址。使用前須初始化,並在主程式中更新。
回傳值
無回傳值。忽略 null order。不清除舊項目位元組或已建構的 OAM。
使用條件與限制
引入 sprite_order.h,並將 sprite_order.c 編譯一次。初始化後,每影格依序呼叫 begin、對每個候選呼叫 push,最後 build。排序函式庫本身不需要 sprite.c 或任何全域變數定義。
硬體依 OAM 順序選擇與各掃描線相交的前十個物件。較小優先值排前面,可在擁擠的線上保護重要物件。循環順序不保證同優先群組內顯示頻率相等。高優先物件若占滿十個位置,該線的低優先物件仍不可見。
使用範例
sprite_order_begin(&order_demo);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本範例以同列十四個物件展示掃描線選取。HIGH 下兩個菱形優先度高,NORMAL 下十二個方形為一般優先度。CGB 使用紅菱形、藍方形;DMG 使用灰、黑。兩個菱形保持可見,方形只出現八個。0..B 標示方形位置;PHASE 04 顯示 4..B,PHASE 08 顯示 8..B 與 0..3。一般建置每等待 60 影格推進 PHASE。公開擷取固定同一程式的相位,執行版本也確認了方形選取變化。



建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_order_demo.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_order_demo.gb --cgb=cgb --profile=dev --rst-disable --stack-bank=fixed --no-cache --no-disasm實作與原始碼
kitaqgb/lib/sprite_order.h:42
Discard this frame's submissions while preserving storage, height and phase. A null state is ignored. Call once before submitting the next frame's sprites.
kitaqgb/lib/sprite_order.c:24
void sprite_order_begin(SpriteOrder* order)
{
if (order != 0) order->count = 0;
}sprite_order_build
依優先及循環順序,從提交候選建構 160 位元組 OAM 副本。未用槽全部歸零以隱藏,再推進下次建構的相位。不重排提交儲存區。
語法
u8 sprite_order_build(SpriteOrder* order, SpriteOrderOamEntry* output, u8 limit);參數
order呼叫端持有的
SpriteOrder位址。使用前須初始化,並在主程式中更新。output可寫入的 40 個
SpriteOrderOamEntry陣列。即使 limit 為零或小於 40,也會寫入全部 160 位元組。limit最大輸出數 0..40,較大值限制為 40。限制的是整個 OAM,不是每條掃描線。
回傳值
傳回輸出數 0..40。有效空佇列清除所有槽並設 phase=0。否則先以 count 取模正規化 phase,在各遞增優先群組使用此循環起點,再遞增並回繞 phase。limit 為零仍推進相位。order/output 為 null、停用狀態、無效高度或 count>capacity 時,傳回零且不改輸出或相位。
使用條件與限制
硬體依 OAM 順序選擇與各掃描線相交的前十個物件。較小優先值排前面,可在擁擠的線上保護重要物件。循環順序不保證同優先群組內顯示頻率相等。高優先物件若占滿十個位置,該線的低優先物件仍不可見。
priority 引數控制選取順序,與背景後方屬性獨立。DMG 上已選物件重疊時,較小 X 座標優先,相同則依 OAM 順序。一般 CGB 彩色模式依 OAM 順序,但透過 OPRI 選用的 DMG 式排序設定仍適用。此函式庫不改變硬體優先規則。
SpriteOrderOamEntry 含 Y、X、tile、flags 四個位元組。若要使用 sprite.h 的 OAM 副本,請寫入 (SpriteOrderOamEntry*)kq_sprite_oam。維持標準 SPRITE_MAX 40,不要混用配置器管理的槽 ID 與重排輸出;build 不更新配置器記錄。
build 只寫 RAM。請提供不與狀態或提交資料重疊的 160 位元組輸出陣列。OAM DMA 緩衝區須從 256 位元組邊界開始。VBlank 傳輸前須完成建構,中斷不可傳送建構一半的緩衝區。範例使用 sprite_flush_oam。
每次提交的工作量有界。建構會清除 160 位元組 OAM 副本,並最多掃描提交陣列四次,不排序原陣列,也不需暫存排序緩衝區。這不保證 255 個候選可符合遊戲每影格預算;只提交場景所需候選。
使用範例
order_demo_state[1]=sprite_order_build(&order_demo,(SpriteOrderOamEntry*)kq_sprite_oam,40);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本範例以同列十四個物件展示掃描線選取。HIGH 下兩個菱形優先度高,NORMAL 下十二個方形為一般優先度。CGB 使用紅菱形、藍方形;DMG 使用灰、黑。兩個菱形保持可見,方形只出現八個。0..B 標示方形位置;PHASE 04 顯示 4..B,PHASE 08 顯示 8..B 與 0..3。一般建置每等待 60 影格推進 PHASE。公開擷取固定同一程式的相位,執行版本也確認了方形選取變化。



建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_order_demo.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_order_demo.gb --cgb=cgb --profile=dev --rst-disable --stack-bank=fixed --no-cache --no-disasm實作與原始碼
kitaqgb/lib/sprite_order.h:62
Write a complete 160-byte shadow OAM: ascending priority, then cyclic order within each priority. Clamp limit to 40, return the number emitted and zero all unused entries (including Y) so they cannot consume scanline slots. Advance phase once for a nonempty valid queue, even when limit is zero. Empty queues reset phase to zero. Null/disabled/corrupt state or null output returns 0 without modifying output or phase. Output must provide 40 entries and must not overlap item/state storage. This only writes RAM. Build in foreground, then transfer during VBlank. DMG overlap priority also depends on X: this cannot override that hardware rule. OAM order chooses the first ten sprites per scanline on both DMG/CGB. It neither updates sprite_alloc's bookkeeping nor performs OAM DMA.
kitaqgb/lib/sprite_order.c:57
u8 sprite_order_build(SpriteOrder* order, SpriteOrderOamEntry* output, u8 limit)
{
u8 i;
u8 count;
u8 phase;
u8 priority;
u8 visited;
u8 written;
SpriteOrderItem* item;
if (order == 0 || output == 0) return 0;
if (order->items == 0 || order->capacity == 0) return 0;
if (order->count > order->capacity) return 0;
if (order->height != 8 && order->height != 16) return 0;
// Clear all hardware slots regardless of the requested emission limit.
for (i = 0; i < SPRITE_ORDER_OAM_COUNT; i++) {
output[i].y = 0;
output[i].x = 0;
output[i].tile = 0;
output[i].flags = 0;
}
count = order->count;
if (count == 0) {
order->phase = 0;
return 0;
}
if (limit > SPRITE_ORDER_OAM_COUNT) limit = SPRITE_ORDER_OAM_COUNT;
phase = order->phase;
while (phase >= count) phase = (u8)(phase - count);
written = 0;
for (priority = 0; priority < SPRITE_ORDER_LEVELS && written < limit; priority++) {
i = phase;
visited = 0;
while (visited < count && written < limit) {
item = &order->items[i];
if (item->priority == priority) {
output[written].y = item->oam.y;
output[written].x = item->oam.x;
output[written].tile = item->oam.tile;
output[written].flags = item->oam.flags;
written++;
}
visited++;
i++;
if (i >= count) i = 0;
}
}
phase++;
if (phase >= count) phase = 0;
order->phase = phase;
return written;
}sprite_order_init
將提交儲存區綁定至排序狀態,並重設數量與循環相位。用於開始場景或更換儲存區。
語法
u8 sprite_order_init(SpriteOrder* order, SpriteOrderItem* items, u8 capacity, u8 height);參數
order呼叫端持有的
SpriteOrder位址。使用前須初始化,並在主程式中更新。items可寫入的
SpriteOrderItem陣列,每項五位元組。配置 capacity 個項目,使用期間維持有效。capacity陣列容量 1..255 項,不是位元組數或硬體槽數。
height所有物件共用高度。請傳入 8 或 16,配合 LCDC 的 8×8/8×16 設定;函式庫不設定 LCDC。8×16 模式下,硬體忽略圖塊編號最低位元。
回傳值
成功傳回 1;items 為 null、容量零、高度不是 8/16 或 order 為 null 時傳回 0。order 非 null 時,失敗會設為停用狀態:items=NULL、capacity=count=phase=0、height=8。不改變項目陣列。
使用條件與限制
引入 sprite_order.h,並將 sprite_order.c 編譯一次。初始化後,每影格依序呼叫 begin、對每個候選呼叫 push,最後 build。排序函式庫本身不需要 sprite.c 或任何全域變數定義。
使用範例
sprite_init();sprite_order_init(&order_demo,order_demo_items,14,8);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本範例以同列十四個物件展示掃描線選取。HIGH 下兩個菱形優先度高,NORMAL 下十二個方形為一般優先度。CGB 使用紅菱形、藍方形;DMG 使用灰、黑。兩個菱形保持可見,方形只出現八個。0..B 標示方形位置;PHASE 04 顯示 4..B,PHASE 08 顯示 8..B 與 0..3。一般建置每等待 60 影格推進 PHASE。公開擷取固定同一程式的相位,執行版本也確認了方形選取變化。



建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_order_demo.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_order_demo.gb --cgb=cgb --profile=dev --rst-disable --stack-bank=fixed --no-cache --no-disasm實作與原始碼
kitaqgb/lib/sprite_order.h:38
Bind writable item storage and select the hardware sprite height (8 or 16). Return 1 on success. Invalid storage, zero capacity or another height returns 0 and leaves a non-null state disabled. A null state returns 0 without writes.
kitaqgb/lib/sprite_order.c:6
u8 sprite_order_init(SpriteOrder* order, SpriteOrderItem* items, u8 capacity, u8 height)
{
if (order == 0) return 0;
order->items = 0;
order->capacity = 0;
order->count = 0;
order->height = 8;
order->phase = 0;
if (items == 0 || capacity == 0) return 0;
if (height != 8 && height != 16) return 0;
order->items = items;
order->capacity = capacity;
order->height = height;
return 1;
}sprite_order_push
提交至少一像素與可見畫面相交的精靈。完全在畫面外的候選會先被拒絕,不消耗 OAM 選取位置。
語法
u8 sprite_order_push(SpriteOrder* order, s16 x, s16 y, u8 tile, u8 flags, u8 priority);參數
order呼叫端持有的
SpriteOrder位址。使用前須初始化,並在主程式中更新。x從左上角量測的帶正負號螢幕 X。左邊緣 −7..159 可接受;小於或等於 −8、大於或等於 160 則完全在畫面外。儲存時加 8 轉成 OAM 座標。
y從左上角量測的帶正負號螢幕 Y。高度 8 接受 −7..143,高度 16 接受 −15..143。儲存時加 16 轉成 OAM 座標。
tile圖塊編號 0..255,原樣儲存。8×16 模式請參閱高度注意事項。
flags硬體屬性位元組原樣儲存:翻轉、背景後方優先、DMG/CGB 調色盤與 CGB VRAM 記憶體庫位元維持各自硬體含義。
priority軟體選取優先值 0..3,零最先。大於或等於四會拒絕,與硬體 flags 位元組分開。
回傳值
接受時傳回 1 並遞增 count。null/停用狀態、無效高度、儲存已滿、無效優先值或完全離屏物件,皆傳回 0,不改變 items 或 count。
使用條件與限制
所有物件共用高度。請傳入 8 或 16,配合 LCDC 的 8×8/8×16 設定;函式庫不設定 LCDC。8×16 模式下,硬體忽略圖塊編號最低位元。
硬體依 OAM 順序選擇與各掃描線相交的前十個物件。較小優先值排前面,可在擁擠的線上保護重要物件。循環順序不保證同優先群組內顯示頻率相等。高優先物件若占滿十個位置,該線的低優先物件仍不可見。
priority 引數控制選取順序,與背景後方屬性獨立。DMG 上已選物件重疊時,較小 X 座標優先,相同則依 OAM 順序。一般 CGB 彩色模式依 OAM 順序,但透過 OPRI 選用的 DMG 式排序設定仍適用。此函式庫不改變硬體優先規則。
使用範例
sprite_order_push(&order_demo,8,64,128,0,0);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本範例以同列十四個物件展示掃描線選取。HIGH 下兩個菱形優先度高,NORMAL 下十二個方形為一般優先度。CGB 使用紅菱形、藍方形;DMG 使用灰、黑。兩個菱形保持可見,方形只出現八個。0..B 標示方形位置;PHASE 04 顯示 4..B,PHASE 08 顯示 8..B 與 0..3。一般建置每等待 60 影格推進 PHASE。公開擷取固定同一程式的相位,執行版本也確認了方形選取變化。



建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_order_demo.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_order_demo.gb --cgb=cgb --profile=dev --rst-disable --stack-bank=fixed --no-cache --no-disasm實作與原始碼
kitaqgb/lib/sprite_order.h:49
Submit one sprite at signed, top-left SCREEN pixel coordinates. Preserve the tile and attribute bytes; use priority 0 (first) through 3 (last). Fully off-screen sprites, invalid priorities, disabled state and full storage return 0 without consuming a slot. Partly visible sprites are accepted. Return 1 on acceptance. Hardware 8x16 mode still ignores the tile index's low bit.
kitaqgb/lib/sprite_order.c:31
u8 sprite_order_push(SpriteOrder* order, s16 x, s16 y, u8 tile, u8 flags, u8 priority)
{
SpriteOrderItem* item;
if (order == 0) return 0;
if (order->items == 0 || order->capacity == 0) return 0;
if (order->height != 8 && order->height != 16) return 0;
if (order->count >= order->capacity || priority >= SPRITE_ORDER_LEVELS) return 0;
if (x <= -8 || x >= 160 || y >= 144) return 0;
if (order->height == 16) {
if (y <= -16) return 0;
} else {
if (y <= -8) return 0;
}
item = &order->items[order->count];
item->oam.y = (u8)(y + 16);
item->oam.x = (u8)(x + 8);
item->oam.tile = tile;
item->oam.flags = flags;
item->priority = priority;
order->count++;
return 1;
}system.h — 啟動、影格計數、等待與中斷
管理影格等待次數、等待後的回呼,以及可遮罩 CPU 中斷。
gb_disable_interrupts
gb_disable_interrupts 是 system_disable_interrupts 的別名,停用 GB CPU 中斷。
停用 CPU 的可遮罩中斷。
語法
void gb_disable_interrupts();回傳值
無傳回值。
使用條件與限制
標頭定義會展開為實作名稱的物件式巨集。引數、傳回值與狀態存取均與目標相同;別名不增加獨立狀態或處理。請依完整範例與建置命令,輸入使用 input.h/input.c,影格服務使用 system.h/system.c。
受保護的更新區段應保持簡短,之後須適當還原中斷。中斷遮罩與影格等待函式所需的條件是兩回事。
GB 的 LCD 關閉時,等待會立即返回,但包裝函式仍會遞增計數器並呼叫回呼。僅執行初始化不會設定 LCD 或中斷來源。
請以預設 Legacy ABI 建置此完整範例。回呼使用函式指標呼叫,而編譯器在 --abi=stack 下會以不支援為由拒絕。使用別名時也有相同限制。
使用範例
gb_disable_interrupts();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例成對使用停用與啟用操作;另有專用驗證程式檢查 CPU 中斷狀態。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\system_aliases.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\system_aliases.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/system.h:32
#define gb_disable_interrupts system_disable_interruptskitaqgb/lib/system.c:52
void system_disable_interrupts()
{
__asm {
DI
RET
}
}gb_enable_interrupts
gb_enable_interrupts 是 system_enable_interrupts 的別名,啟用 GB CPU 中斷。
啟用 CPU 的可遮罩中斷。
語法
void gb_enable_interrupts();回傳值
無傳回值。
使用條件與限制
標頭定義會展開為實作名稱的物件式巨集。引數、傳回值與狀態存取均與目標相同;別名不增加獨立狀態或處理。請依完整範例與建置命令,輸入使用 input.h/input.c,影格服務使用 system.h/system.c。
啟用前請先準備好中斷來源與處理常式。在 FC 上,此操作與 NMI 的啟用或停用互相獨立。
GB 的 LCD 關閉時,等待會立即返回,但包裝函式仍會遞增計數器並呼叫回呼。僅執行初始化不會設定 LCD 或中斷來源。
請以預設 Legacy ABI 建置此完整範例。回呼使用函式指標呼叫,而編譯器在 --abi=stack 下會以不支援為由拒絕。使用別名時也有相同限制。
使用範例
gb_enable_interrupts();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例還原中斷。FC 程式會先停用 APU 影格與 DMC IRQ 來源,避免重複處理尚未清除的 IRQ。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\system_aliases.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\system_aliases.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/system.h:31
#define gb_enable_interrupts system_enable_interruptskitaqgb/lib/system.c:43
void system_enable_interrupts()
{
__asm {
EI
RET
}
}gb_frame_count
gb_frame_count 是 system_get_frame 的別名,讀取封裝等待函式完成次數的 16 位元軟體計數。
讀取影格等待包裝函式的 16 位元計數器。
語法
u16 gb_frame_count();回傳值
傳回目前計數器值,範圍為 0~65535。
使用條件與限制
標頭定義會展開為實作名稱的物件式巨集。引數、傳回值與狀態存取均與目標相同;別名不增加獨立狀態或處理。請依完整範例與建置命令,輸入使用 input.h/input.c,影格服務使用 system.h/system.c。
計數器只計算透過此包裝函式等待的次數,不會自動測量硬體實際經過的影格數。超出 16 位元範圍時會回繞。
GB 的 LCD 關閉時,等待會立即返回,但包裝函式仍會遞增計數器並呼叫回呼。僅執行初始化不會設定 LCD 或中斷來源。
請以預設 Legacy ABI 建置此完整範例。回呼使用函式指標呼叫,而編譯器在 --abi=stack 下會以不支援為由拒絕。使用別名時也有相同限制。
使用範例
result[3]=gb_frame_count();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例等待三次後讀到三。回繞檢查會明確將計數器設為 65535,再確認下一次等待後為零。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\system_aliases.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\system_aliases.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/system.h:30
#define gb_frame_count system_get_framekitaqgb/lib/system.c:31
u16 system_get_frame()
{
return kq_system_frame;
}gb_init
gb_init 是 system_init 的別名,重設軟體影格計數與回呼註冊。
清除計數器與已註冊回呼,以初始化影格管理。
語法
void gb_init();回傳值
無傳回值。
使用條件與限制
標頭定義會展開為實作名稱的物件式巨集。引數、傳回值與狀態存取均與目標相同;別名不增加獨立狀態或處理。請依完整範例與建置命令,輸入使用 input.h/input.c,影格服務使用 system.h/system.c。
計數器只計算透過此包裝函式等待的次數,不會自動測量硬體實際經過的影格數。超出 16 位元範圍時會回繞。
GB 的 LCD 關閉時,等待會立即返回,但包裝函式仍會遞增計數器並呼叫回呼。僅執行初始化不會設定 LCD 或中斷來源。
請以預設 Legacy ABI 建置此完整範例。回呼使用函式指標呼叫,而編譯器在 --abi=stack 下會以不支援為由拒絕。使用別名時也有相同限制。
使用範例
gb_init();result[0]=gb_frame_count();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例在註冊回呼前,確認初始影格編號為零。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\system_aliases.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\system_aliases.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/system.h:27
#define gb_init system_initkitaqgb/lib/system.c:7
void system_init()
{
kq_system_frame = 0;
system_vblank_callback = 0;
}gb_set_vblank_callback
gb_set_vblank_callback 是 system_set_vblank_callback 的別名,註冊或移除影格等待後同步呼叫的回呼。
註冊、替換或移除影格等待後要呼叫的函式。
語法
void gb_set_vblank_callback(SystemCallback callback);參數
callback要呼叫的函式;0 會移除回呼。
回傳值
無傳回值。
使用條件與限制
標頭定義會展開為實作名稱的物件式巨集。引數、傳回值與狀態存取均與目標相同;別名不增加獨立狀態或處理。請依完整範例與建置命令,輸入使用 input.h/input.c,影格服務使用 system.h/system.c。
這是指向無引數、無傳回值函式的一般指標,不含記憶體庫編號。只要仍可能被呼叫,就必須維持目標程式碼的映射。
GB 的 LCD 關閉時,等待會立即返回,但包裝函式仍會遞增計數器並呼叫回呼。僅執行初始化不會設定 LCD 或中斷來源。
請以預設 Legacy ABI 建置此完整範例。回呼使用函式指標呼叫,而編譯器在 --abi=stack 下會以不支援為由拒絕。使用別名時也有相同限制。
使用範例
gb_set_vblank_callback(on_frame);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
回呼執行三次後,註冊 0 會停用呼叫。下一次等待使影格計數前進到四,但回呼次數仍為三。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\system_aliases.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\system_aliases.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/system.h:29
#define gb_set_vblank_callback system_set_vblank_callbackkitaqgb/lib/system.c:25
void system_set_vblank_callback(SystemCallback callback)
{
system_vblank_callback = callback;
}gb_wait_vblank
gb_wait_vblank 是 system_wait_vblank 的別名,等待影格邊界、推進軟體影格計數,並呼叫已註冊回呼。
等待下一個影格、遞增計數器,再呼叫已註冊的回呼。
語法
void gb_wait_vblank();回傳值
無傳回值。
使用條件與限制
標頭定義會展開為實作名稱的物件式巨集。引數、傳回值與狀態存取均與目標相同;別名不增加獨立狀態或處理。請依完整範例與建置命令,輸入使用 input.h/input.c,影格服務使用 system.h/system.c。
回呼在此函式內同步執行;註冊回呼不會安裝中斷處理常式。計數器只計算透過此包裝函式等待的次數,不會自動測量硬體實際經過的影格數,並在超出 16 位元範圍時回繞。
GB 的 LCD 關閉時,等待會立即返回,但包裝函式仍會遞增計數器並呼叫回呼。僅執行初始化不會設定 LCD 或中斷來源。
請以預設 Legacy ABI 建置此完整範例。回呼使用函式指標呼叫,而編譯器在 --abi=stack 下會以不支援為由拒絕。使用別名時也有相同限制。
使用範例
gb_wait_vblank();gb_wait_vblank();gb_wait_vblank();result[1]=frame_calls;result[2]=frame_seen;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
等待三次會呼叫回呼三次,最後一次回呼內讀到的計數器值為三。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\system_aliases.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\system_aliases.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/system.h:28
#define gb_wait_vblank system_wait_vblankkitaqgb/lib/system.c:15
void system_wait_vblank()
{
__wait_vblank();
kq_system_frame++;
if (system_vblank_callback != 0) {
system_vblank_callback();
}
}system_disable_interrupts
停用 CPU 的可遮罩中斷。
語法
void system_disable_interrupts();回傳值
無傳回值。
使用條件與限制
受保護的更新區段應保持簡短,之後須適當還原中斷。中斷遮罩與影格等待函式所需的條件是兩回事。
GB 的 LCD 關閉時,等待會立即返回,但包裝函式仍會遞增計數器並呼叫回呼。僅執行初始化不會設定 LCD 或中斷來源。
請以預設 Legacy ABI 建置此完整範例。回呼使用函式指標呼叫,而編譯器在 --abi=stack 下會以不支援為由拒絕。使用別名時也有相同限制。
使用範例
system_disable_interrupts();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例成對使用停用與啟用操作;另有專用驗證程式檢查 CPU 中斷狀態。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/system.h:25
Disable CPU interrupts and return; callers must explicitly re-enable them later.
kitaqgb/lib/system.c:52
void system_disable_interrupts()
{
__asm {
DI
RET
}
}system_enable_interrupts
啟用 CPU 的可遮罩中斷。
語法
void system_enable_interrupts();回傳值
無傳回值。
使用條件與限制
啟用前請先準備好中斷來源與處理常式。在 FC 上,此操作與 NMI 的啟用或停用互相獨立。
GB 的 LCD 關閉時,等待會立即返回,但包裝函式仍會遞增計數器並呼叫回呼。僅執行初始化不會設定 LCD 或中斷來源。
請以預設 Legacy ABI 建置此完整範例。回呼使用函式指標呼叫,而編譯器在 --abi=stack 下會以不支援為由拒絕。使用別名時也有相同限制。
使用範例
system_enable_interrupts();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例還原中斷。FC 程式會先停用 APU 影格與 DMC IRQ 來源,避免重複處理尚未清除的 IRQ。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/system.h:23
Enable CPU interrupts and return using the inline-assembly function body.
kitaqgb/lib/system.c:43
void system_enable_interrupts()
{
__asm {
EI
RET
}
}system_get_frame
讀取影格等待包裝函式的 16 位元計數器。
語法
u16 system_get_frame();回傳值
傳回目前計數器值,範圍為 0~65535。
使用條件與限制
計數器只計算透過此包裝函式等待的次數,不會自動測量硬體實際經過的影格數。超出 16 位元範圍時會回繞。
GB 的 LCD 關閉時,等待會立即返回,但包裝函式仍會遞增計數器並呼叫回呼。僅執行初始化不會設定 LCD 或中斷來源。
請以預設 Legacy ABI 建置此完整範例。回呼使用函式指標呼叫,而編譯器在 --abi=stack 下會以不支援為由拒絕。使用別名時也有相同限制。
使用範例
result[3]=system_get_frame();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例等待三次後讀到三。回繞檢查會明確將計數器設為 65535,再確認下一次等待後為零。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/system.h:19
Read the software count of completed system_wait_vblank calls.
kitaqgb/lib/system.c:31
u16 system_get_frame()
{
return kq_system_frame;
}system_get_frame8
讀取影格計數器的低八位元,供短週期循環使用。
語法
u8 system_get_frame8();回傳值
傳回低位元組,範圍為 0~255。
使用條件與限制
計數器只計算透過此包裝函式等待的次數,不會自動測量硬體實際經過的影格數。超出 16 位元範圍時會回繞。
GB 的 LCD 關閉時,等待會立即返回,但包裝函式仍會遞增計數器並呼叫回呼。僅執行初始化不會設定 LCD 或中斷來源。
請以預設 Legacy ABI 建置此完整範例。回呼使用函式指標呼叫,而編譯器在 --abi=stack 下會以不支援為由拒絕。使用別名時也有相同限制。
使用範例
result[4]=system_get_frame8();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例等待三次後讀到三,16 位元計數器回繞時讀到零。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/system.h:21
Return the low byte of the software frame counter for wrapping 8-bit timing.
kitaqgb/lib/system.c:37
u8 system_get_frame8()
{
return (u8)kq_system_frame;
}system_init
清除計數器與已註冊回呼,以初始化影格管理。
語法
void system_init();回傳值
無傳回值。
使用條件與限制
計數器只計算透過此包裝函式等待的次數,不會自動測量硬體實際經過的影格數。超出 16 位元範圍時會回繞。
GB 的 LCD 關閉時,等待會立即返回,但包裝函式仍會遞增計數器並呼叫回呼。僅執行初始化不會設定 LCD 或中斷來源。
請以預設 Legacy ABI 建置此完整範例。回呼使用函式指標呼叫,而編譯器在 --abi=stack 下會以不支援為由拒絕。使用別名時也有相同限制。
使用範例
system_init();result[0]=system_get_frame();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
本例在註冊回呼前,確認初始影格編號為零。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/system.h:12
Reset the software frame counter and remove any registered callback.
kitaqgb/lib/system.c:7
void system_init()
{
kq_system_frame = 0;
system_vblank_callback = 0;
}system_set_vblank_callback
註冊、替換或移除影格等待後要呼叫的函式。
語法
void system_set_vblank_callback(SystemCallback callback);參數
callback要呼叫的函式;0 會移除回呼。
回傳值
無傳回值。
使用條件與限制
這是指向無引數、無傳回值函式的一般指標,不含記憶體庫編號。只要仍可能被呼叫,就必須維持目標程式碼的映射。
GB 的 LCD 關閉時,等待會立即返回,但包裝函式仍會遞增計數器並呼叫回呼。僅執行初始化不會設定 LCD 或中斷來源。
請以預設 Legacy ABI 建置此完整範例。回呼使用函式指標呼叫,而編譯器在 --abi=stack 下會以不支援為由拒絕。使用別名時也有相同限制。
使用範例
system_set_vblank_callback(on_frame);這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
回呼執行三次後,註冊 0 會停用呼叫。下一次等待使影格計數前進到四,但回呼次數仍為三。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/system.h:17
Replace the callback used by system_wait_vblank; null disables the callback.
kitaqgb/lib/system.c:25
void system_set_vblank_callback(SystemCallback callback)
{
system_vblank_callback = callback;
}system_wait_vblank
等待下一個影格、遞增計數器,再呼叫已註冊的回呼。
語法
void system_wait_vblank();回傳值
無傳回值。
使用條件與限制
回呼在此函式內同步執行;註冊回呼不會安裝中斷處理常式。計數器只計算透過此包裝函式等待的次數,不會自動測量硬體實際經過的影格數,並在超出 16 位元範圍時回繞。
GB 的 LCD 關閉時,等待會立即返回,但包裝函式仍會遞增計數器並呼叫回呼。僅執行初始化不會設定 LCD 或中斷來源。
請以預設 Legacy ABI 建置此完整範例。回呼使用函式指標呼叫,而編譯器在 --abi=stack 下會以不支援為由拒絕。使用別名時也有相同限制。
使用範例
system_wait_vblank();system_wait_vblank();system_wait_vblank();result[1]=frame_calls;result[2]=frame_seen;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
等待三次會呼叫回呼三次,最後一次回呼內讀到的計數器值為三。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k實作與原始碼
kitaqgb/lib/system.h:15
Wait for VBlank, count this wrapper call, then invoke the callback synchronously. The counter wraps at 16 bits and is not an independent hardware frame clock.
kitaqgb/lib/system.c:15
void system_wait_vblank()
{
__wait_vblank();
kq_system_frame++;
if (system_vblank_callback != 0) {
system_vblank_callback();
}
}vram.h — VRAM 佇列更新與傳輸
將延後執行的VRAM寫入命令佇列初始化為空,並清除溢位旗標。不會清除畫面、上傳圖塊圖形或配置硬體VRAM。
GB以命令槽計數,預設容量32。每個加入函式使用一個槽,大型傳輸或零長度傳輸也一樣。VRAM_QUEUE_MAX應在所有編譯單元中一致設為1至255。空佇列為used=0、free=capacity。
先用__wait_vblank等待,再呼叫vram_flush_now。適合批次執行少量畫面更新。一次等待並不會限制傳輸量,也不保證整個批次能在一次VBlank內完成。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
vram_clear_queue
丟棄待執行的 VRAM 命令並清除溢位旗標,不進行寫入。
語法
void vram_clear_queue();回傳值
無(void)。
使用條件與限制
GB以命令槽計數,預設容量32。每個加入函式使用一個槽,大型傳輸或零長度傳輸也一樣。VRAM_QUEUE_MAX應在所有編譯單元中一致設為1至255。空佇列為used=0、free=capacity。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
vram_clear_queue();
if (vram_get_queue_used()!=0 || vram_get_overflowed()!=0) failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
CGB模式下,上方兩個正方形、三圖樣複製和最後透過VBlank寫入的正方形為紅色;32×24矩形和雙圖樣複製為藍色;3×2圖塊區塊和40×8橫條為綠色。文字仍為白底黑字。除形狀外,還檢查每個繪製像素的顏色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/vram.h:41
Discard pending commands and clear the latched overflow flag without writing VRAM.
kitaqgb/lib/vram.c:41
void vram_clear_queue()
{
kq_vram_queue_used = 0;
kq_vram_queue_overflowed = 0;
}vram_flush
先用__wait_vblank等待,再呼叫vram_flush_now。適合批次執行少量畫面更新。一次等待並不會限制傳輸量,也不保證整個批次能在一次VBlank內完成。
語法
void vram_flush();回傳值
無(void)。
使用條件與限制
GB以命令槽計數,預設容量32。每個加入函式使用一個槽,大型傳輸或零長度傳輸也一樣。VRAM_QUEUE_MAX應在所有編譯單元中一致設為1至255。空佇列為used=0、free=capacity。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
VRAM中的目的位元組位址(0x8000–0x9FFF),使用執行時選中的記憶體庫。傳輸位址連續,不在圖塊對映表列尾換列。整個目的範圍都必須有效。LCD開啟時,安全寫入路徑可能啟用中斷,不保留呼叫前的中斷停用狀態。
使用範例
vram_flush(); // One small write through the VBlank/NMI path.
if (vram_get_queue_used()!=0) failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
CGB模式下,上方兩個正方形、三圖樣複製和最後透過VBlank寫入的正方形為紅色;32×24矩形和雙圖樣複製為藍色;3×2圖塊區塊和40×8橫條為綠色。文字仍為白底黑字。除形狀外,還檢查每個繪製像素的顏色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/vram.h:64
Wait for VBlank before executing the queue. Waiting once does not itself limit the queued workload to the available VBlank duration.
kitaqgb/lib/vram.c:148
void vram_flush()
{
__wait_vblank();
vram_flush_now();
}vram_flush_now
依加入順序執行所有佇列命令,然後將使用數設為0。此函式本身不等待VBlank。LCD開啟時,被呼叫的安全VRAM內建函式會等待可寫時段,但大佇列可能跨越多條掃描線或多個影格。溢位旗標保留。
語法
void vram_flush_now();回傳值
無(void)。
使用條件與限制
GB以命令槽計數,預設容量32。每個加入函式使用一個槽,大型傳輸或零長度傳輸也一樣。VRAM_QUEUE_MAX應在所有編譯單元中一致設為1至255。空佇列為used=0、free=capacity。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
VRAM中的目的位元組位址(0x8000–0x9FFF),使用執行時選中的記憶體庫。傳輸位址連續,不在圖塊對映表列尾換列。整個目的範圍都必須有效。LCD開啟時,安全寫入路徑可能啟用中斷,不保留呼叫前的中斷停用狀態。
使用範例
// Rendering is stopped here. On FC, commit readiness before direct execution.
vram_flush_now();
after_flush=vram_get_queue_used();
if (after_flush!=0) failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
CGB模式下,上方兩個正方形、三圖樣複製和最後透過VBlank寫入的正方形為紅色;32×24矩形和雙圖樣複製為藍色;3×2圖塊區塊和40×8橫條為綠色。文字仍為白底黑字。除形狀外,還檢查每個繪製像素的顏色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/vram.h:61
Execute pending commands in insertion order without waiting for VBlank here. The caller must arrange suitable VRAM access timing and a sufficient transfer budget. Only the used count is cleared; overflow stays latched until an explicit reset.
kitaqgb/lib/vram.c:125
void vram_flush_now()
{
u8 i = 0;
while (i < kq_vram_queue_used) {
VramCommand* cmd = &kq_vram_queue[(__safe_index u8)i];
if (cmd->kind == VRAM_CMD_BG_TILE) {
__settile_xy(cmd->x, cmd->y, cmd->value);
} else if (cmd->kind == VRAM_CMD_BG_RECT) {
__settile_rect(cmd->x, cmd->y, cmd->w, cmd->h, cmd->value);
} else if (cmd->kind == VRAM_CMD_BG_BLOCK) {
__settilemap_rect(cmd->dst, cmd->x, cmd->y, cmd->w, cmd->h, cmd->src);
} else if (cmd->kind == VRAM_CMD_MEMCPY) {
__vram_copy(cmd->dst, cmd->src, cmd->len);
} else if (cmd->kind == VRAM_CMD_MEMSET) {
__vram_fill(cmd->dst, cmd->value, cmd->len);
}
i++;
}
kq_vram_queue_used = 0;
}vram_get_overflowed
讀取佇列溢位旗標而不清除;先前的失敗紀錄可能仍保留。
語法
u8 vram_get_overflowed();回傳值
未記錄溢位時為0;加入被拒絕後為1,直到明確重設。執行佇列不會清除此旗標。
使用條件與限制
GB以命令槽計數,預設容量32。每個加入函式使用一個槽,大型傳輸或零長度傳輸也一樣。VRAM_QUEUE_MAX應在所有編譯單元中一致設為1至255。空佇列為used=0、free=capacity。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
overflow_seen=vram_get_overflowed();
if (overflow_seen!=1) failures++;
// Reading the latch again does not clear it.
if (vram_get_overflowed()!=1) failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
CGB模式下,上方兩個正方形、三圖樣複製和最後透過VBlank寫入的正方形為紅色;32×24矩形和雙圖樣複製為藍色;3×2圖塊區塊和40×8橫條為綠色。文字仍為白底黑字。除形狀外,還檢查每個繪製像素的顏色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/vram.h:73
Read the overflow latch without clearing it.
kitaqgb/lib/vram.c:175
u8 vram_get_overflowed()
{
return kq_vram_queue_overflowed;
}vram_get_queue_capacity
此 API 在本機版中的差異,請參閱 2026-10-03 差異與驗證。
回傳命令緩衝區的總容量,與目前使用量無關。
語法
u8 vram_get_queue_capacity();回傳值
以此處說明的平台單位表示的無號八位元值。讀取不會修改或執行佇列。
使用條件與限制
GB以命令槽計數,預設容量32。每個加入函式使用一個槽,大型傳輸或零長度傳輸也一樣。VRAM_QUEUE_MAX應在所有編譯單元中一致設為1至255。空佇列為used=0、free=capacity。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
capacity=vram_get_queue_capacity();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
CGB模式下,上方兩個正方形、三圖樣複製和最後透過VBlank寫入的正方形為紅色;32×24矩形和雙圖樣複製為藍色;3×2圖塊區塊和40×8橫條為綠色。文字仍為白底黑字。除形狀外,還檢查每個繪製像素的顏色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/vram.h:69
Return the total number of command slots, independent of queue usage. This is command-buffer capacity, not free space in hardware VRAM.
kitaqgb/lib/vram.c:162
u8 vram_get_queue_capacity()
{
return VRAM_QUEUE_MAX;
}vram_get_queue_free
回傳命令緩衝區總容量減去目前用量。加入前應確認下一筆完整記錄或整個批次能否放下;此查詢不會預留空間。
語法
u8 vram_get_queue_free();回傳值
以此處說明的平台單位表示的無號八位元值。讀取不會修改或執行佇列。
使用條件與限制
GB以命令槽計數,預設容量32。每個加入函式使用一個槽,大型傳輸或零長度傳輸也一樣。VRAM_QUEUE_MAX應在所有編譯單元中一致設為1至255。空佇列為used=0、free=capacity。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
available=vram_get_queue_free();
if (used+available!=capacity) failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
CGB模式下,上方兩個正方形、三圖樣複製和最後透過VBlank寫入的正方形為紅色;32×24矩形和雙圖樣複製為藍色;3×2圖塊區塊和40×8橫條為綠色。文字仍為白底黑字。除形狀外,還檢查每個繪製像素的顏色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/vram.h:71
Return the remaining command-slot capacity.
kitaqgb/lib/vram.c:169
u8 vram_get_queue_free()
{
return (u8)(VRAM_QUEUE_MAX - kq_vram_queue_used);
}vram_get_queue_used
回傳待執行命令目前占用的命令緩衝區用量,不是將寫入視訊記憶體的資料位元組數。
語法
u8 vram_get_queue_used();回傳值
以此處說明的平台單位表示的無號八位元值。讀取不會修改或執行佇列。
使用條件與限制
GB以命令槽計數,預設容量32。每個加入函式使用一個槽,大型傳輸或零長度傳輸也一樣。VRAM_QUEUE_MAX應在所有編譯單元中一致設為1至255。空佇列為used=0、free=capacity。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
used=vram_get_queue_used();這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
CGB模式下,上方兩個正方形、三圖樣複製和最後透過VBlank寫入的正方形為紅色;32×24矩形和雙圖樣複製為藍色;3×2圖塊區塊和40×8橫條為綠色。文字仍為白底黑字。除形狀外,還檢查每個繪製像素的顏色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/vram.h:66
Return the number of queued commands, not the number of transfer bytes.
kitaqgb/lib/vram.c:155
u8 vram_get_queue_used()
{
return kq_vram_queue_used;
}vram_init
將延後執行的VRAM寫入命令佇列初始化為空,並清除溢位旗標。不會清除畫面、上傳圖塊圖形或配置硬體VRAM。
語法
void vram_init();回傳值
無(void)。
使用條件與限制
GB以命令槽計數,預設容量32。每個加入函式使用一個槽,大型傳輸或零長度傳輸也一樣。VRAM_QUEUE_MAX應在所有編譯單元中一致設為1至255。空佇列為used=0、free=capacity。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
vram_init();
if (vram_get_queue_used()!=0 || vram_get_overflowed()!=0) failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
CGB模式下,上方兩個正方形、三圖樣複製和最後透過VBlank寫入的正方形為紅色;32×24矩形和雙圖樣複製為藍色;3×2圖塊區塊和40×8橫條為綠色。文字仍為白底黑字。除形狀外,還檢查每個繪製像素的顏色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/vram.h:39
Start with an empty command queue and a clear overflow flag.
kitaqgb/lib/vram.c:34
void vram_init()
{
kq_vram_queue_used = 0;
kq_vram_queue_overflowed = 0;
}vram_queue_bg_block
將從src讀取w × h個圖塊編號並寫入base地圖矩形的操作加入佇列。來源資料每行緊密排列w位元組,目標行相隔32位元組。命令保留來源指標,因此執行前修改來源資料會改變最後顯示的區塊。
語法
u8 vram_queue_bg_block(u16 base, u8 x, u8 y, u8 w, u8 h, const u8* src);參數
base單圖塊和矩形命令在執行時依LCDC位元3選擇背景對映表。CGB圖塊編號應使用VRAM記憶體庫0。區塊傳輸使用指定的基底位址,通常為
0x9800或0x9C00。列跨度為32位元組,不裁切座標。x, y以8×8圖塊為單位的左上角座標,不是像素座標。不執行裁切。應滿足
x + w <= 32;GB的y + h <= 32,FC名稱表圖塊區域的y + h <= 30。單一圖塊以寬高均為1計算。w, h以無號八位元值指定圖塊寬高。來源區塊依行排列,共
w * h位元組。零尺寸不產生可見寫入,但佇列儲存用量遵循平台的記錄規則。src指向可讀位元組的近指標,保留到執行時。整個執行期間必須保持資料有效且其記憶體或ROM記憶體庫可存取;不儲存記憶體庫編號或資料副本。非空傳輸需要有效來源,不可使用生命週期已結束的區域陣列。
回傳值
本次命令入列成功回傳1,沒有空槽回傳0。失敗時設定溢位旗標並保留既有命令。先前的溢位本身不會使後續成功加入回傳0。
使用條件與限制
GB以命令槽計數,預設容量32。每個加入函式使用一個槽,大型傳輸或零長度傳輸也一樣。VRAM_QUEUE_MAX應在所有編譯單元中一致設為1至255。空佇列為used=0、free=capacity。
單圖塊和矩形命令在執行時依LCDC位元3選擇背景對映表。CGB圖塊編號應使用VRAM記憶體庫0。區塊傳輸使用指定的基底位址,通常為0x9800或0x9C00。列跨度為32位元組,不裁切座標。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
check_result=vram_queue_bg_block(MAP_BASE,10,4,3,2,block);
block[0]=1; // The queued pointer sees this change when the queue executes.
if (check_result!=1) failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
CGB模式下,上方兩個正方形、三圖樣複製和最後透過VBlank寫入的正方形為紅色;32×24矩形和雙圖樣複製為藍色;3×2圖塊區塊和40×8橫條為綠色。文字仍為白底黑字。除形狀外,還檢查每個繪製像素的顏色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/vram.h:50
Queue a tile-map rectangle while retaining src rather than copying its bytes. Keep the source data and its ROM bank accessible until the queue is flushed.
kitaqgb/lib/vram.c:79
u8 vram_queue_bg_block(u16 base, u8 x, u8 y, u8 w, u8 h, const u8* src)
{
VramCommand* cmd = vram_push(VRAM_CMD_BG_BLOCK);
if (cmd == 0) return 0;
cmd->dst = base;
cmd->x = x;
cmd->y = y;
cmd->w = w;
cmd->h = h;
cmd->src = src;
return 1;
}vram_queue_bg_rect
將使用同一圖塊編號填滿背景地圖矩形的操作加入佇列。左上角圖塊座標為(x, y),大小為w × h個圖塊。純色圖塊會形成實心矩形,有圖案的圖塊則會在每個格子重複圖案。
語法
u8 vram_queue_bg_rect(u8 x, u8 y, u8 w, u8 h, u8 tile);參數
x, y以8×8圖塊為單位的左上角座標,不是像素座標。不執行裁切。應滿足
x + w <= 32;GB的y + h <= 32,FC名稱表圖塊區域的y + h <= 30。單一圖塊以寬高均為1計算。w, h以無號八位元值指定圖塊寬高。來源區塊依行排列,共
w * h位元組。零尺寸不產生可見寫入,但佇列儲存用量遵循平台的記錄規則。tile0至255的圖塊地圖位元組。應另行載入對應圖形並選擇合適的圖案表或定址模式。圖塊編號不是指標或顏色值。
回傳值
本次命令入列成功回傳1,沒有空槽回傳0。失敗時設定溢位旗標並保留既有命令。先前的溢位本身不會使後續成功加入回傳0。
使用條件與限制
GB以命令槽計數,預設容量32。每個加入函式使用一個槽,大型傳輸或零長度傳輸也一樣。VRAM_QUEUE_MAX應在所有編譯單元中一致設為1至255。空佇列為used=0、free=capacity。
單圖塊和矩形命令在執行時依LCDC位元3選擇背景對映表。CGB圖塊編號應使用VRAM記憶體庫0。區塊傳輸使用指定的基底位址,通常為0x9800或0x9C00。列跨度為32位元組,不裁切座標。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
check_result=vram_queue_bg_rect(2,4,4,3,1); // A filled 32x24 rectangle at (16,32).
if (check_result!=1) failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
CGB模式下,上方兩個正方形、三圖樣複製和最後透過VBlank寫入的正方形為紅色;32×24矩形和雙圖樣複製為藍色;3×2圖塊區塊和40×8橫條為綠色。文字仍為白底黑字。除形狀外,還檢查每個繪製像素的顏色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/vram.h:47
Queue a rectangle filled with one tile value; coordinates and dimensions are in tiles.
kitaqgb/lib/vram.c:65
u8 vram_queue_bg_rect(u8 x, u8 y, u8 w, u8 h, u8 tile)
{
VramCommand* cmd = vram_push(VRAM_CMD_BG_RECT);
if (cmd == 0) return 0;
cmd->x = x;
cmd->y = y;
cmd->w = w;
cmd->h = h;
cmd->value = tile;
return 1;
}vram_queue_bg_tile
將一個向背景(x, y)寫入圖塊編號的命令加入佇列。可見圖塊在佇列執行時才改變。此命令寫入地圖項目,不上傳圖塊像素資料,也不改變調色盤屬性。
語法
u8 vram_queue_bg_tile(u8 x, u8 y, u8 tile);參數
x, y以8×8圖塊為單位的左上角座標,不是像素座標。不執行裁切。應滿足
x + w <= 32;GB的y + h <= 32,FC名稱表圖塊區域的y + h <= 30。單一圖塊以寬高均為1計算。tile0至255的圖塊地圖位元組。應另行載入對應圖形並選擇合適的圖案表或定址模式。圖塊編號不是指標或顏色值。
回傳值
本次命令入列成功回傳1,沒有空槽回傳0。失敗時設定溢位旗標並保留既有命令。先前的溢位本身不會使後續成功加入回傳0。
使用條件與限制
GB以命令槽計數,預設容量32。每個加入函式使用一個槽,大型傳輸或零長度傳輸也一樣。VRAM_QUEUE_MAX應在所有編譯單元中一致設為1至255。空佇列為used=0、free=capacity。
單圖塊和矩形命令在執行時依LCDC位元3選擇背景對映表。CGB圖塊編號應使用VRAM記憶體庫0。區塊傳輸使用指定的基底位址,通常為0x9800或0x9C00。列跨度為32位元組,不裁切座標。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
check_result=vram_queue_bg_tile(2,2,1); // A solid 8x8 tile at pixel (16,16).
if (check_result!=1) failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
CGB模式下,上方兩個正方形、三圖樣複製和最後透過VBlank寫入的正方形為紅色;32×24矩形和雙圖樣複製為藍色;3×2圖塊區塊和40×8橫條為綠色。文字仍為白底黑字。除形狀外,還檢查每個繪製像素的顏色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/vram.h:43
Queue a single background tile write; return zero if no command slot is available.
kitaqgb/lib/vram.c:48
u8 vram_queue_bg_tile(u8 x, u8 y, u8 tile)
{
VramCommand* cmd = vram_push(VRAM_CMD_BG_TILE);
if (cmd == 0) return 0;
cmd->x = x;
cmd->y = y;
cmd->value = tile;
return 1;
}vram_queue_memcpy
將從src向dst複製連續len位元組的操作加入佇列。來源與目標均逐位元組遞增,不使用圖塊行間距。可傳輸地圖位元組或可寫圖塊圖案位元組,但不會轉換格式或推算每個圖塊的位元組數。
語法
u8 vram_queue_memcpy(u16 dst, const void* src, u16 len);參數
dstVRAM中的目的位元組位址(
0x8000–0x9FFF),使用執行時選中的記憶體庫。傳輸位址連續,不在圖塊對映表列尾換列。整個目的範圍都必須有效。LCD開啟時,安全寫入路徑可能啟用中斷,不保留呼叫前的中斷停用狀態。src指向可讀位元組的近指標,保留到執行時。整個執行期間必須保持資料有效且其記憶體或ROM記憶體庫可存取;不儲存記憶體庫編號或資料副本。非空傳輸需要有效來源,不可使用生命週期已結束的區域陣列。
len連續位元組數,範圍0至65535,不是圖塊數。整個範圍應位於有效來源與可寫目標區域內;API不檢查邊界,也不防止十六位元位址回繞。
回傳值
本次命令入列成功回傳1,沒有空槽回傳0。失敗時設定溢位旗標並保留既有命令。先前的溢位本身不會使後續成功加入回傳0。
使用條件與限制
GB以命令槽計數,預設容量32。每個加入函式使用一個槽,大型傳輸或零長度傳輸也一樣。VRAM_QUEUE_MAX應在所有編譯單元中一致設為1至255。空佇列為used=0、free=capacity。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
check_result=vram_queue_memcpy(MAP_BASE+8*32+2,strip,3);
if (check_result!=1) failures++; // Copy three map bytes, not three tile patterns.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
CGB模式下,上方兩個正方形、三圖樣複製和最後透過VBlank寫入的正方形為紅色;32×24矩形和雙圖樣複製為藍色;3×2圖塊區塊和40×8橫條為綠色。文字仍為白底黑字。除形狀外,還檢查每個繪製像素的顏色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/vram.h:53
Queue a byte transfer and retain the source pointer. The source must remain valid and visible until flush; len is measured in bytes, not tiles.
kitaqgb/lib/vram.c:94
u8 vram_queue_memcpy(u16 dst, const void* src, u16 len)
{
VramCommand* cmd = vram_push(VRAM_CMD_MEMCPY);
if (cmd == 0) return 0;
cmd->dst = dst;
cmd->src = (const u8*)src;
cmd->len = len;
return 1;
}vram_queue_memset
將從dst開始的連續len位元組填為單一位元組value的操作加入佇列。重複的是一個位元組,不是多位元組圖塊圖案,也不會自動插入32位元組的地圖行間距。
語法
u8 vram_queue_memset(u16 dst, u8 value, u16 len);參數
dstVRAM中的目的位元組位址(
0x8000–0x9FFF),使用執行時選中的記憶體庫。傳輸位址連續,不在圖塊對映表列尾換列。整個目的範圍都必須有效。LCD開啟時,安全寫入路徑可能啟用中斷,不保留呼叫前的中斷停用狀態。value重複寫入0至255的單一位元組。顯示意義取決於目標是圖塊索引、像素位元平面還是其他位元組結構。
len連續位元組數,範圍0至65535,不是圖塊數。整個範圍應位於有效來源與可寫目標區域內;API不檢查邊界,也不防止十六位元位址回繞。
回傳值
本次命令入列成功回傳1,沒有空槽回傳0。失敗時設定溢位旗標並保留既有命令。先前的溢位本身不會使後續成功加入回傳0。
使用條件與限制
GB以命令槽計數,預設容量32。每個加入函式使用一個槽,大型傳輸或零長度傳輸也一樣。VRAM_QUEUE_MAX應在所有編譯單元中一致設為1至255。空佇列為used=0、free=capacity。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
check_result=vram_queue_memset(MAP_BASE+8*32+10,1,5);
if (check_result!=1) failures++; // Five solid tiles form a 40x8 horizontal bar.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
CGB模式下,上方兩個正方形、三圖樣複製和最後透過VBlank寫入的正方形為紅色;32×24矩形和雙圖樣複製為藍色;3×2圖塊區塊和40×8橫條為綠色。文字仍為白底黑字。除形狀外,還檢查每個繪製像素的顏色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/vram.h:57
Queue a byte fill and return zero if the command queue is full.
kitaqgb/lib/vram.c:111
u8 vram_queue_memset(u16 dst, u8 value, u16 len)
{
VramCommand* cmd = vram_push(VRAM_CMD_MEMSET);
if (cmd == 0) return 0;
cmd->dst = dst;
cmd->value = value;
cmd->len = len;
return 1;
}vram_queue_tile
vram_queue_tile用相同參數直接呼叫vram_queue_bg_tile並回傳相同結果。這是寫入單一背景地圖項目的簡寫名稱,不是精靈操作或圖塊圖形上傳。
語法
u8 vram_queue_tile(u8 x, u8 y, u8 tile);參數
x, y以8×8圖塊為單位的左上角座標,不是像素座標。不執行裁切。應滿足
x + w <= 32;GB的y + h <= 32,FC名稱表圖塊區域的y + h <= 30。單一圖塊以寬高均為1計算。tile0至255的圖塊地圖位元組。應另行載入對應圖形並選擇合適的圖案表或定址模式。圖塊編號不是指標或顏色值。
回傳值
本次命令入列成功回傳1,沒有空槽回傳0。失敗時設定溢位旗標並保留既有命令。先前的溢位本身不會使後續成功加入回傳0。
使用條件與限制
GB以命令槽計數,預設容量32。每個加入函式使用一個槽,大型傳輸或零長度傳輸也一樣。VRAM_QUEUE_MAX應在所有編譯單元中一致設為1至255。空佇列為used=0、free=capacity。
單圖塊和矩形命令在執行時依LCDC位元3選擇背景對映表。CGB圖塊編號應使用VRAM記憶體庫0。區塊傳輸使用指定的基底位址,通常為0x9800或0x9C00。列跨度為32位元組,不裁切座標。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
check_result=vram_queue_tile(4,2,1); // The short alias draws at pixel (32,16).
if (check_result!=1) failures++;這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
CGB模式下,上方兩個正方形、三圖樣複製和最後透過VBlank寫入的正方形為紅色;32×24矩形和雙圖樣複製為藍色;3×2圖塊區塊和40×8橫條為綠色。文字仍為白底黑字。除形狀外,還檢查每個繪製像素的顏色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/vram.h:45
Provide the short alias for a queued background tile write.
kitaqgb/lib/vram.c:59
u8 vram_queue_tile(u8 x, u8 y, u8 tile)
{
return vram_queue_bg_tile(x, y, tile);
}vram_queue_tiles
vram_queue_tiles直接呼叫vram_queue_memcpy。len仍是位元組數,不是圖塊數。保留的來源指標、佇列記錄、回傳值及執行時機均相同。
語法
u8 vram_queue_tiles(u16 dst, const void* src, u16 len);參數
dstVRAM中的目的位元組位址(
0x8000–0x9FFF),使用執行時選中的記憶體庫。傳輸位址連續,不在圖塊對映表列尾換列。整個目的範圍都必須有效。LCD開啟時,安全寫入路徑可能啟用中斷,不保留呼叫前的中斷停用狀態。src指向可讀位元組的近指標,保留到執行時。整個執行期間必須保持資料有效且其記憶體或ROM記憶體庫可存取;不儲存記憶體庫編號或資料副本。非空傳輸需要有效來源,不可使用生命週期已結束的區域陣列。
len連續位元組數,範圍0至65535,不是圖塊數。整個範圍應位於有效來源與可寫目標區域內;API不檢查邊界,也不防止十六位元位址回繞。
回傳值
本次命令入列成功回傳1,沒有空槽回傳0。失敗時設定溢位旗標並保留既有命令。先前的溢位本身不會使後續成功加入回傳0。
使用條件與限制
GB以命令槽計數,預設容量32。每個加入函式使用一個槽,大型傳輸或零長度傳輸也一樣。VRAM_QUEUE_MAX應在所有編譯單元中一致設為1至255。空佇列為used=0、free=capacity。
應協調佇列建立與執行階段。不要在中斷執行佇列時加入、直接修改管理變數或意外覆寫保留的來源資料。這些API不提供鎖定或雙重緩衝。容量指命令緩衝區,不是硬體VRAM可用位元組數。
使用範例
check_result=vram_queue_tiles(MAP_BASE+8*32+6,strip+1,2);
if (check_result!=1) failures++; // This alias also measures length in bytes.這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
完整程式示範延後寫入、佇列容量管理和溢位復原。7次繪圖加入在GB上使用32個槽中的7個,在FC上使用128位元組中的52位元組。CAPACITY/USED/FREE分別顯示032/007/025或128/052/076。AFTER FLUSH和FAILED CHECKS應為000,OVERFLOW SEEN應為001。程式刻意向已滿佇列加入資料來檢查溢位旗標;讀取或執行不會清除旗標,清空佇列才會。FC還會檢查未提交時直接執行不會改變待處理佇列。
影像座標以左上角為原點,單位為像素。應在(16,16)和(32,16)看到8×8實心正方形,在(16,32)看到32×24實心矩形,在(80,64)看到40×8橫條。最後一次VBlank寫入在(144,80)加入8×8正方形。已取消的寫入位置(144,24)必須保持空白。DMG為白底黑圖形,CGB為白底紅、藍、綠圖形,FC為黑底紅、藍、綠圖形。這些模擬器影像不代表實機驗證。
使用三種自製8×8圖樣區分複製操作:圖塊1全部填滿,2只填左側四欄,3為靠左的三角形,從頂部1像素逐列加寬至底部8像素。(80,32)處的3×2圖塊區塊應為[1,2,3] / [3,0,2],0表示空白。來源資料首位元組在加入佇列後修改,因此左上角出現實心圖塊可證明保留的是來源指標。(16,64)的複製顯示[1,2,3],(48,64)的tiles別名顯示[2,3]。三者大小依序為24×16、24×8和16×8像素。
CGB模式下,上方兩個正方形、三圖樣複製和最後透過VBlank寫入的正方形為紅色;32×24矩形和雙圖樣複製為藍色;3×2圖塊區塊和40×8橫條為綠色。文字仍為白底黑字。除形狀外,還檢查每個繪製像素的顏色。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm實作與原始碼
kitaqgb/lib/vram.h:55
Alias the queued byte-copy operation; this does not convert a tile count to bytes.
kitaqgb/lib/vram.c:105
u8 vram_queue_tiles(u16 dst, const void* src, u16 len)
{
return vram_queue_memcpy(dst, src, len);
}wire3d.h — DMG 線框
單色 3D 線段繪製。須提供模型頂點、邊、面,以及物件位置、旋轉與倍率。依初始化、影格開始、繪製、上傳的順序使用。物理另行處理。角度每圈 16 步;模型倍率 256 為一倍。
Vec3 儲存 x/y/z,Edge 儲存頂點索引 a/b,Face 儲存三角形索引 a/b/c。Model 的 vertices、edges、faces 指向這些陣列,各計數表示其長度。edge_faces 包含相鄰面索引 f0/f1,缺少的面以 FACE_NONE 表示。flags 中的 MODEL_HIDDEN_LINES 要求依面選擇邊。投影後的有號面積決定面朝向,因此頂點順序很重要。
Object 儲存模型參照、位置 x/y/z、角度 rx/ry/rz、scale_q8 與 visible。物件可共用模型,但繪製不會複製表或自動切換其 ROM 記憶體庫。整個繪製期間須保持參照資料可讀。CGB 的 Object 另有色彩索引。
高度 96 的 Model 另含 edge_masks 與 edge_mask_count。請提供依物件偏航選取之 16 位元邊遮罩的 RAM 表;不使用時將兩欄位皆設為零。
Wire3D_BeginFrame
開始繪製影格並停用遮蔽檢查。
語法
void Wire3D_BeginFrame();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96. 清空暫存像素與遮蔽遮罩,並停用遮蔽篩選。不改變目前顯示的 VRAM 影格與待處理 BG 圖塊佇列。
此範例使用 128×96 設定,視埠從畫面 (0,0) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
Wire3D_SetCamera(8,0,0,0,0,0);
result[1]=Wire3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=Wire3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
Wire3D_SetCamera(0,0,0,0,0,0);
Wire3D_BeginFrame();
Wire3D_DrawLine2D(8,8,56,8);
Wire3D_DrawLine2D(56,8,56,40);
Wire3D_DrawLine2D(56,40,8,40);
Wire3D_DrawLine2D(8,40,8,8);
Wire3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
Wire3D_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
Wire3D_PutBgTile(18,1,157);
Wire3D_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_raster.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d.h:34
WIRE3D_DMG_HEIGHT = 96. Clear staged pixels and occlusion mask and disable occlusion filtering. This leaves the displayed VRAM frame and pending BG tile queue unchanged.
kitaqgb/lib/wire3d_dmg.c:2641
void Wire3DDMG_BeginFrame()
{
w3ddmg_clear_stage_asm();
w3ddmg_clear_occlusion_mask();
w3ddmg_occlusion_active = 0;
}Wire3D_DrawLine2D
在暫存區繪製包含兩端點、四連通的畫面空間線段。
語法
void Wire3D_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by);參數
ax頂點 A 的 X 座標,以視埠像素為單位。
ay頂點 A 的 Y 座標,以視埠像素為單位。
bx頂點 B 的 X 座標,以視埠像素為單位。
by頂點 B 的 Y 座標,以視埠像素為單位。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96. 在 128×96 暫存區繪製包含端點的連通線。DrawScene 期間採用五點取樣的粗略遮蔽剔除,其他情況直接繪製。須提供視埠座標。VRAM 僅由 EndFrame 更新。
此範例使用 128×96 設定,視埠從畫面 (0,0) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
Wire3D_SetCamera(8,0,0,0,0,0);
result[1]=Wire3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=Wire3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
Wire3D_SetCamera(0,0,0,0,0,0);
Wire3D_BeginFrame();
Wire3D_DrawLine2D(8,8,56,8);
Wire3D_DrawLine2D(56,8,56,40);
Wire3D_DrawLine2D(56,40,8,40);
Wire3D_DrawLine2D(8,40,8,8);
Wire3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
Wire3D_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
Wire3D_PutBgTile(18,1,157);
Wire3D_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_raster.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d.h:35
WIRE3D_DMG_HEIGHT = 96. Draw a connected line into the 128x96 stage, including endpoints. During DrawScene, use the coarse five-sample occlusion rejection; otherwise draw directly. Supply viewport coordinates. VRAM is updated only by EndFrame.
kitaqgb/lib/wire3d_dmg.c:2685
void Wire3DDMG_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by)
{
if (w3ddmg_occlusion_active)
{
w3ddmg_line_stage_masked_c(ax, ay, bx, by);
return;
}
w3ddmg_line_x0 = ax;
w3ddmg_line_y0 = ay;
w3ddmg_line_x1 = bx;
w3ddmg_line_y1 = by;
if (ax < 128 && bx < 128 && ay < WIRE3D_DMG_SCREEN_H && by < WIRE3D_DMG_SCREEN_H)
w3ddmg_line_inside_asm();
else
w3ddmg_line_stage_asm();
}Wire3D_DrawLine3D
投影兩個世界座標端點,並在其間繪製線段。
語法
void Wire3D_DrawLine3D(w3ddmg_i16 ax, w3ddmg_i16 ay, w3ddmg_i16 az, w3ddmg_i16 bx, w3ddmg_i16 by, w3ddmg_i16 bz);參數
ax起點的世界座標 X 分量。
ay起點的世界座標 Y 分量。
az起點的世界座標 Z 分量。
bx終點的世界座標 X 分量。
by終點的世界座標 Y 分量。
bz終點的世界座標 Z 分量。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96. 投影兩個世界座標端點,僅在兩者均通過深度範圍時繪製。不求跨界線段與近/遠平面的交點;投影後端點各自限制於畫面邊緣。
此範例使用 128×96 設定,視埠從畫面 (0,0) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
Wire3D_SetCamera(8,0,0,0,0,0);
result[1]=Wire3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=Wire3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
Wire3D_SetCamera(0,0,0,0,0,0);
Wire3D_BeginFrame();
Wire3D_DrawLine2D(8,8,56,8);
Wire3D_DrawLine2D(56,8,56,40);
Wire3D_DrawLine2D(56,40,8,40);
Wire3D_DrawLine2D(8,40,8,8);
Wire3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
Wire3D_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
Wire3D_PutBgTile(18,1,157);
Wire3D_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_raster.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d.h:36
WIRE3D_DMG_HEIGHT = 96. Project both world endpoints and draw only when both pass the depth range. Do not intersect a crossing segment with near/far planes; projected endpoints are independently clamped to the screen edges.
kitaqgb/lib/wire3d_dmg.c:2808
void Wire3DDMG_DrawLine3D(w3ddmg_i16 ax, w3ddmg_i16 ay, w3ddmg_i16 az, w3ddmg_i16 bx, w3ddmg_i16 by, w3ddmg_i16 bz)
{
w3ddmg_u8 sx0;
w3ddmg_u8 sy0;
w3ddmg_u8 sx1;
w3ddmg_u8 sy1;
if (w3ddmg_project_world(ax, ay, az, &sx0, &sy0) == 0) return;
if (w3ddmg_project_world(bx, by, bz, &sx1, &sy1) == 0) return;
Wire3DDMG_DrawLine2D(sx0, sy0, sx1, sy1);
}Wire3D_DrawModel
以指定位置與旋轉,按原倍率繪製頂點與邊組成的模型。
語法
void Wire3D_DrawModel(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz);參數
model包含頂點、邊、面陣列及數量的模型;呼叫期間須保持各表可讀。
x點或物件原點的世界座標 X 分量。
y點或物件原點的世界座標 Y 分量。
z點或物件原點的世界座標 Z 分量。
rx繞 X 軸旋轉;十六步為一整圈。
ry繞 Y 軸旋轉;十六步為一整圈。
rz繞 Z 軸旋轉;十六步為一整圈。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96. 以倍率 256 委派給 DrawModelScaled,按原大小繪製模型。
此範例使用 128×96 設定,視埠從畫面 (0,0) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3D_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom Wire3D_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
Wire3D_Model cube;
Wire3D_Object objects[2];
u16 masks[2];
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;
cube.edge_masks=0; cube.edge_mask_count=0;
Wire3D_BeginFrame();
// Upper pair: direct model calls at unity and half scale.
Wire3D_DrawModel(&cube,-32,32,96,0,0,0);
Wire3D_DrawModelScaled(&cube,32,32,96,0,0,0,128);
// Lower pair: the caller owns both object records and the model tables.
for(i=0;i<2;i++) {
objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
objects[i].y=-32;objects[i].z=96;
objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
}
Wire3D_DrawScene(objects,2);
// Numeric checks cover the operation supplied by this viewport profile.
masks[0]=3;masks[1]=12;cube.edge_masks=masks; cube.edge_mask_count=2;
result[1]=Wire3D_SelectEdgeMask(&cube,0,0,0);
result[2]=Wire3D_SelectEdgeMask(&cube,0,8,0);
Wire3D_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
原倍率與半倍率模型顯示在相同倍率的物件陣列場景上方,用以示範投影與縮放。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_models.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d.h:37
WIRE3D_DMG_HEIGHT = 96. Draw an unscaled model by delegating to DrawModelScaled with scale 256.
kitaqgb/lib/wire3d_dmg.c:2825
void Wire3DDMG_DrawModel(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz)
{
Wire3DDMG_DrawModelScaled(model, x, y, z, rx, ry, rz, 256);
}Wire3D_DrawModelScaled
縮放模型,依 Y/X/Z 順序旋轉,平移並投影頂點,再繪製邊。
語法
void Wire3D_DrawModelScaled(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz, w3ddmg_i16 scale_q8);參數
model包含頂點、邊、面陣列及數量的模型;呼叫期間須保持各表可讀。
x點或物件原點的世界座標 X 分量。
y點或物件原點的世界座標 Y 分量。
z點或物件原點的世界座標 Z 分量。
rx繞 X 軸旋轉;十六步為一整圈。
ry繞 Y 軸旋轉;十六步為一整圈。
rz繞 Z 軸旋轉;十六步為一整圈。
scale_q8倍率,以 256 表示一倍;非正值也視為一倍。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96. 縮放最多 24 個頂點,依 Y/X/Z 順序旋轉、平移並投影,再以偏航遮罩與可選的正面篩選繪製最多 16 條邊。非正倍率轉為一倍(256)。忽略 null 模型/頂點/邊指標;參照的表須保持可讀。縮放乘積與平移結果須在有號 16 位元範圍內。跨越深度邊界的邊會捨棄,不會裁切。
此範例使用 128×96 設定,視埠從畫面 (0,0) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3D_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom Wire3D_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
Wire3D_Model cube;
Wire3D_Object objects[2];
u16 masks[2];
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;
cube.edge_masks=0; cube.edge_mask_count=0;
Wire3D_BeginFrame();
// Upper pair: direct model calls at unity and half scale.
Wire3D_DrawModel(&cube,-32,32,96,0,0,0);
Wire3D_DrawModelScaled(&cube,32,32,96,0,0,0,128);
// Lower pair: the caller owns both object records and the model tables.
for(i=0;i<2;i++) {
objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
objects[i].y=-32;objects[i].z=96;
objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
}
Wire3D_DrawScene(objects,2);
// Numeric checks cover the operation supplied by this viewport profile.
masks[0]=3;masks[1]=12;cube.edge_masks=masks; cube.edge_mask_count=2;
result[1]=Wire3D_SelectEdgeMask(&cube,0,0,0);
result[2]=Wire3D_SelectEdgeMask(&cube,0,8,0);
Wire3D_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
原倍率與半倍率模型顯示在相同倍率的物件陣列場景上方,用以示範投影與縮放。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_models.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d.h:38
WIRE3D_DMG_HEIGHT = 96. Scale, rotate in Y/X/Z order, translate and project at most 24 vertices; then draw up to 16 edges filtered by yaw masks and optional front-facing faces. Nonpositive scale becomes unity (256). Null model/vertex/edge pointers are ignored; referenced tables must remain readable. Keep scale products and translations in signed 16-bit range. Depth-crossing edges are dropped, not clipped.
kitaqgb/lib/wire3d_dmg.c:2965
void Wire3DDMG_DrawModelScaled(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz, w3ddmg_i16 scale_q8)
{
w3ddmg_u8 i;
w3ddmg_u8 count;
w3ddmg_u8 edge_count;
w3ddmg_u8 face_count;
if (model == 0) return;
if (model->vertices == 0) return;
if (model->edges == 0) return;
if (scale_q8 <= 0) scale_q8 = 256;
count = model->vertex_count;
if (count > WIRE3D_DMG_MODEL_VERTEX_LIMIT) count = WIRE3D_DMG_MODEL_VERTEX_LIMIT;
i = 0;
while (i < count)
{
const Wire3DDMG_Vec3* v;
w3ddmg_i16 vx;
w3ddmg_i16 vy;
w3ddmg_i16 vz;
w3ddmg_u8 sx;
w3ddmg_u8 sy;
v = &model->vertices[(__safe_index w3ddmg_u8)i];
vx = (w3ddmg_i16)((v->x * scale_q8) >> 8);
vy = (w3ddmg_i16)((v->y * scale_q8) >> 8);
vz = (w3ddmg_i16)((v->z * scale_q8) >> 8);
w3ddmg_rotate_y(&vx, &vz, (w3ddmg_i8)ry);
w3ddmg_rotate_x(&vy, &vz, (w3ddmg_i8)rx);
w3ddmg_rotate_z(&vx, &vy, (w3ddmg_i8)rz);
vx = (w3ddmg_i16)(vx + x);
vy = (w3ddmg_i16)(vy + y);
vz = (w3ddmg_i16)(vz + z);
if (w3ddmg_project_world(vx, vy, vz, &sx, &sy))
{
w3ddmg_screen_x[(__safe_index w3ddmg_u8)i] = sx;
w3ddmg_screen_y[(__safe_index w3ddmg_u8)i] = sy;
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 1;
}
else
{
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 0;
}
i = (w3ddmg_u8)(i + 1);
}
face_count = model->face_count;
if (face_count > WIRE3D_DMG_MODEL_FACE_LIMIT) face_count = WIRE3D_DMG_MODEL_FACE_LIMIT;
if ((model->flags & WIRE3D_DMG_MODEL_HIDDEN_LINES) && (model->faces != 0) && (model->edge_faces != 0))
{
w3ddmg_build_face_visibility(model, count, face_count);
}
edge_count = model->edge_count;
if (edge_count > WIRE3D_DMG_MODEL_EDGE_LIMIT) edge_count = WIRE3D_DMG_MODEL_EDGE_LIMIT;
w3ddmg_build_edge_flags(model, edge_count, face_count, rx, ry, rz);
i = 0;
while (i < edge_count)
{
const Wire3DDMG_Edge* e;
e = &model->edges[(__safe_index w3ddmg_u8)i];
if ((e->a < count) && (e->b < count))
{
if (w3ddmg_screen_visible[(__safe_index w3ddmg_u8)e->a] &&
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)e->b] &&
w3ddmg_edge_flags[(__safe_index w3ddmg_u8)i])
{
Wire3DDMG_DrawLine2D(
w3ddmg_screen_x[(__safe_index w3ddmg_u8)e->a],
w3ddmg_screen_y[(__safe_index w3ddmg_u8)e->a],
w3ddmg_screen_x[(__safe_index w3ddmg_u8)e->b],
w3ddmg_screen_y[(__safe_index w3ddmg_u8)e->b]);
}
}
i = (w3ddmg_u8)(i + 1);
}
}Wire3D_DrawScene
由近至遠繪製最多八個物件,以較近的面遮住後續邊。
語法
void Wire3D_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count);參數
objects包含位置、旋轉、倍率與可見旗標的物件陣列。
count提供的陣列項目數;處理上限請參閱各操作的說明。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96. 最多處理前八個物件,依變換後原點深度由近至遠排序。繪製可見且有效的模型,再標記其正面外接矩形,以拒絕後續取樣點全部被遮住的線段。這是物件間遮蔽的近似,不是深度緩衝區。會清空自身遮罩,但保留既有暫存像素。忽略 null 陣列;物件與其資料須保持可讀。
此範例使用 128×96 設定,視埠從畫面 (0,0) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3D_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom Wire3D_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
Wire3D_Model cube;
Wire3D_Object objects[2];
u16 masks[2];
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;
cube.edge_masks=0; cube.edge_mask_count=0;
Wire3D_BeginFrame();
// Upper pair: direct model calls at unity and half scale.
Wire3D_DrawModel(&cube,-32,32,96,0,0,0);
Wire3D_DrawModelScaled(&cube,32,32,96,0,0,0,128);
// Lower pair: the caller owns both object records and the model tables.
for(i=0;i<2;i++) {
objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
objects[i].y=-32;objects[i].z=96;
objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
}
Wire3D_DrawScene(objects,2);
// Numeric checks cover the operation supplied by this viewport profile.
masks[0]=3;masks[1]=12;cube.edge_masks=masks; cube.edge_mask_count=2;
result[1]=Wire3D_SelectEdgeMask(&cube,0,0,0);
result[2]=Wire3D_SelectEdgeMask(&cube,0,8,0);
Wire3D_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
原倍率與半倍率模型顯示在相同倍率的物件陣列場景上方,用以示範投影與縮放。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_models.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d.h:39
WIRE3D_DMG_HEIGHT = 96. Process at most the first eight objects, sorted near to far by transformed origin depth. Draw visible valid models, then mark their front-face bounding rectangles to reject fully sampled later lines. This approximates inter-object occlusion, not a depth buffer. It clears its mask but retains existing staged pixels. Null arrays are ignored; objects and their data must remain readable.
kitaqgb/lib/wire3d_dmg.c:2723
void Wire3DDMG_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count)
{
w3ddmg_u8 scene_count;
w3ddmg_u8 i;
if (objects == 0) return;
scene_count = count;
if (scene_count > WIRE3D_DMG_SCENE_OBJECT_LIMIT) scene_count = WIRE3D_DMG_SCENE_OBJECT_LIMIT;
i = 0;
while (i < scene_count)
{
w3ddmg_scene_order[(__safe_index w3ddmg_u8)i] = i;
w3ddmg_scene_depth[(__safe_index w3ddmg_u8)i] = w3ddmg_scene_object_depth(&objects[(__safe_index w3ddmg_u8)i]);
i = (w3ddmg_u8)(i + 1);
}
i = 0;
while (i < scene_count)
{
w3ddmg_u8 j;
j = (w3ddmg_u8)(i + 1);
while (j < scene_count)
{
w3ddmg_u8 oi;
w3ddmg_u8 oj;
oi = w3ddmg_scene_order[(__safe_index w3ddmg_u8)i];
oj = w3ddmg_scene_order[(__safe_index w3ddmg_u8)j];
// Put the nearer origin first so its face bounds can suppress later lines.
// The array itself stays in caller order; only the scratch index list is sorted.
if (w3ddmg_scene_depth[(__safe_index w3ddmg_u8)oj] < w3ddmg_scene_depth[(__safe_index w3ddmg_u8)oi])
{
w3ddmg_scene_order[(__safe_index w3ddmg_u8)i] = oj;
w3ddmg_scene_order[(__safe_index w3ddmg_u8)j] = oi;
}
j = (w3ddmg_u8)(j + 1);
}
i = (w3ddmg_u8)(i + 1);
}
w3ddmg_clear_occlusion_mask();
w3ddmg_occlusion_active = 1;
i = 0;
while (i < scene_count)
{
Wire3DDMG_Object* obj;
obj = &objects[(__safe_index w3ddmg_u8)w3ddmg_scene_order[(__safe_index w3ddmg_u8)i]];
if ((obj->visible != 0) && (obj->model != 0))
{
Wire3DDMG_DrawModelScaled(obj->model, obj->x, obj->y, obj->z, (w3ddmg_i8)obj->rx, (w3ddmg_i8)obj->ry, (w3ddmg_i8)obj->rz, obj->scale_q8);
w3ddmg_mark_model_occluder(obj->model);
}
i = (w3ddmg_u8)(i + 1);
}
w3ddmg_occlusion_active = 0;
}Wire3D_EndFrame
將待處理背景寫入與暫存繪圖提交至 VRAM。
語法
void Wire3D_EndFrame();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96. 等待下一次 VBlank,送出待處理的 BG 地圖寫入,再輪詢可存取時段,將暫存區複製至 VRAM。複製會消耗暫存像素。傳輸可能超出 VBlank;這不是原子影格交換。
此範例使用 128×96 設定,視埠從畫面 (0,0) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
Wire3D_SetCamera(8,0,0,0,0,0);
result[1]=Wire3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=Wire3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
Wire3D_SetCamera(0,0,0,0,0,0);
Wire3D_BeginFrame();
Wire3D_DrawLine2D(8,8,56,8);
Wire3D_DrawLine2D(56,8,56,40);
Wire3D_DrawLine2D(56,40,8,40);
Wire3D_DrawLine2D(8,40,8,8);
Wire3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
Wire3D_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
Wire3D_PutBgTile(18,1,157);
Wire3D_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_raster.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d.h:42
WIRE3D_DMG_HEIGHT = 96. Wait for the next VBlank, flush pending BG map writes, then copy the stage to VRAM while polling access windows. Copying consumes the staged pixels. The transfer may extend beyond VBlank; this is not an atomic frame swap.
kitaqgb/lib/wire3d_dmg.c:3081
void Wire3DDMG_EndFrame()
{
w3ddmg_wait_vblank_start();
w3ddmg_flush_bg_queue();
w3ddmg_transfer_stage_asm();
}Wire3D_EraseModelFaces
投影模型朝前的三角形,並擦除其內部暫存像素。
語法
void Wire3D_EraseModelFaces(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz, w3ddmg_i16 scale_q8);參數
model包含頂點、邊、面陣列及數量的模型;呼叫期間須保持各表可讀。
x點或物件原點的世界座標 X 分量。
y點或物件原點的世界座標 Y 分量。
z點或物件原點的世界座標 Z 分量。
rx繞 X 軸旋轉;十六步為一整圈。
ry繞 Y 軸旋轉;十六步為一整圈。
rz繞 Z 軸旋轉;十六步為一整圈。
scale_q8倍率,以 256 表示一倍;非正值也視為一倍。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96. 對具有隱線旗標與面資料的模型,投影最多 24 個頂點,並從暫存區擦除朝前三角形的內部。非正倍率表示 256(一倍)。最多考慮 16 個面,跨越深度邊界的面會略過。亦會替換共用投影快取,但不更新 VRAM。
此範例使用 128×96 設定,視埠從畫面 (0,0) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Erase a screen triangle and a projected model face from separate filled panels.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3D_Vec3 vertices[4]={{-24,-24,0},{24,-24,0},{24,24,0},{-24,24,0}};
__prg_rom Wire3D_Edge edges[4]={{0,1},{1,2},{2,3},{3,0}};
__prg_rom Wire3D_Face faces[2]={{0,2,1},{0,3,2}};
Wire3D_Model plane;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
plane.vertices=vertices;plane.edges=edges;plane.faces=faces;plane.edge_faces=0;
plane.vertex_count=4;plane.edge_count=4;plane.face_count=2;plane.flags=1;plane.edge_masks=0;plane.edge_mask_count=0;
Wire3D_BeginFrame();
// Separate panels show a direct screen triangle and a projected square face.
for(i=8;i<=32;i++) Wire3D_DrawLine2D(8,i,32,i);
for(i=24;i<=72;i++) Wire3D_DrawLine2D(40,i,88,i);
Wire3D_EraseTriangle2D(12,12,28,12,12,28);
Wire3D_EraseModelFaces(&plane,0,0,64,0,0,0,256);
Wire3D_EndFrame(); result[7]=0xA55A; while(1) {}
}預期結果
投影後的面會擦除填滿區域,可看出保留與清除的部分。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_faces.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_faces.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d.h:43
WIRE3D_DMG_HEIGHT = 96. Project up to 24 vertices and erase front-facing triangle interiors from the stage for a model with hidden-line flags and face data. Nonpositive scale means 256 (unity). Up to 16 faces are considered; depth-crossing faces are skipped. This also replaces shared projection caches, but does not update VRAM.
kitaqgb/lib/wire3d_dmg.c:2841
void Wire3DDMG_EraseModelFaces(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz, w3ddmg_i16 scale_q8)
{
w3ddmg_u8 i;
w3ddmg_u8 count;
w3ddmg_u8 face_count;
if (model == 0) return;
if (model->vertices == 0) return;
if (model->faces == 0) return;
if ((model->flags & WIRE3D_DMG_MODEL_HIDDEN_LINES) == 0) return;
if (scale_q8 <= 0) scale_q8 = 256;
count = model->vertex_count;
if (count > WIRE3D_DMG_MODEL_VERTEX_LIMIT) count = WIRE3D_DMG_MODEL_VERTEX_LIMIT;
i = 0;
while (i < count)
{
const Wire3DDMG_Vec3* v;
w3ddmg_i16 vx;
w3ddmg_i16 vy;
w3ddmg_i16 vz;
w3ddmg_u8 sx;
w3ddmg_u8 sy;
v = &model->vertices[(__safe_index w3ddmg_u8)i];
vx = (w3ddmg_i16)((v->x * scale_q8) >> 8);
vy = (w3ddmg_i16)((v->y * scale_q8) >> 8);
vz = (w3ddmg_i16)((v->z * scale_q8) >> 8);
w3ddmg_rotate_y(&vx, &vz, (w3ddmg_i8)ry);
w3ddmg_rotate_x(&vy, &vz, (w3ddmg_i8)rx);
w3ddmg_rotate_z(&vx, &vy, (w3ddmg_i8)rz);
vx = (w3ddmg_i16)(vx + x);
vy = (w3ddmg_i16)(vy + y);
vz = (w3ddmg_i16)(vz + z);
if (w3ddmg_project_world(vx, vy, vz, &sx, &sy))
{
w3ddmg_screen_x[(__safe_index w3ddmg_u8)i] = sx;
w3ddmg_screen_y[(__safe_index w3ddmg_u8)i] = sy;
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 1;
}
else
{
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 0;
}
i = (w3ddmg_u8)(i + 1);
}
face_count = model->face_count;
if (face_count > WIRE3D_DMG_MODEL_FACE_LIMIT) face_count = WIRE3D_DMG_MODEL_FACE_LIMIT;
w3ddmg_build_face_visibility(model, count, face_count);
i = 0;
while (i < face_count)
{
const Wire3DDMG_Face* f;
f = &model->faces[(__safe_index w3ddmg_u8)i];
if (w3ddmg_face_visible[(__safe_index w3ddmg_u8)i] &&
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)f->a] &&
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)f->b] &&
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)f->c])
{
w3ddmg_clear_triangle(
w3ddmg_screen_x[(__safe_index w3ddmg_u8)f->a],
w3ddmg_screen_y[(__safe_index w3ddmg_u8)f->a],
w3ddmg_screen_x[(__safe_index w3ddmg_u8)f->b],
w3ddmg_screen_y[(__safe_index w3ddmg_u8)f->b],
w3ddmg_screen_x[(__safe_index w3ddmg_u8)f->c],
w3ddmg_screen_y[(__safe_index w3ddmg_u8)f->c]);
}
i = (w3ddmg_u8)(i + 1);
}
}Wire3D_EraseSpan2D
在暫存區的一列中擦除包含兩端點的水平跨度。
語法
void Wire3D_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1);參數
y要擦除之列的像素 Y 座標。
x0較小的 X 端點,以視埠像素為單位;排序與裁切依此操作的注意事項。
x1較大的 X 端點,以視埠像素為單位;排序與裁切依此操作的注意事項。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96. 排序 X 端點並擦除包含端點的暫存跨度。兩端點皆須在 0..127;無效 Y 會被忽略。此常式不代為裁切 X。
此範例使用 128×96 設定,視埠從畫面 (0,0) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
Wire3D_SetCamera(8,0,0,0,0,0);
result[1]=Wire3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=Wire3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
Wire3D_SetCamera(0,0,0,0,0,0);
Wire3D_BeginFrame();
Wire3D_DrawLine2D(8,8,56,8);
Wire3D_DrawLine2D(56,8,56,40);
Wire3D_DrawLine2D(56,40,8,40);
Wire3D_DrawLine2D(8,40,8,8);
Wire3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
Wire3D_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
Wire3D_PutBgTile(18,1,157);
Wire3D_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_raster.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d.h:44
WIRE3D_DMG_HEIGHT = 96. Order the X endpoints and erase the inclusive staged span. Both endpoints must be in 0..127; invalid Y is ignored. The routine does not clip X for you.
kitaqgb/lib/wire3d_dmg.c:2943
void Wire3DDMG_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1)
{
w3ddmg_u8 tx;
if (x0 > x1)
{
tx = x0;
x0 = x1;
x1 = tx;
}
w3ddmg_stage_clear_span(y, x0, x1);
}Wire3D_EraseTriangle2D
使用水平掃描線跨度,從暫存區擦除畫面空間三角形。
語法
void Wire3D_EraseTriangle2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by, w3ddmg_u8 cx, w3ddmg_u8 cy);參數
ax頂點 A 的 X 座標,以視埠像素為單位。
ay頂點 A 的 Y 座標,以視埠像素為單位。
bx頂點 B 的 X 座標,以視埠像素為單位。
by頂點 B 的 Y 座標,以視埠像素為單位。
cx頂點 C 的 X 座標,以視埠像素為單位。
cy頂點 C 的 Y 座標,以視埠像素為單位。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96. 利用整數掃描線交點,從暫存像素擦除三角形。須提供視埠座標。忽略退化三角形;遮蔽遮罩與 VRAM 不變。
此範例使用 128×96 設定,視埠從畫面 (0,0) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Erase a screen triangle and a projected model face from separate filled panels.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3D_Vec3 vertices[4]={{-24,-24,0},{24,-24,0},{24,24,0},{-24,24,0}};
__prg_rom Wire3D_Edge edges[4]={{0,1},{1,2},{2,3},{3,0}};
__prg_rom Wire3D_Face faces[2]={{0,2,1},{0,3,2}};
Wire3D_Model plane;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
plane.vertices=vertices;plane.edges=edges;plane.faces=faces;plane.edge_faces=0;
plane.vertex_count=4;plane.edge_count=4;plane.face_count=2;plane.flags=1;plane.edge_masks=0;plane.edge_mask_count=0;
Wire3D_BeginFrame();
// Separate panels show a direct screen triangle and a projected square face.
for(i=8;i<=32;i++) Wire3D_DrawLine2D(8,i,32,i);
for(i=24;i<=72;i++) Wire3D_DrawLine2D(40,i,88,i);
Wire3D_EraseTriangle2D(12,12,28,12,12,28);
Wire3D_EraseModelFaces(&plane,0,0,64,0,0,0,256);
Wire3D_EndFrame(); result[7]=0xA55A; while(1) {}
}預期結果
投影後的面會擦除填滿區域,可看出保留與清除的部分。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_faces.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_faces.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d.h:45
WIRE3D_DMG_HEIGHT = 96. Erase a triangle from staged pixels using integer scanline intersections. Supply viewport coordinates. Degenerate triangles are ignored; the occlusion mask and VRAM are unchanged.
kitaqgb/lib/wire3d_dmg.c:2933
void Wire3DDMG_EraseTriangle2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by, w3ddmg_u8 cx, w3ddmg_u8 cy)
{
w3ddmg_clear_triangle(ax, ay, bx, by, cx, cy);
}Wire3D_Init
為單色線框視埠初始化 LCD、圖塊及背景地圖。
語法
void Wire3D_Init();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96. 接管 LCD:等待 VBlank 後關閉 LCD,清空 6144 個圖塊位元組與 BG 地圖,安裝 HUD 圖塊及採有號圖塊編號的 128×96 視埠,再以零捲動、BGP=0xB4 啟用 BG 顯示。重設相機、BG 佇列與暫存區。須保留 0xD000..0xDFFF 作為暫存區,並保持其 WRAM 記憶體庫映射。繪製前呼叫 BeginFrame,一併初始化遮蔽狀態。
此範例使用 128×96 設定,視埠從畫面 (0,0) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
Wire3D_SetCamera(8,0,0,0,0,0);
result[1]=Wire3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=Wire3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
Wire3D_SetCamera(0,0,0,0,0,0);
Wire3D_BeginFrame();
Wire3D_DrawLine2D(8,8,56,8);
Wire3D_DrawLine2D(56,8,56,40);
Wire3D_DrawLine2D(56,40,8,40);
Wire3D_DrawLine2D(8,40,8,8);
Wire3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
Wire3D_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
Wire3D_PutBgTile(18,1,157);
Wire3D_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_raster.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d.h:47
WIRE3D_DMG_HEIGHT = 96. Take over the LCD: wait for VBlank, switch it off, clear 6144 tile bytes and the BG map, install HUD tiles and the 128x96 signed-tile viewport, then enable BG display with scroll zero and BGP=0xB4. Reset camera, BG queue and stage. Reserve 0xD000..0xDFFF for staging and retain its WRAM bank mapping. Call BeginFrame before drawing to initialize the occlusion state as well.
kitaqgb/lib/wire3d_dmg.c:2572
void Wire3DDMG_Init()
{
w3ddmg_u8 row;
w3ddmg_u8 col;
w3ddmg_u8 tid;
w3ddmg_u16 off;
w3ddmg_wait_vblank_start();
w3ddmg_reg_lcdc = 0;
w3ddmg_clear_vram_asm();
w3ddmg_load_hud_tiles();
w3ddmg_fill_bg_map_asm();
row = 0;
tid = 0x90;
while (row < WIRE3D_DMG_TILE_H)
{
off = (w3ddmg_u16)((w3ddmg_u16)row << 5);
col = 0;
while (col < WIRE3D_DMG_TILE_W)
{
w3ddmg_bg_map_9800[(w3ddmg_u16)(off + (w3ddmg_u16)col)] = tid;
tid = (w3ddmg_u8)(tid + WIRE3D_DMG_TILE_H);
col = (w3ddmg_u8)(col + 1);
}
row = (w3ddmg_u8)(row + 1);
tid = (w3ddmg_u8)(0x90 + row);
}
w3ddmg_reg_scx = 0;
w3ddmg_reg_scy = 0;
w3ddmg_reg_bgp = 0xB4;
w3ddmg_reg_lcdc = 0x81;
w3ddmg_bgq_count = 0;
Wire3DDMG_SetCamera(0, 0, 0, 0, 0, 0);
w3ddmg_clear_stage_asm();
}Wire3D_ProjectPoint
將世界座標點透過相機投影至視埠座標。
語法
w3ddmg_u8 Wire3D_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy);參數
x點或物件原點的世界座標 X 分量。
y點或物件原點的世界座標 Y 分量。
z點或物件原點的世界座標 Z 分量。
sx接收投影 X 座標的有效可寫入 u8 指標。
sy接收投影 Y 座標的有效可寫入 u8 指標。
回傳值
投影成功傳回 1,深度遭拒傳回 0。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96. 以目前相機投影世界座標點。深度遭拒時傳回零並保留輸出;成功時寫入限制於 128×96 的座標。輸出指標須有效。畫面座標限幅不是幾何裁切。
此範例使用 128×96 設定,視埠從畫面 (0,0) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
Wire3D_SetCamera(8,0,0,0,0,0);
result[1]=Wire3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=Wire3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
Wire3D_SetCamera(0,0,0,0,0,0);
Wire3D_BeginFrame();
Wire3D_DrawLine2D(8,8,56,8);
Wire3D_DrawLine2D(56,8,56,40);
Wire3D_DrawLine2D(56,40,8,40);
Wire3D_DrawLine2D(8,40,8,8);
Wire3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
Wire3D_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
Wire3D_PutBgTile(18,1,157);
Wire3D_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_raster.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d.h:50
WIRE3D_DMG_HEIGHT = 96. Project a world point with the current camera. Return zero for rejected depth, leaving outputs unchanged; success writes clamped 128x96 coordinates. Output pointers must be valid. Screen clamping is not geometric clipping.
kitaqgb/lib/wire3d_dmg.c:549
w3ddmg_u8 Wire3DDMG_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy)
{
return w3ddmg_project_world(x, y, z, sx, sy);
}Wire3D_PutBgTile
將背景地圖一格的圖塊編號寫入排入佇列。
語法
void Wire3D_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile);參數
x32×32 背景地圖中的 X 圖塊座標。
y32×32 背景地圖中的 Y 圖塊座標。
tile背景格的八位元圖塊編號。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96. 將 0x9800 的 32×32 地圖圖塊寫入排入佇列,交由 EndFrame 處理。無效地圖座標及超過 48 筆待處理寫入的要求會直接忽略,不另行回報。此佇列與一般 vram 函式庫佇列分開。
此範例使用 128×96 設定,視埠從畫面 (0,0) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
Wire3D_SetCamera(8,0,0,0,0,0);
result[1]=Wire3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=Wire3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
Wire3D_SetCamera(0,0,0,0,0,0);
Wire3D_BeginFrame();
Wire3D_DrawLine2D(8,8,56,8);
Wire3D_DrawLine2D(56,8,56,40);
Wire3D_DrawLine2D(56,40,8,40);
Wire3D_DrawLine2D(8,40,8,8);
Wire3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
Wire3D_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
Wire3D_PutBgTile(18,1,157);
Wire3D_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_raster.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d.h:51
WIRE3D_DMG_HEIGHT = 96. Queue a tile write to the 32x32 map at 0x9800 for EndFrame. Invalid map coordinates and submissions beyond 48 pending writes are silently ignored. This queue is separate from the general vram library queue.
kitaqgb/lib/wire3d_dmg.c:582
void Wire3DDMG_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile)
{
if (x >= 32) return;
if (y >= 32) return;
if (w3ddmg_bgq_count >= WIRE3D_DMG_BG_QUEUE_LIMIT) return;
w3ddmg_bgq_x[(__safe_index w3ddmg_u8)w3ddmg_bgq_count] = x;
w3ddmg_bgq_y[(__safe_index w3ddmg_u8)w3ddmg_bgq_count] = y;
w3ddmg_bgq_tile[(__safe_index w3ddmg_u8)w3ddmg_bgq_count] = tile;
w3ddmg_bgq_count = (w3ddmg_u8)(w3ddmg_bgq_count + 1);
}Wire3D_SelectEdgeMask
依物件偏航選擇預先計算的邊可見遮罩。
語法
w3ddmg_u16 Wire3D_SelectEdgeMask(const Wire3DDMG_Model* model, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz);參數
model包含頂點、邊、面陣列及數量的模型;呼叫期間須保持各表可讀。
rx繞 X 軸旋轉;十六步為一整圈。
ry繞 Y 軸旋轉;十六步為一整圈。
rz繞 Z 軸旋轉;十六步為一整圈。
回傳值
16 位元邊可見遮罩;未提供表時為 0xFFFF。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96. 依物件偏航的低四位元選擇預先計算的遮罩;忽略俯仰、滾轉與相機朝向。使用 16、8、4 或 2 個區段;其他正計數選擇項目零(計數 >=16 時使用前 16 個)。缺少資料時傳回 0xFFFF。須讓遮罩表在目前資料指標映射下保持可讀。
此範例使用 128×96 設定,視埠從畫面 (0,0) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3D_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom Wire3D_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
Wire3D_Model cube;
Wire3D_Object objects[2];
u16 masks[2];
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;
cube.edge_masks=0; cube.edge_mask_count=0;
Wire3D_BeginFrame();
// Upper pair: direct model calls at unity and half scale.
Wire3D_DrawModel(&cube,-32,32,96,0,0,0);
Wire3D_DrawModelScaled(&cube,32,32,96,0,0,0,128);
// Lower pair: the caller owns both object records and the model tables.
for(i=0;i<2;i++) {
objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
objects[i].y=-32;objects[i].z=96;
objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
}
Wire3D_DrawScene(objects,2);
// Numeric checks cover the operation supplied by this viewport profile.
masks[0]=3;masks[1]=12;cube.edge_masks=masks; cube.edge_mask_count=2;
result[1]=Wire3D_SelectEdgeMask(&cube,0,0,0);
result[2]=Wire3D_SelectEdgeMask(&cube,0,8,0);
Wire3D_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
原倍率與半倍率模型顯示在相同倍率的物件陣列場景上方,用以示範投影與縮放。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_models.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d.h:52
WIRE3D_DMG_HEIGHT = 96. Select a precomputed mask from the low four bits of object yaw; pitch, roll and camera orientation are ignored. Use 16, 8, 4 or 2 bins; other positive counts select entry zero (counts >=16 use the first 16). Missing data returns 0xFFFF. Keep the mask table readable through the current data-pointer mapping.
kitaqgb/lib/wire3d_dmg.c:1109
w3ddmg_u16 Wire3DDMG_SelectEdgeMask(const Wire3DDMG_Model* model, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz)
{
w3ddmg_u8 count;
w3ddmg_u8 bin;
if (model == 0) return 0xFFFF;
if (model->edge_masks == 0) return 0xFFFF;
count = model->edge_mask_count;
if (count == 0) return 0xFFFF;
(void)rx;
(void)rz;
bin = (w3ddmg_u8)(((w3ddmg_u8)ry) & 15);
if (count >= 16) return model->edge_masks[(__safe_index w3ddmg_u8)bin];
if (count == 8) bin = (w3ddmg_u8)(bin >> 1);
else if (count == 4) bin = (w3ddmg_u8)(bin >> 2);
else if (count == 2) bin = (w3ddmg_u8)(bin >> 3);
else bin = 0;
if (bin >= count) bin = (w3ddmg_u8)(count - 1);
return model->edge_masks[(__safe_index w3ddmg_u8)bin];
}Wire3D_SetCamera
儲存後續投影使用的相機位置與朝向。
語法
void Wire3D_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 pitch, w3ddmg_i8 yaw, w3ddmg_i8 roll);參數
x相機的世界座標 X 分量。
y相機的世界座標 Y 分量。
z相機的世界座標 Z 分量。
pitch繞 X 軸旋轉;十六步為一整圈。
yaw繞 Y 軸旋轉;十六步為一整圈。
roll繞 Z 軸旋轉;十六步為一整圈。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96. 儲存後續繪製使用的相機位置與角度;每圈 16 個角度步階。不重新投影既有繪圖,也不驗證輸入範圍。
此範例使用 128×96 設定,視埠從畫面 (0,0) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
Wire3D_SetCamera(8,0,0,0,0,0);
result[1]=Wire3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=Wire3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
Wire3D_SetCamera(0,0,0,0,0,0);
Wire3D_BeginFrame();
Wire3D_DrawLine2D(8,8,56,8);
Wire3D_DrawLine2D(56,8,56,40);
Wire3D_DrawLine2D(56,40,8,40);
Wire3D_DrawLine2D(8,40,8,8);
Wire3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
Wire3D_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
Wire3D_PutBgTile(18,1,157);
Wire3D_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_raster.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d.h:53
WIRE3D_DMG_HEIGHT = 96. Store camera position and angles for later draws; a full turn is 16 angle steps. No existing drawing is reprojected and no input range validation occurs.
kitaqgb/lib/wire3d_dmg.c:2659
void Wire3DDMG_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 pitch, w3ddmg_i8 yaw, w3ddmg_i8 roll)
{
w3ddmg_cam_x = x;
w3ddmg_cam_y = y;
w3ddmg_cam_z = z;
w3ddmg_cam_pitch = pitch;
w3ddmg_cam_yaw = yaw;
w3ddmg_cam_roll = roll;
}Wire3D_SetPalette
寫入單色背景調色盤暫存器 BGP 的四階明暗對應。
語法
void Wire3D_SetPalette(w3ddmg_u8 bgp);參數
bgp包含四個兩位元明暗指定的 BGP 暫存器值。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96. 立即寫入原始 DMG BGP 調色盤編碼,不進行影格同步。
此範例使用 128×96 設定,視埠從畫面 (0,0) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3D_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
Wire3D_SetCamera(8,0,0,0,0,0);
result[1]=Wire3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=Wire3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
Wire3D_SetCamera(0,0,0,0,0,0);
Wire3D_BeginFrame();
Wire3D_DrawLine2D(8,8,56,8);
Wire3D_DrawLine2D(56,8,56,40);
Wire3D_DrawLine2D(56,40,8,40);
Wire3D_DrawLine2D(8,40,8,8);
Wire3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
Wire3D_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
Wire3D_PutBgTile(18,1,157);
Wire3D_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。


建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_raster.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d.h:54
WIRE3D_DMG_HEIGHT = 96. Write the raw DMG BGP palette encoding immediately; no frame synchronization occurs.
kitaqgb/lib/wire3d_dmg.c:597
void Wire3DDMG_SetPalette(w3ddmg_u8 bgp)
{
w3ddmg_reg_bgp = bgp;
}wire3d_cgb.h — CGB 彩色線框
使用高速繪圖路徑
一般 128×96 繪圖器會逐步更新繪圖位址。未遮蔽線條每條線只選擇一次色彩平面,並將像素數與誤差保存在 CPU 暫存器中。需要遮蔽的線條同樣每條線只選擇一次色彩平面,並逐步更新繪圖與遮罩位址。每個像素都會檢查遮罩位元,只在未被遮住時寫入。160×144 繪圖器與 FastMap 各有專用路徑。0、90、180、270 度旋轉先限制輸入範圍,再以座標交換及符號變更處理。整體遊戲效能也取決於頂點數、邊長、遮蔽與 VRAM 傳輸。請分別測量各操作與完成一張顯示影像所需的時間。
CGB 彩色線框。128×96 像素繪圖器、160×144 圖塊配置器與外框圖塊 FastMap 各有不同的初始化及傳輸順序。模型頂點、邊與三角形面由呼叫端持有。此模組不模擬物理。
Vec3 儲存 x/y/z,Edge 儲存頂點索引 a/b,Face 儲存三角形索引 a/b/c。Model 的 vertices、edges、faces 指向這些陣列,各計數表示其長度。edge_faces 包含相鄰面索引 f0/f1,缺少的面以 FACE_NONE 表示。flags 中的 MODEL_HIDDEN_LINES 要求依面選擇邊。投影後的有號面積決定面朝向,因此頂點順序很重要。
Object 儲存模型參照、位置 x/y/z、角度 rx/ry/rz、scale_q8 與 visible。物件可共用模型,但繪製不會複製表或自動切換其 ROM 記憶體庫。整個繪製期間須保持參照資料可讀。CGB 的 Object 另有色彩索引。
FastCube 的 x/y 是相對畫面中心的偏移;z 選擇大小或繪製順序。FastCubes 忽略角度,FastCubeFrame 則用 rx/ry/rz 選擇四種圖樣。這些簡化顯示與透過相機投影的 DrawModel 用途不同。
Wire3DCGB_BeginFrame
在所選繪圖模式中開始新的空白影格。
語法
void Wire3DCGB_BeginFrame();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
一般模式下選擇整個暫存區傳輸、清空全部暫存像素與點陣遮罩、重設遮罩邊界,並停用遮蔽。全畫面模式則改為重設該模式的配置器與跨度。待處理的 BG 寫入仍保留在佇列中。須使用完整執行階段建置。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
CGB稀疏顯示啟動時,首次使用各目標記憶體區(前兩幀)會更新整個視窗,清除初始化圖塊。量測包含啟動成本。一般DrawLine2D不登記稀疏範圍,請使用DrawLineClipped2D或明確呼叫MarkDirtyRect2D。
使用範例
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DCGB_EnableDoubleSpeed();
Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
result[2]=(u8)(sample_key1&128);
// Palette writes are performed with the LCD off, after entering VBlank.
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0;
Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
sample_lcdc=0x81;
Wire3DCGB_SetScreenOffset(0,0);
Wire3DCGB_SetCamera(0,0,0,0,0,0);
Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
Wire3DCGB_DrawLine2D(8,8,56,8);
Wire3DCGB_DrawLine2D(56,8,56,40);
Wire3DCGB_DrawLine2D(56,40,8,40);
Wire3DCGB_DrawLine2D(8,40,8,8);
Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
Wire3DCGB_SetLineColor(3);
Wire3DCGB_DrawPoint2D(64,48);
Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
Wire3DCGB_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。紅色邊框內有藍色對角線,另有綠點與綠色水平線、藍色 L,以及右上角的綠色數字 0。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:122
kitaqgb/lib/wire3d_cgb.c:8154
void Wire3DCGB_BeginFrame()
{
if (w3dcgb_full_mode != 0)
{
w3dcgb_full_begin_asm();
return;
}
w3dcgb_full_frame_transfer = 1;
w3dcgb_clear_stage_asm();
w3dcgb_clear_occlusion_mask_asm();
w3dcgb_occ_min_x = (w3dcgb_u8)(WIRE3DCGB_SCREEN_W - 1);
w3dcgb_occ_min_y = (w3dcgb_u8)(WIRE3DCGB_SCREEN_H - 1);
w3dcgb_occ_max_x = 0;
w3dcgb_occ_max_y = 0;
w3dcgb_occlusion_active = 0;
}Wire3DCGB_BeginFrameFast
開始已清空的影格,並將先前稀疏範圍失效化,使其涵蓋整個視埠。
語法
void Wire3DCGB_BeginFrameFast();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
執行與 BeginFrame 相同的一般/全畫面影格重設,但先將兩個先前的稀疏歷史範圍都標為完整的 192 圖塊視埠,避免後續稀疏上傳誤信過期的記憶體庫內容。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
CGB稀疏顯示啟動時,首次使用各目標記憶體區(前兩幀)會更新整個視窗,清除初始化圖塊。量測包含啟動成本。一般DrawLine2D不登記稀疏範圍,請使用DrawLineClipped2D或明確呼叫MarkDirtyRect2D。
使用範例
#pragma bank 0
// Reuse both VRAM banks and remove old geometry while presenting sparse frames.
#include "wire_cgb_example.h"
void main() {
wire_results_clear(); Wire3DCGB_Init();
Wire3DCGB_ClearFrameTiles();
Wire3DCGB_EnableAtomicMaps(); wire_colors();
// First frame: red on the left. Fast begin invalidates both bank histories.
Wire3DCGB_BeginFrameFast(); wire_frame(8,8,32,32,1);
Wire3DCGB_EndFrameFast();
// Second frame: blue in the middle, with the old red frame removed.
Wire3DCGB_BeginFrameSparse(); wire_frame(40,40,64,64,2);
Wire3DCGB_EndFrameSparse();
// Third frame: explicitly clearing a stage discards its first green point.
Wire3DCGB_BeginFrameSparse();
Wire3DCGB_SetLineColor(3); Wire3DCGB_DrawPoint2D(4,4);
Wire3DCGB_ClearSparseStageFast();
// The final image contains only this green frame on the right.
wire_frame(80,8,112,32,3);
Wire3DCGB_MarkDirtyRect2D(80,8,112,32);
Wire3DCGB_InvalidateFrameHistory();
Wire3DCGB_EndFrameSparseNow();
result[0]=Wire3DCGB_GetLineColor();
result[7]=0xA55A;
while(1) {}
}預期結果
先前繪製的紅框與藍框消失,只留下 (80,8)..(112,32) 的最後一個綠框,示範稀疏上傳與歷史管理。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_sparse.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_sparse.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:123
kitaqgb/lib/wire3d_cgb.c:8175
void Wire3DCGB_BeginFrameFast()
{
w3dcgb_older_dirty_min_tile = 0;
w3dcgb_older_dirty_max_tile = (w3dcgb_u8)(WIRE3DCGB_TILE_COUNT - 1);
w3dcgb_prev_dirty_min_tile = 0;
w3dcgb_prev_dirty_max_tile = (w3dcgb_u8)(WIRE3DCGB_TILE_COUNT - 1);
if (w3dcgb_full_mode != 0)
{
w3dcgb_full_begin_asm();
return;
}
w3dcgb_full_frame_transfer = 1;
w3dcgb_clear_stage_asm();
w3dcgb_clear_occlusion_mask_asm();
w3dcgb_occ_min_x = (w3dcgb_u8)(WIRE3DCGB_SCREEN_W - 1);
w3dcgb_occ_min_y = (w3dcgb_u8)(WIRE3DCGB_SCREEN_H - 1);
w3dcgb_occ_max_x = 0;
w3dcgb_occ_max_y = 0;
w3dcgb_occlusion_active = 0;
}Wire3DCGB_BeginFrameSparse
開始用於稀疏範圍傳輸的影格。
語法
void Wire3DCGB_BeginFrameSparse();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
選擇稀疏傳輸並清空整個 128×96 暫存區,避免 dirty 範圍擴大時殘留舊像素。重設遮罩邊界並停用遮蔽;PAINTER_ONLY 建置略過未使用之點陣遮罩的清除。全畫面模式交由自身的配置器重設處理。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
CGB稀疏顯示啟動時,首次使用各目標記憶體區(前兩幀)會更新整個視窗,清除初始化圖塊。量測包含啟動成本。一般DrawLine2D不登記稀疏範圍,請使用DrawLineClipped2D或明確呼叫MarkDirtyRect2D。
使用範例
#pragma bank 0
// Reuse both VRAM banks and remove old geometry while presenting sparse frames.
#include "wire_cgb_example.h"
void main() {
wire_results_clear(); Wire3DCGB_Init();
Wire3DCGB_ClearFrameTiles();
Wire3DCGB_EnableAtomicMaps(); wire_colors();
// First frame: red on the left. Fast begin invalidates both bank histories.
Wire3DCGB_BeginFrameFast(); wire_frame(8,8,32,32,1);
Wire3DCGB_EndFrameFast();
// Second frame: blue in the middle, with the old red frame removed.
Wire3DCGB_BeginFrameSparse(); wire_frame(40,40,64,64,2);
Wire3DCGB_EndFrameSparse();
// Third frame: explicitly clearing a stage discards its first green point.
Wire3DCGB_BeginFrameSparse();
Wire3DCGB_SetLineColor(3); Wire3DCGB_DrawPoint2D(4,4);
Wire3DCGB_ClearSparseStageFast();
// The final image contains only this green frame on the right.
wire_frame(80,8,112,32,3);
Wire3DCGB_MarkDirtyRect2D(80,8,112,32);
Wire3DCGB_InvalidateFrameHistory();
Wire3DCGB_EndFrameSparseNow();
result[0]=Wire3DCGB_GetLineColor();
result[7]=0xA55A;
while(1) {}
}預期結果
先前繪製的紅框與藍框消失,只留下 (80,8)..(112,32) 的最後一個綠框,示範稀疏上傳與歷史管理。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_sparse.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_sparse.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:124
kitaqgb/lib/wire3d_cgb.c:8200
void Wire3DCGB_BeginFrameSparse()
{
if (w3dcgb_full_mode != 0)
{
w3dcgb_full_begin_asm();
return;
}
w3dcgb_full_frame_transfer = 0;
w3dcgb_dirty_count = 0;
/* One ASM pass is faster than repeated range-growth clears and guarantees
that newly exposed dirty tiles can never copy stale stage pixels. */
w3dcgb_clear_stage_asm();
#ifndef WIRE3DCGB_PAINTER_ONLY
/* A Z-sorted painter erases silhouettes directly in the stage and never
reads the separate front-to-back coverage mask. */
w3dcgb_clear_occlusion_mask_asm();
#endif
w3dcgb_occ_min_x = (w3dcgb_u8)(WIRE3DCGB_SCREEN_W - 1);
w3dcgb_occ_min_y = (w3dcgb_u8)(WIRE3DCGB_SCREEN_H - 1);
w3dcgb_occ_max_x = 0;
w3dcgb_occ_max_y = 0;
w3dcgb_occlusion_active = 0;
}Wire3DCGB_ClearFrameTiles
清空目前顯示的 128×96 畫面圖塊與暫存區。
語法
void Wire3DCGB_ClearFrameTiles();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
針對 128×96 繪圖器,等待 VBlank、關閉 LCD、清空暫存區與兩庫的畫面圖塊範圍、重設地圖屬性,再啟用 LCDC 0x81。清除 dirty 旗標與計數,但保留稀疏傳輸的 min/max 歷史。不重設 full_mode,也不是全畫面的重新初始化函式。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
CGB稀疏顯示啟動時,首次使用各目標記憶體區(前兩幀)會更新整個視窗,清除初始化圖塊。量測包含啟動成本。一般DrawLine2D不登記稀疏範圍,請使用DrawLineClipped2D或明確呼叫MarkDirtyRect2D。
使用範例
#pragma bank 0
// Reuse both VRAM banks and remove old geometry while presenting sparse frames.
#include "wire_cgb_example.h"
void main() {
wire_results_clear(); Wire3DCGB_Init();
Wire3DCGB_ClearFrameTiles();
Wire3DCGB_EnableAtomicMaps(); wire_colors();
// First frame: red on the left. Fast begin invalidates both bank histories.
Wire3DCGB_BeginFrameFast(); wire_frame(8,8,32,32,1);
Wire3DCGB_EndFrameFast();
// Second frame: blue in the middle, with the old red frame removed.
Wire3DCGB_BeginFrameSparse(); wire_frame(40,40,64,64,2);
Wire3DCGB_EndFrameSparse();
// Third frame: explicitly clearing a stage discards its first green point.
Wire3DCGB_BeginFrameSparse();
Wire3DCGB_SetLineColor(3); Wire3DCGB_DrawPoint2D(4,4);
Wire3DCGB_ClearSparseStageFast();
// The final image contains only this green frame on the right.
wire_frame(80,8,112,32,3);
Wire3DCGB_MarkDirtyRect2D(80,8,112,32);
Wire3DCGB_InvalidateFrameHistory();
Wire3DCGB_EndFrameSparseNow();
result[0]=Wire3DCGB_GetLineColor();
result[7]=0xA55A;
while(1) {}
}預期結果
先前繪製的紅框與藍框消失,只留下 (80,8)..(112,32) 的最後一個綠框,示範稀疏上傳與歷史管理。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_sparse.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_sparse.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:121
kitaqgb/lib/wire3d_cgb.c:8240
void Wire3DCGB_ClearFrameTiles()
{
w3dcgb_u8 i;
w3dcgb_wait_vblank_start();
w3dcgb_reg_lcdc = 0;
w3dcgb_clear_stage_asm();
w3dcgb_clear_frame_tiles_vram_asm();
w3dcgb_fill_attr_map_asm();
w3dcgb_reg_lcdc = 0x81;
i = 0;
while (i < W3DCGB_DIRTY_TILE_LIMIT)
{
w3dcgb_dirty_flags[(__safe_index w3dcgb_u8)i] = 0;
w3dcgb_prev_dirty_flags[(__safe_index w3dcgb_u8)i] = 0;
i = (w3dcgb_u8)(i + 1);
}
w3dcgb_dirty_count = 0;
w3dcgb_prev_dirty_count = 0;
}Wire3DCGB_ClearOcclusionMask
清除遮蔽點陣或全畫面跨度歷史。
語法
void Wire3DCGB_ClearOcclusionMask();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
full_mode 設定時清除全畫面跨度歷史;否則清除 128×96 點陣遮罩及其邊界。不擦除顯示中或暫存的像素,也不改變遮蔽檢查是否啟用。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Red/blue scanlines stop inside masks; green outlines identify the triangle.
#include "wire_cgb_example.h"
__prg_rom u8 silhouette[5]={0x73,0x74,0xFF,0x75,0x73};
void main() {
u8 y;
wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
// Clearing this first test mask must leave the upper-left scanline intact.
Wire3DCGB_MarkTriangle2D(8,8,16,8,8,16);
Wire3DCGB_ClearOcclusionMask();
Wire3DCGB_MarkTriangle2D(32,16,64,16,32,48);
Wire3DCGB_MarkPackedSilhouette2D(silhouette,5,-2,104,32);
Wire3DCGB_SetOcclusionActive(1);
for(y=8;y<=56;y=y+4) Wire3DCGB_DrawLine2DColor(8,y,88,y,1);
for(y=28;y<=36;y++) Wire3DCGB_DrawLine2DColor(92,y,120,y,2);
Wire3DCGB_SetOcclusionActive(0);
Wire3DCGB_DrawLine2DColor(32,16,64,16,3);
Wire3DCGB_DrawLine2DColor(64,16,32,48,3);
Wire3DCGB_DrawLine2DColor(32,48,32,16,3);
Wire3DCGB_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
三角形遮住紅色掃描線的中段,封裝的剪影遮住藍線;綠色外框標示遮蔽區域的位置。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_mask.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_mask.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:148
kitaqgb/lib/wire3d_cgb.c:1962
void Wire3DCGB_ClearOcclusionMask()
{
if (w3dcgb_full_mode != 0) w3dcgb_full_clear_spans_asm();
else w3dcgb_clear_occlusion_mask();
}Wire3DCGB_ClearSparseStageFast
清空整個暫存區,並將完整 128×96 視埠標為待上傳。
語法
void Wire3DCGB_ClearSparseStageFast();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
清空記憶體庫 2 的整個暫存區,並將完整 128×96 視埠標為 dirty。雖然名稱如此,這不是局部清除,也不保留暫存像素。不清除遮蔽狀態,也不選擇傳輸模式。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Reuse both VRAM banks and remove old geometry while presenting sparse frames.
#include "wire_cgb_example.h"
void main() {
wire_results_clear(); Wire3DCGB_Init();
Wire3DCGB_ClearFrameTiles();
Wire3DCGB_EnableAtomicMaps(); wire_colors();
// First frame: red on the left. Fast begin invalidates both bank histories.
Wire3DCGB_BeginFrameFast(); wire_frame(8,8,32,32,1);
Wire3DCGB_EndFrameFast();
// Second frame: blue in the middle, with the old red frame removed.
Wire3DCGB_BeginFrameSparse(); wire_frame(40,40,64,64,2);
Wire3DCGB_EndFrameSparse();
// Third frame: explicitly clearing a stage discards its first green point.
Wire3DCGB_BeginFrameSparse();
Wire3DCGB_SetLineColor(3); Wire3DCGB_DrawPoint2D(4,4);
Wire3DCGB_ClearSparseStageFast();
// The final image contains only this green frame on the right.
wire_frame(80,8,112,32,3);
Wire3DCGB_MarkDirtyRect2D(80,8,112,32);
Wire3DCGB_InvalidateFrameHistory();
Wire3DCGB_EndFrameSparseNow();
result[0]=Wire3DCGB_GetLineColor();
result[7]=0xA55A;
while(1) {}
}預期結果
先前繪製的紅框與藍框消失,只留下 (80,8)..(112,32) 的最後一個綠框,示範稀疏上傳與歷史管理。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_sparse.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_sparse.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:125
kitaqgb/lib/wire3d_cgb.c:8227
void Wire3DCGB_ClearSparseStageFast()
{
w3dcgb_clear_stage_asm();
w3dcgb_mark_dirty_rect(0, 0,
(w3dcgb_u8)(WIRE3DCGB_SCREEN_W - 1),
(w3dcgb_u8)(WIRE3DCGB_SCREEN_H - 1));
}Wire3DCGB_DrawEdgeList2D
依預先投影的有號位元組頂點偏移繪製最多 64 條邊。
語法
void Wire3DCGB_DrawEdgeList2D(const Wire3DCGB_Edge* edges, w3dcgb_u8 edge_count, const w3dcgb_i8* vertex_x, const w3dcgb_i8* vertex_y, w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_u8 color);參數
edges每條邊的頂點索引,採用所宣告的結構或位元組配對格式。
edge_count邊的數量。
vertex_x預先投影的頂點 X 偏移陣列。
vertex_y預先投影的頂點 Y 偏移陣列。
x中心 X 座標,以視埠像素為單位。
y中心 Y 座標,以視埠像素為單位。
color繪圖色彩索引;範例調色盤使用 1=紅、2=藍、3=綠。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
依相對於 (cx,cy) 的有號位元組偏移,繪製最多 64 條索引邊。忽略 null 陣列;索引須指向可讀頂點。平移後端點在會回繞的位元組轉換前須位於視埠內。依模式分派並保留先前色彩;不檢查頂點數。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Preprojected edge arrays, a clipped square, a tiny marker and a projectile.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Edge edges[4]={{0,1},{1,2},{2,3},{3,0}};
__prg_rom s8 vx8[4]={-8,8,8,-8};
__prg_rom s8 vy8[4]={-8,-8,8,8};
__prg_rom s16 vx16[4]={-12,12,12,-12};
__prg_rom s16 vy16[4]={-8,-8,8,8};
__prg_rom u8 mask[1]={5};
Wire3DCGB_Model shape;
void main() {
wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
shape.vertices=0;shape.edges=edges;shape.faces=0;shape.edge_faces=0;
shape.vertex_count=4;shape.edge_count=4;shape.face_count=0;shape.flags=0;
Wire3DCGB_SetLineColor(2);
Wire3DCGB_DrawMaskedModel2D(&shape,vx8,vy8,mask,24,24,1);
Wire3DCGB_DrawEdgeList2D(edges,4,vx8,vy8,64,24,2);
Wire3DCGB_DrawEdgeListClipped2D(edges,4,vx16,vy16,4,4,64,3);
Wire3DCGB_DrawTinyModel2D(104,24,16,3);
result[0]=Wire3DCGB_ProjectAxis48(48,96);
result[1]=Wire3DCGB_ProjectAxis48(-48,96);
Wire3DCGB_DrawFastProjectile(96,64,64,0,1);
result[2]=Wire3DCGB_GetLineColor();
Wire3DCGB_EndFrame();result[7]=0xA55A;
while(1) {}
}預期結果
以兩條紅色水平邊、藍色正方形、經裁切的綠框、綠色六像素標記與紅色投射物,比較各種列表格式。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_lists.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_lists.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:183
kitaqgb/lib/wire3d_cgb.c:8524
void Wire3DCGB_DrawEdgeList2D(const Wire3DCGB_Edge* edges, w3dcgb_u8 edge_count,
const w3dcgb_i8* vertex_x, const w3dcgb_i8* vertex_y,
w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_u8 color)
{
w3dcgb_u8 i;
w3dcgb_u8 a;
w3dcgb_u8 b;
w3dcgb_u8 old_color;
if (edges == 0) return;
if (vertex_x == 0) return;
if (vertex_y == 0) return;
if (edge_count > WIRE3DCGB_MODEL_EDGE_LIMIT) edge_count = WIRE3DCGB_MODEL_EDGE_LIMIT;
old_color = w3dcgb_line_color;
w3dcgb_line_color = (w3dcgb_u8)(color & 3);
if (w3dcgb_full_mode == 0)
{
w3dcgb_edge_list_ptr = edges;
w3dcgb_edge_x_ptr = vertex_x;
w3dcgb_edge_y_ptr = vertex_y;
w3dcgb_edge_remaining = edge_count;
w3dcgb_edge_center_x = x;
w3dcgb_edge_center_y = y;
w3dcgb_edge_list_asm();
w3dcgb_line_color = old_color;
return;
}
i = 0;
while (i < edge_count)
{
a = edges[(__safe_index w3dcgb_u8)i].a;
b = edges[(__safe_index w3dcgb_u8)i].b;
w3dcgb_line_x0 = (w3dcgb_u8)((w3dcgb_i16)x + (w3dcgb_i16)vertex_x[(__safe_index w3dcgb_u8)a]);
w3dcgb_line_y0 = (w3dcgb_u8)((w3dcgb_i16)y + (w3dcgb_i16)vertex_y[(__safe_index w3dcgb_u8)a]);
w3dcgb_line_x1 = (w3dcgb_u8)((w3dcgb_i16)x + (w3dcgb_i16)vertex_x[(__safe_index w3dcgb_u8)b]);
w3dcgb_line_y1 = (w3dcgb_u8)((w3dcgb_i16)y + (w3dcgb_i16)vertex_y[(__safe_index w3dcgb_u8)b]);
if (w3dcgb_full_mode != 0) w3dcgb_full_line_fast_asm();
else w3dcgb_line_stage_asm();
i = (w3dcgb_u8)(i + 1);
}
w3dcgb_line_color = old_color;
}Wire3DCGB_DrawEdgeListClipped2D
驗證有號投影頂點與邊,再裁切並繪製邊列表。
語法
void Wire3DCGB_DrawEdgeListClipped2D(const Wire3DCGB_Edge* edges, w3dcgb_u8 edge_count, const w3dcgb_i16* vx, const w3dcgb_i16* vy, w3dcgb_u8 vertex_count, w3dcgb_i16 cx, w3dcgb_i16 cy, w3dcgb_u8 color);參數
edges每條邊的頂點索引,採用所宣告的結構或位元組配對格式。
edge_count邊的數量。
vx裁切前的有號 16 位元 X 偏移陣列。
vy裁切前的有號 16 位元 Y 偏移陣列。
vertex_count頂點陣列的項目數。
cx中心 X 座標,以視埠像素為單位。
cy中心 Y 座標,以視埠像素為單位。
color繪圖色彩索引;範例調色盤使用 1=紅、2=藍、3=綠。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
繪製前驗證指標、1..24 個頂點、最多 64 條邊、每個索引,以及輸入座標與中心是否在 ±2047 內。完全可見的幾何圖形使用有號位元組暫存區與快速索引路徑;其餘邊使用有號線段裁切器。即使各輸入皆通過驗證,平移後端點超出 ±2047 仍可能被裁切器拒絕。此操作替換共用畫面暫存區,並透過所呼叫的線段 API 保留先前色彩。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Preprojected edge arrays, a clipped square, a tiny marker and a projectile.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Edge edges[4]={{0,1},{1,2},{2,3},{3,0}};
__prg_rom s8 vx8[4]={-8,8,8,-8};
__prg_rom s8 vy8[4]={-8,-8,8,8};
__prg_rom s16 vx16[4]={-12,12,12,-12};
__prg_rom s16 vy16[4]={-8,-8,8,8};
__prg_rom u8 mask[1]={5};
Wire3DCGB_Model shape;
void main() {
wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
shape.vertices=0;shape.edges=edges;shape.faces=0;shape.edge_faces=0;
shape.vertex_count=4;shape.edge_count=4;shape.face_count=0;shape.flags=0;
Wire3DCGB_SetLineColor(2);
Wire3DCGB_DrawMaskedModel2D(&shape,vx8,vy8,mask,24,24,1);
Wire3DCGB_DrawEdgeList2D(edges,4,vx8,vy8,64,24,2);
Wire3DCGB_DrawEdgeListClipped2D(edges,4,vx16,vy16,4,4,64,3);
Wire3DCGB_DrawTinyModel2D(104,24,16,3);
result[0]=Wire3DCGB_ProjectAxis48(48,96);
result[1]=Wire3DCGB_ProjectAxis48(-48,96);
Wire3DCGB_DrawFastProjectile(96,64,64,0,1);
result[2]=Wire3DCGB_GetLineColor();
Wire3DCGB_EndFrame();result[7]=0xA55A;
while(1) {}
}預期結果
以兩條紅色水平邊、藍色正方形、經裁切的綠框、綠色六像素標記與紅色投射物,比較各種列表格式。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_lists.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_lists.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:138
kitaqgb/lib/wire3d_cgb.c:9806
void Wire3DCGB_DrawEdgeListClipped2D(const Wire3DCGB_Edge* edges, w3dcgb_u8 edge_count,
const w3dcgb_i16* vx, const w3dcgb_i16* vy, w3dcgb_u8 vertex_count,
w3dcgb_i16 cx, w3dcgb_i16 cy, w3dcgb_u8 color)
{
w3dcgb_u8 i;
w3dcgb_u8 a;
w3dcgb_u8 b;
w3dcgb_u8 inside;
w3dcgb_i16 x;
w3dcgb_i16 y;
w3dcgb_i16 min_x;
w3dcgb_i16 min_y;
w3dcgb_i16 max_x;
w3dcgb_i16 max_y;
if ((edges == 0) || (vx == 0) || (vy == 0)) return;
if ((cx < -2047) || (cx > 2047) || (cy < -2047) || (cy > 2047)) return;
if ((vertex_count == 0) || (vertex_count > WIRE3DCGB_MODEL_VERTEX_LIMIT) ||
(edge_count > WIRE3DCGB_MODEL_EDGE_LIMIT)) return;
i = 0;
while (i < edge_count)
{
if ((edges[(__safe_index w3dcgb_u8)i].a >= vertex_count) ||
(edges[(__safe_index w3dcgb_u8)i].b >= vertex_count)) return;
i = (w3dcgb_u8)(i + 1);
}
min_x = 32767;
min_y = 32767;
max_x = -32767;
max_y = -32767;
inside = 1;
i = 0;
while (i < vertex_count)
{
if ((vx[(__safe_index w3dcgb_u8)i] < -2047) ||
(vx[(__safe_index w3dcgb_u8)i] > 2047) ||
(vy[(__safe_index w3dcgb_u8)i] < -2047) ||
(vy[(__safe_index w3dcgb_u8)i] > 2047)) return;
x = (w3dcgb_i16)(cx + vx[(__safe_index w3dcgb_u8)i]);
y = (w3dcgb_i16)(cy + vy[(__safe_index w3dcgb_u8)i]);
if (x < min_x) min_x = x;
if (x > max_x) max_x = x;
if (y < min_y) min_y = y;
if (y > max_y) max_y = y;
/* Reuse projected-vertex scratch; drawing is non-reentrant. */
w3dcgb_screen_x[(__safe_index w3dcgb_u8)i] = (w3dcgb_u8)(x - 64);
w3dcgb_screen_y[(__safe_index w3dcgb_u8)i] = (w3dcgb_u8)(y - 48);
i = (w3dcgb_u8)(i + 1);
}
if ((w3dcgb_clip_outcode(min_x, min_y) | w3dcgb_clip_outcode(max_x, max_y)) != 0) inside = 0;
if (inside != 0)
{
if (w3dcgb_full_mode == 0) w3dcgb_mark_dirty_rect((w3dcgb_u8)min_x,
(w3dcgb_u8)min_y, (w3dcgb_u8)max_x, (w3dcgb_u8)max_y);
Wire3DCGB_DrawEdgeList2D(edges, edge_count, (const w3dcgb_i8*)w3dcgb_screen_x,
(const w3dcgb_i8*)w3dcgb_screen_y, 64, 48, color);
return;
}
i = 0;
while (i < edge_count)
{
a = edges[(__safe_index w3dcgb_u8)i].a;
b = edges[(__safe_index w3dcgb_u8)i].b;
Wire3DCGB_DrawLineClipped2D((w3dcgb_i16)(cx + vx[(__safe_index w3dcgb_u8)a]),
(w3dcgb_i16)(cy + vy[(__safe_index w3dcgb_u8)a]),
(w3dcgb_i16)(cx + vx[(__safe_index w3dcgb_u8)b]),
(w3dcgb_i16)(cy + vy[(__safe_index w3dcgb_u8)b]), color);
i = (w3dcgb_u8)(i + 1);
}
}Wire3DCGB_DrawFastCubeFrame
取代前一個立方體圖樣影格,並上傳最多三個圖樣及狀態指示器。
語法
void Wire3DCGB_DrawFastCubeFrame(Wire3DCGB_FastCube* cubes, w3dcgb_u8 count, w3dcgb_u8 hidden_enabled, w3dcgb_u8 selected);參數
cubes用於快速立方體繪製的位置、角度與色彩陣列。
count提供的陣列項目數;處理上限請參閱各操作的說明。
hidden_enabled零包含隱藏邊;非零選擇簡化的隱邊移除。
selected所選物件在原始陣列中的索引;圖樣 API 將其用於狀態指示。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
準備地圖、擦除先前邊界與狀態格,依原始 Z 值將最多三個立方體圖樣由遠至近排序,再繪製並於 VBlank 上傳編號與屬性。不重排呼叫端陣列。非 null 且 count 為零會清除舊圖樣;null 陣列則完全不動作。selected & 3 僅選擇狀態格,不會突顯立方體。須已載入立方體圖樣,並具備完整執行階段與一致的 FastMap WRAM 映射;此函式不初始化這些條件。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
CGB稀疏顯示啟動時,首次使用各目標記憶體區(前兩幀)會更新整個視窗,清除初始化圖塊。量測包含啟動成本。一般DrawLine2D不登記稀疏範圍,請使用DrawLineClipped2D或明確呼叫MarkDirtyRect2D。
使用範例
#pragma bank 0
// A complete cube-stamp frame removes the preceding stamp's old map cells.
#include "wire_cgb_example.h"
Wire3DCGB_FastCube cube[1];
void main() {
u8 bank;
wire_results_clear(); Wire3DCGB_Init(); wire_colors();
cube[0].x=-24;cube[0].y=0;cube[0].z=96;
cube[0].rx=0;cube[0].ry=0;cube[0].rz=0;cube[0].color=1;
bank=sample_svbk;sample_svbk=2;
Wire3DCGB_DrawFastCubeFrame(cube,1,1,0);
cube[0].x=24;
Wire3DCGB_DrawFastCubeFrame(cube,1,1,0);
sample_svbk=bank;result[0]=cube[0].x;result[7]=0xA55A;
while(1) {}
}預期結果
舊立方體圖樣消失。紅色 32×32 立方體從 (72,32) 開始,上方顯示綠色狀態指示器。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_stamp.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_stamp.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:158
kitaqgb/lib/wire3d_cgb.c:10800
void Wire3DCGB_DrawFastCubeFrame(Wire3DCGB_FastCube* cubes, w3dcgb_u8 count, w3dcgb_u8 hidden_enabled, w3dcgb_u8 selected)
{
w3dcgb_u8 i;
w3dcgb_u8 scene_count;
w3dcgb_u8 a;
w3dcgb_u8 b;
w3dcgb_u8 c;
w3dcgb_u8 x;
if (cubes == 0) return;
scene_count = count;
if (scene_count > 3) scene_count = 3;
w3dcgb_fast_map_prepare();
i = 0;
while (i < w3dcgb_fast_prev_count)
{
w3dcgb_fast_map_clear_rect(
w3dcgb_fast_prev_x[(__safe_index w3dcgb_u8)i],
w3dcgb_fast_prev_y[(__safe_index w3dcgb_u8)i],
w3dcgb_fast_prev_w[(__safe_index w3dcgb_u8)i],
w3dcgb_fast_prev_h[(__safe_index w3dcgb_u8)i]);
i = (w3dcgb_u8)(i + 1);
}
w3dcgb_fast_map_clear_rect(0, 0, 4, 1);
w3dcgb_fast_map_clear_rect(14, 0, 2, 1);
if (scene_count == 0)
{
w3dcgb_fast_prev_count = 0;
w3dcgb_wait_vblank_start();
w3dcgb_fast_map_flush_gdma_asm();
return;
}
a = 0;
b = 1;
c = 2;
if (scene_count == 1)
{
w3dcgb_fast_map_draw_cube_one(&cubes[0], hidden_enabled, (w3dcgb_u8)(selected == 0), 0);
w3dcgb_fast_prev_count = 1;
}
else if (scene_count == 2)
{
if (cubes[0].z < cubes[1].z)
{
w3dcgb_fast_map_draw_cube_one(&cubes[1], hidden_enabled, (w3dcgb_u8)(selected == 1), 1);
w3dcgb_fast_map_draw_cube_one(&cubes[0], hidden_enabled, (w3dcgb_u8)(selected == 0), 0);
}
else
{
w3dcgb_fast_map_draw_cube_one(&cubes[0], hidden_enabled, (w3dcgb_u8)(selected == 0), 0);
w3dcgb_fast_map_draw_cube_one(&cubes[1], hidden_enabled, (w3dcgb_u8)(selected == 1), 1);
}
w3dcgb_fast_prev_count = 2;
}
else
{
if (cubes[a].z < cubes[b].z)
{
w3dcgb_u8 t;
t = a;
a = b;
b = t;
}
if (cubes[b].z < cubes[c].z)
{
w3dcgb_u8 t;
t = b;
b = c;
c = t;
}
if (cubes[a].z < cubes[b].z)
{
w3dcgb_u8 t;
t = a;
a = b;
b = t;
}
w3dcgb_fast_map_draw_cube_one(&cubes[a], hidden_enabled, (w3dcgb_u8)(selected == a), a);
w3dcgb_fast_map_draw_cube_one(&cubes[b], hidden_enabled, (w3dcgb_u8)(selected == b), b);
w3dcgb_fast_map_draw_cube_one(&cubes[c], hidden_enabled, (w3dcgb_u8)(selected == c), c);
w3dcgb_fast_prev_count = 3;
}
x = (w3dcgb_u8)(selected & 3);
w3dcgb_fast_map_or_cell((w3dcgb_i16)x, (w3dcgb_i16)0, WIRE3DCGB_COLOR_HIGH, 15);
if (hidden_enabled != 0) w3dcgb_fast_map_or_cell((w3dcgb_i16)15, (w3dcgb_i16)0, WIRE3DCGB_COLOR_HIGH, 15);
else w3dcgb_fast_map_or_cell((w3dcgb_i16)14, (w3dcgb_i16)0, WIRE3DCGB_COLOR_LOW, 15);
w3dcgb_wait_vblank_start();
w3dcgb_fast_map_flush_gdma_asm();
}Wire3DCGB_DrawFastCubes
以依深度決定大小的 2D 外框,繪製最多三個立方體。
語法
void Wire3DCGB_DrawFastCubes(Wire3DCGB_FastCube* cubes, w3dcgb_u8 count, w3dcgb_u8 hidden_enabled, w3dcgb_u8 selected);參數
cubes用於快速立方體繪製的位置、角度與色彩陣列。
count提供的陣列項目數;處理上限請參閱各操作的說明。
hidden_enabled零包含隱藏邊;非零選擇簡化的隱邊移除。
selected所選物件在原始陣列中的索引;圖樣 API 將其用於狀態指示。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
不重排呼叫端陣列,依原始 Z 值由遠至近排序,繪製最多三個 2D 近似立方體。忽略 null 或空輸入。selected 是原始陣列索引。不使用相機或旋轉,也不恢復色彩。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Fast cube approximations use screen offsets and depth size bands, not a camera.
#include "wire_cgb_example.h"
Wire3DCGB_FastCube cubes[2];
void main() {
u8 i;
wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
for(i=0;i<2;i++){cubes[i].rx=0;cubes[i].ry=0;cubes[i].rz=0;}
cubes[0].x=-32;cubes[0].y=-8;cubes[0].z=90;cubes[0].color=1;
cubes[1].x=32;cubes[1].y=8;cubes[1].z=160;cubes[1].color=2;
Wire3DCGB_SetCamera(100,0,0,4,4,4); // FastCubes intentionally ignores this.
Wire3DCGB_DrawFastCubes(cubes,2,1,0);
Wire3DCGB_DrawFastStatus(1,0);
result[0]=Wire3DCGB_GetLineColor();
result[1]=cubes[0].z;result[2]=cubes[1].z;
Wire3DCGB_EndFrame();result[7]=0xA55A;
while(1) {}
}預期結果
左側近處的紅色立方體比右側遠處的藍色立方體大。綠色十字標記選取的紅色立方體。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_cubes.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_cubes.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:156
kitaqgb/lib/wire3d_cgb.c:8765
void Wire3DCGB_DrawFastCubes(Wire3DCGB_FastCube* cubes, w3dcgb_u8 count, w3dcgb_u8 hidden_enabled, w3dcgb_u8 selected)
{
w3dcgb_u8 scene_count;
w3dcgb_u8 a;
w3dcgb_u8 b;
w3dcgb_u8 c;
w3dcgb_u8 x;
if (cubes == 0) return;
scene_count = count;
if (scene_count == 0) return;
if (scene_count > 3) scene_count = 3;
a = 0;
b = 1;
c = 2;
if (scene_count == 1)
{
w3dcgb_draw_fast_cube_one(&cubes[0], hidden_enabled, (w3dcgb_u8)(selected == 0));
return;
}
if (scene_count == 2)
{
if (cubes[0].z < cubes[1].z)
{
w3dcgb_draw_fast_cube_one(&cubes[1], hidden_enabled, (w3dcgb_u8)(selected == 1));
w3dcgb_draw_fast_cube_one(&cubes[0], hidden_enabled, (w3dcgb_u8)(selected == 0));
}
else
{
w3dcgb_draw_fast_cube_one(&cubes[0], hidden_enabled, (w3dcgb_u8)(selected == 0));
w3dcgb_draw_fast_cube_one(&cubes[1], hidden_enabled, (w3dcgb_u8)(selected == 1));
}
return;
}
if (cubes[a].z < cubes[b].z)
{
w3dcgb_u8 t;
t = a;
a = b;
b = t;
}
if (cubes[b].z < cubes[c].z)
{
w3dcgb_u8 t;
t = b;
b = c;
c = t;
}
if (cubes[a].z < cubes[b].z)
{
w3dcgb_u8 t;
t = a;
a = b;
b = t;
}
w3dcgb_draw_fast_cube_one(&cubes[a], hidden_enabled, (w3dcgb_u8)(selected == a));
w3dcgb_draw_fast_cube_one(&cubes[b], hidden_enabled, (w3dcgb_u8)(selected == b));
w3dcgb_draw_fast_cube_one(&cubes[c], hidden_enabled, (w3dcgb_u8)(selected == c));
}Wire3DCGB_DrawFastProjectile
在已投影的中心繪製六邊投射物,大小與方向由深度及相位決定。
語法
void Wire3DCGB_DrawFastProjectile(w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_i16 z, w3dcgb_u8 phase, w3dcgb_u8 color);參數
x中心 X 座標,以視埠像素為單位。
y中心 Y 座標,以視埠像素為單位。
z用於選擇大小或計算投影的深度。
phase旋轉相位,每八次計數前進一個方向。
color繪圖色彩索引;範例調色盤使用 1=紅、2=藍、3=綠。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
在已投影的中心,以四個深度尺寸區段與四種相位方向繪製六邊投射物。中心超出 X=10..117 或 Y=10..85 則拒絕,標記 dirty 邊界,並保留指定色彩為目前選擇。使用一般光柵器,不套用相機。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Preprojected edge arrays, a clipped square, a tiny marker and a projectile.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Edge edges[4]={{0,1},{1,2},{2,3},{3,0}};
__prg_rom s8 vx8[4]={-8,8,8,-8};
__prg_rom s8 vy8[4]={-8,-8,8,8};
__prg_rom s16 vx16[4]={-12,12,12,-12};
__prg_rom s16 vy16[4]={-8,-8,8,8};
__prg_rom u8 mask[1]={5};
Wire3DCGB_Model shape;
void main() {
wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
shape.vertices=0;shape.edges=edges;shape.faces=0;shape.edge_faces=0;
shape.vertex_count=4;shape.edge_count=4;shape.face_count=0;shape.flags=0;
Wire3DCGB_SetLineColor(2);
Wire3DCGB_DrawMaskedModel2D(&shape,vx8,vy8,mask,24,24,1);
Wire3DCGB_DrawEdgeList2D(edges,4,vx8,vy8,64,24,2);
Wire3DCGB_DrawEdgeListClipped2D(edges,4,vx16,vy16,4,4,64,3);
Wire3DCGB_DrawTinyModel2D(104,24,16,3);
result[0]=Wire3DCGB_ProjectAxis48(48,96);
result[1]=Wire3DCGB_ProjectAxis48(-48,96);
Wire3DCGB_DrawFastProjectile(96,64,64,0,1);
result[2]=Wire3DCGB_GetLineColor();
Wire3DCGB_EndFrame();result[7]=0xA55A;
while(1) {}
}預期結果
以兩條紅色水平邊、藍色正方形、經裁切的綠框、綠色六像素標記與紅色投射物,比較各種列表格式。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_lists.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_lists.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:159
kitaqgb/lib/wire3d_cgb.c:8833
void Wire3DCGB_DrawFastProjectile(w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_i16 z,
w3dcgb_u8 phase, w3dcgb_u8 color)
{
w3dcgb_u8 radius;
w3dcgb_u8 half;
w3dcgb_u8 depth;
w3dcgb_u8 ax;
w3dcgb_u8 ay;
w3dcgb_u8 bx;
w3dcgb_u8 by;
w3dcgb_u8 cx;
w3dcgb_u8 cy;
w3dcgb_u8 dx;
w3dcgb_u8 dy;
w3dcgb_u8 spin;
if ((x < 10) || (x > 117) || (y < 10) || (y > 85)) return;
radius = 3;
depth = 1;
if (z <= 160) { radius = 4; depth = 2; }
if (z <= 112) { radius = 5; depth = 3; }
if (z <= 64) { radius = 7; depth = 4; }
half = (w3dcgb_u8)(radius >> 1);
ax = x;
ay = (w3dcgb_u8)(y - radius);
bx = (w3dcgb_u8)(x - radius);
by = (w3dcgb_u8)(y + half);
cx = (w3dcgb_u8)(x + radius);
cy = by;
spin = (w3dcgb_u8)((phase >> 3) & 3);
dx = (w3dcgb_u8)(x + depth);
dy = (w3dcgb_u8)(y - depth);
if (spin == 1) dy = (w3dcgb_u8)(y + depth);
else if (spin == 2)
{
dx = (w3dcgb_u8)(x - depth);
dy = (w3dcgb_u8)(y + depth);
}
else if (spin == 3) dx = (w3dcgb_u8)(x - depth);
w3dcgb_mark_dirty_rect((w3dcgb_u8)(x - radius), (w3dcgb_u8)(y - radius),
(w3dcgb_u8)(x + radius), (w3dcgb_u8)(y + radius));
w3dcgb_line_color = color;
w3dcgb_draw_line_raw(ax, ay, bx, by);
w3dcgb_draw_line_raw(bx, by, cx, cy);
w3dcgb_draw_line_raw(cx, cy, ax, ay);
w3dcgb_draw_line_raw(ax, ay, dx, dy);
w3dcgb_draw_line_raw(bx, by, dx, dy);
w3dcgb_draw_line_raw(cx, cy, dx, dy);
}Wire3DCGB_DrawFastStatus
繪製表示物件選取與隱線模式的小型線段指示器。
語法
void Wire3DCGB_DrawFastStatus(w3dcgb_u8 hidden_enabled, w3dcgb_u8 selected);參數
hidden_enabled零包含隱藏邊;非零選擇簡化的隱邊移除。
selected所選物件在原始陣列中的索引;圖樣 API 將其用於狀態指示。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
以色彩 3 繪製小型選取/隱線模式指示器,並將其一般模式邊界標為 dirty。selected 預期為 0..2,不執行檢查。這些指示器使用線段而非字型圖塊,且不恢復先前色彩。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Fast cube approximations use screen offsets and depth size bands, not a camera.
#include "wire_cgb_example.h"
Wire3DCGB_FastCube cubes[2];
void main() {
u8 i;
wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
for(i=0;i<2;i++){cubes[i].rx=0;cubes[i].ry=0;cubes[i].rz=0;}
cubes[0].x=-32;cubes[0].y=-8;cubes[0].z=90;cubes[0].color=1;
cubes[1].x=32;cubes[1].y=8;cubes[1].z=160;cubes[1].color=2;
Wire3DCGB_SetCamera(100,0,0,4,4,4); // FastCubes intentionally ignores this.
Wire3DCGB_DrawFastCubes(cubes,2,1,0);
Wire3DCGB_DrawFastStatus(1,0);
result[0]=Wire3DCGB_GetLineColor();
result[1]=cubes[0].z;result[2]=cubes[1].z;
Wire3DCGB_EndFrame();result[7]=0xA55A;
while(1) {}
}預期結果
左側近處的紅色立方體比右側遠處的藍色立方體大。綠色十字標記選取的紅色立方體。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_cubes.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_cubes.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:157
kitaqgb/lib/wire3d_cgb.c:8888
void Wire3DCGB_DrawFastStatus(w3dcgb_u8 hidden_enabled, w3dcgb_u8 selected)
{
w3dcgb_u8 x;
w3dcgb_mark_dirty_rect(0, 0, 31, 7);
w3dcgb_mark_dirty_rect(116, 0, 127, 7);
x = (w3dcgb_u8)(4 + (selected * 8));
w3dcgb_line_color = WIRE3DCGB_COLOR_HIGH;
w3dcgb_draw_line_raw(x, 3, (w3dcgb_u8)(x + 5), 3);
w3dcgb_draw_line_raw(x, 6, (w3dcgb_u8)(x + 5), 6);
if (hidden_enabled != 0)
{
w3dcgb_draw_line_raw(118, 3, 124, 3);
w3dcgb_draw_line_raw(118, 6, 124, 6);
}
else
{
w3dcgb_draw_line_raw(118, 3, 124, 6);
w3dcgb_draw_line_raw(118, 6, 124, 3);
}
}Wire3DCGB_DrawLine2D
以目前繪圖器繪製包含兩端點的畫面空間線段。
語法
void Wire3DCGB_DrawLine2D(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by);參數
ax頂點 A 的 X 座標,以視埠像素為單位。
ay頂點 A 的 Y 座標,以視埠像素為單位。
bx頂點 B 的 X 座標,以視埠像素為單位。
by頂點 B 的 Y 座標,以視埠像素為單位。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
儲存位元組端點並呼叫一般或全畫面線段光柵器。座標須位於所選視埠內;有號或畫面外幾何圖形請用 DrawLineClipped2D。一般線段對色彩平面做 OR 且不標記稀疏邊界;稀疏上傳前須用裁切 API 或 InvalidateFrameHistory。全畫面線段則替換色彩並配置圖塊。兩條使用中的線段路徑皆將色彩零視為 3,而非擦除。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DCGB_EnableDoubleSpeed();
Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
result[2]=(u8)(sample_key1&128);
// Palette writes are performed with the LCD off, after entering VBlank.
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0;
Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
sample_lcdc=0x81;
Wire3DCGB_SetScreenOffset(0,0);
Wire3DCGB_SetCamera(0,0,0,0,0,0);
Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
Wire3DCGB_DrawLine2D(8,8,56,8);
Wire3DCGB_DrawLine2D(56,8,56,40);
Wire3DCGB_DrawLine2D(56,40,8,40);
Wire3DCGB_DrawLine2D(8,40,8,8);
Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
Wire3DCGB_SetLineColor(3);
Wire3DCGB_DrawPoint2D(64,48);
Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
Wire3DCGB_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。紅色邊框內有藍色對角線,另有綠點與綠色水平線、藍色 L,以及右上角的綠色數字 0。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:177
kitaqgb/lib/wire3d_cgb.c:8363
void Wire3DCGB_DrawLine2D(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by)
{
w3dcgb_line_x0 = ax;
w3dcgb_line_y0 = ay;
w3dcgb_line_x1 = bx;
w3dcgb_line_y1 = by;
if (w3dcgb_full_mode != 0) w3dcgb_full_line_fast_asm();
else w3dcgb_line_stage_asm();
}Wire3DCGB_DrawLine2DColor
以暫時色彩繪製畫面空間線段,並保留原先選取的色彩。
語法
void Wire3DCGB_DrawLine2DColor(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by, w3dcgb_u8 color);參數
ax頂點 A 的 X 座標,以視埠像素為單位。
ay頂點 A 的 Y 座標,以視埠像素為單位。
bx頂點 B 的 X 座標,以視埠像素為單位。
by頂點 B 的 Y 座標,以視埠像素為單位。
color繪圖色彩索引;範例調色盤使用 1=紅、2=藍、3=綠。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
在 DrawLine2D 期間設定 color & 3,完成後恢復先前色彩。須遵守該函式的座標、色彩合併及稀疏範圍約定;兩個使用中的繪圖器皆不以零擦除線段。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DCGB_EnableDoubleSpeed();
Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
result[2]=(u8)(sample_key1&128);
// Palette writes are performed with the LCD off, after entering VBlank.
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0;
Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
sample_lcdc=0x81;
Wire3DCGB_SetScreenOffset(0,0);
Wire3DCGB_SetCamera(0,0,0,0,0,0);
Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
Wire3DCGB_DrawLine2D(8,8,56,8);
Wire3DCGB_DrawLine2D(56,8,56,40);
Wire3DCGB_DrawLine2D(56,40,8,40);
Wire3DCGB_DrawLine2D(8,40,8,8);
Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
Wire3DCGB_SetLineColor(3);
Wire3DCGB_DrawPoint2D(64,48);
Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
Wire3DCGB_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。紅色邊框內有藍色對角線,另有綠點與綠色水平線、藍色 L,以及右上角的綠色數字 0。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:178
kitaqgb/lib/wire3d_cgb.c:8376
void Wire3DCGB_DrawLine2DColor(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by, w3dcgb_u8 color)
{
w3dcgb_u8 old_color;
old_color = w3dcgb_line_color;
Wire3DCGB_SetLineColor(color);
Wire3DCGB_DrawLine2D(ax, ay, bx, by);
w3dcgb_line_color = old_color;
}Wire3DCGB_DrawLine3D
將世界座標端點透過相機投影,並以目前色彩繪製線段。
語法
void Wire3DCGB_DrawLine3D(w3dcgb_i16 ax, w3dcgb_i16 ay, w3dcgb_i16 az, w3dcgb_i16 bx, w3dcgb_i16 by, w3dcgb_i16 bz);參數
ax起點的世界座標 X 分量。
ay起點的世界座標 Y 分量。
az起點的世界座標 Z 分量。
bx終點的世界座標 X 分量。
by終點的世界座標 Y 分量。
bz終點的世界座標 Z 分量。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
將兩端點透過相機投影至 128×96 視埠。任一端點未通過深度檢查即拒絕整條線,不裁切穿越近裁切平面的線段。DrawLine2D 依模式分派,但投影仍為 128×96。一般線段累積色彩平面且不標記稀疏邊界;須使用完整上傳,或在稀疏上傳前明確使影格歷史失效。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Four cubes compare unity/half scale and persistent/temporary line colors.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Vec3 vertices[8]={
{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},
{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}
};
__prg_rom Wire3DCGB_Edge edges[12]={
{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},
{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}
};
Wire3DCGB_Model cube;
u8 sx;
u8 sy;
void main() {
wire_results_clear();
cube.vertices=vertices; cube.edges=edges;
cube.faces=0; cube.edge_faces=0;
cube.vertex_count=8; cube.edge_count=12; cube.face_count=0; cube.flags=0;
Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
Wire3DCGB_DrawModel(&cube,-32,32,96,0,0,0);
Wire3DCGB_DrawModelScaled(&cube,32,32,96,0,0,0,128);
Wire3DCGB_DrawModelColor(&cube,-32,-32,96,0,0,0,2);
Wire3DCGB_DrawModelScaledColor(&cube,32,-32,96,0,0,0,128,3);
result[0]=Wire3DCGB_GetLineColor();
Wire3DCGB_DrawLine3D(0,56,96,0,-56,96);
Wire3DCGB_DrawLine3DColor(-80,0,96,80,0,96,3);
result[1]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
result[2]=sx; result[3]=sy;
// Camera setters affect future projection, leaving the staged cubes intact.
Wire3DCGB_SetCamera(0,0,0,0,4,0);
result[4]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
result[5]=Wire3DCGB_ProjectPointNoRotation(0,0,96,&sx,&sy);
result[6]=sx;
Wire3DCGB_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
比較以紅、藍、綠繪製的原倍率與縮放模型,以及交錯的 3D 線段。RAM 值也用來檢查相機投影及其不旋轉版本。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_models.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:172
kitaqgb/lib/wire3d_cgb.c:8992
void Wire3DCGB_DrawLine3D(w3dcgb_i16 ax, w3dcgb_i16 ay, w3dcgb_i16 az, w3dcgb_i16 bx, w3dcgb_i16 by, w3dcgb_i16 bz)
{
w3dcgb_u8 sx0;
w3dcgb_u8 sy0;
w3dcgb_u8 sx1;
w3dcgb_u8 sy1;
if (w3dcgb_project_world(ax, ay, az, &sx0, &sy0) == 0) return;
if (w3dcgb_project_world(bx, by, bz, &sx1, &sy1) == 0) return;
Wire3DCGB_DrawLine2D(sx0, sy0, sx1, sy1);
}Wire3DCGB_DrawLine3DColor
以暫時色彩繪製 3D 線段。
語法
void Wire3DCGB_DrawLine3DColor(w3dcgb_i16 ax, w3dcgb_i16 ay, w3dcgb_i16 az, w3dcgb_i16 bx, w3dcgb_i16 by, w3dcgb_i16 bz, w3dcgb_u8 color);參數
ax起點的世界座標 X 分量。
ay起點的世界座標 Y 分量。
az起點的世界座標 Z 分量。
bx終點的世界座標 X 分量。
by終點的世界座標 Y 分量。
bz終點的世界座標 Z 分量。
color繪圖色彩索引;範例調色盤使用 1=紅、2=藍、3=綠。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
暫時為 DrawLine3D 選用 color & 3,完成後恢復先前色彩。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Four cubes compare unity/half scale and persistent/temporary line colors.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Vec3 vertices[8]={
{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},
{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}
};
__prg_rom Wire3DCGB_Edge edges[12]={
{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},
{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}
};
Wire3DCGB_Model cube;
u8 sx;
u8 sy;
void main() {
wire_results_clear();
cube.vertices=vertices; cube.edges=edges;
cube.faces=0; cube.edge_faces=0;
cube.vertex_count=8; cube.edge_count=12; cube.face_count=0; cube.flags=0;
Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
Wire3DCGB_DrawModel(&cube,-32,32,96,0,0,0);
Wire3DCGB_DrawModelScaled(&cube,32,32,96,0,0,0,128);
Wire3DCGB_DrawModelColor(&cube,-32,-32,96,0,0,0,2);
Wire3DCGB_DrawModelScaledColor(&cube,32,-32,96,0,0,0,128,3);
result[0]=Wire3DCGB_GetLineColor();
Wire3DCGB_DrawLine3D(0,56,96,0,-56,96);
Wire3DCGB_DrawLine3DColor(-80,0,96,80,0,96,3);
result[1]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
result[2]=sx; result[3]=sy;
// Camera setters affect future projection, leaving the staged cubes intact.
Wire3DCGB_SetCamera(0,0,0,0,4,0);
result[4]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
result[5]=Wire3DCGB_ProjectPointNoRotation(0,0,96,&sx,&sy);
result[6]=sx;
Wire3DCGB_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
比較以紅、藍、綠繪製的原倍率與縮放模型,以及交錯的 3D 線段。RAM 值也用來檢查相機投影及其不旋轉版本。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_models.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:173
kitaqgb/lib/wire3d_cgb.c:9005
void Wire3DCGB_DrawLine3DColor(w3dcgb_i16 ax, w3dcgb_i16 ay, w3dcgb_i16 az, w3dcgb_i16 bx, w3dcgb_i16 by, w3dcgb_i16 bz, w3dcgb_u8 color)
{
w3dcgb_u8 old_color;
old_color = w3dcgb_line_color;
Wire3DCGB_SetLineColor(color);
Wire3DCGB_DrawLine3D(ax, ay, az, bx, by, bz);
w3dcgb_line_color = old_color;
}Wire3DCGB_DrawLineClipped2D
將有號畫面座標裁切至視埠,並以指定色彩繪製線段。
語法
void Wire3DCGB_DrawLineClipped2D(w3dcgb_i16 x0, w3dcgb_i16 y0, w3dcgb_i16 x1, w3dcgb_i16 y1, w3dcgb_u8 color);參數
x0較小的 X 端點,以視埠像素為單位;排序與裁切依此操作的注意事項。
y0較小的 Y 端點,以視埠像素為單位;排序與裁切依此操作的注意事項。
x1較大的 X 端點,以視埠像素為單位;排序與裁切依此操作的注意事項。
y1較大的 Y 端點,以視埠像素為單位;排序與裁切依此操作的注意事項。
color繪圖色彩索引;範例調色盤使用 1=紅、2=藍、3=綠。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
端點為有號值,在轉成光柵器的 u8 ABI 前先裁切。將有號 2D 線段裁切至所選視埠,再以暫時色彩繪製。拒絕 ±2047 以外的輸入。完全位於 128×96 內的線段使用快速路徑;其餘使用區域碼與有界整數交點計算,並設八次迭代保護。一般模式中接受的線段會標記 dirty 邊界。這僅為畫面裁切,不包含 3D 投影或深度裁切。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DCGB_EnableDoubleSpeed();
Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
result[2]=(u8)(sample_key1&128);
// Palette writes are performed with the LCD off, after entering VBlank.
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0;
Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
sample_lcdc=0x81;
Wire3DCGB_SetScreenOffset(0,0);
Wire3DCGB_SetCamera(0,0,0,0,0,0);
Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
Wire3DCGB_DrawLine2D(8,8,56,8);
Wire3DCGB_DrawLine2D(56,8,56,40);
Wire3DCGB_DrawLine2D(56,40,8,40);
Wire3DCGB_DrawLine2D(8,40,8,8);
Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
Wire3DCGB_SetLineColor(3);
Wire3DCGB_DrawPoint2D(64,48);
Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
Wire3DCGB_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。紅色邊框內有藍色對角線,另有綠點與綠色水平線、藍色 L,以及右上角的綠色數字 0。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:136
Signed endpoints, clipped before conversion to the rasterizer's u8 ABI.
kitaqgb/lib/wire3d_cgb.c:9745
void Wire3DCGB_DrawLineClipped2D(w3dcgb_i16 x0, w3dcgb_i16 y0,
w3dcgb_i16 x1, w3dcgb_i16 y1, w3dcgb_u8 color)
{
w3dcgb_u8 c0;
w3dcgb_u8 c1;
w3dcgb_u8 outside;
w3dcgb_u8 guard;
w3dcgb_i16 x;
w3dcgb_i16 y;
c0 = 0;
c1 = 0;
if ((((x0 | y0 | x1 | y1) & 0xFF80) != 0) || (y0 >= WIRE3DCGB_SCREEN_H) || (y1 >= WIRE3DCGB_SCREEN_H))
{
if ((x0 < -2047) || (x0 > 2047) || (y0 < -2047) || (y0 > 2047) ||
(x1 < -2047) || (x1 > 2047) || (y1 < -2047) || (y1 > 2047)) return;
c0 = w3dcgb_clip_outcode(x0, y0);
c1 = w3dcgb_clip_outcode(x1, y1);
}
guard = 0;
while (guard < 8)
{
if ((c0 | c1) == 0)
{
/* The existing ASM rasterizer handles the hot, in-window path. */
if (w3dcgb_full_mode == 0) w3dcgb_mark_dirty_line((w3dcgb_u8)x0, (w3dcgb_u8)y0,
(w3dcgb_u8)x1, (w3dcgb_u8)y1);
Wire3DCGB_DrawLine2DColor((w3dcgb_u8)x0, (w3dcgb_u8)y0,
(w3dcgb_u8)x1, (w3dcgb_u8)y1, color);
return;
}
if ((c0 & c1) != 0) return;
outside = c0;
if (outside == 0) outside = c1;
if ((outside & 12) != 0)
{
y = 0;
if ((outside & 8) != 0) y = WIRE3DCGB_SCREEN_H - 1;
if (((outside & 8) != 0) && (w3dcgb_full_mode != 0)) y = WIRE3DCGB_FULL_SCREEN_H - 1;
x = (w3dcgb_i16)(x0 + w3dcgb_clip_muldiv((w3dcgb_i16)(x1 - x0),
(w3dcgb_i16)(y - y0), (w3dcgb_i16)(y1 - y0)));
}
else
{
x = 0;
if ((outside & 2) != 0) x = WIRE3DCGB_SCREEN_W - 1;
if (((outside & 2) != 0) && (w3dcgb_full_mode != 0)) x = WIRE3DCGB_FULL_SCREEN_W - 1;
y = (w3dcgb_i16)(y0 + w3dcgb_clip_muldiv((w3dcgb_i16)(y1 - y0),
(w3dcgb_i16)(x - x0), (w3dcgb_i16)(x1 - x0)));
}
if (outside == c0) { x0 = x; y0 = y; c0 = w3dcgb_clip_outcode(x0, y0); }
else { x1 = x; y1 = y; c1 = w3dcgb_clip_outcode(x1, y1); }
guard = (w3dcgb_u8)(guard + 1);
}
}Wire3DCGB_DrawLineList2DColor
以指定色彩繪製四位元組畫面空間線段記錄列表。
語法
void Wire3DCGB_DrawLineList2DColor(const w3dcgb_u8* line_xy, w3dcgb_u8 line_count, w3dcgb_u8 color);參數
line_xy由 x0,y0,x1,y1 記錄組成的位元組陣列。
line_count線段記錄數;最多處理 64 筆。
color繪圖色彩索引;範例調色盤使用 1=紅、2=藍、3=綠。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
繪製最多 64 筆四位元組 (x0,y0,x1,y1) 記錄,忽略 null 列表。端點須位於所選視埠內。保留先前色彩,並將各線段分派至一般或全畫面光柵器。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DCGB_EnableDoubleSpeed();
Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
result[2]=(u8)(sample_key1&128);
// Palette writes are performed with the LCD off, after entering VBlank.
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0;
Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
sample_lcdc=0x81;
Wire3DCGB_SetScreenOffset(0,0);
Wire3DCGB_SetCamera(0,0,0,0,0,0);
Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
Wire3DCGB_DrawLine2D(8,8,56,8);
Wire3DCGB_DrawLine2D(56,8,56,40);
Wire3DCGB_DrawLine2D(56,40,8,40);
Wire3DCGB_DrawLine2D(8,40,8,8);
Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
Wire3DCGB_SetLineColor(3);
Wire3DCGB_DrawPoint2D(64,48);
Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
Wire3DCGB_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。紅色邊框內有藍色對角線,另有綠點與綠色水平線、藍色 L,以及右上角的綠色數字 0。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:186
kitaqgb/lib/wire3d_cgb.c:8571
void Wire3DCGB_DrawLineList2DColor(const w3dcgb_u8* line_xy,
w3dcgb_u8 line_count, w3dcgb_u8 color)
{
w3dcgb_u8 i;
w3dcgb_u8 offset;
w3dcgb_u8 old_color;
if (line_xy == 0) return;
if (line_count > WIRE3DCGB_MODEL_EDGE_LIMIT) line_count = WIRE3DCGB_MODEL_EDGE_LIMIT;
old_color = w3dcgb_line_color;
w3dcgb_line_color = (w3dcgb_u8)(color & 3);
i = 0;
offset = 0;
while (i < line_count)
{
w3dcgb_line_x0 = line_xy[(__safe_index w3dcgb_u8)offset];
offset = (w3dcgb_u8)(offset + 1);
w3dcgb_line_y0 = line_xy[(__safe_index w3dcgb_u8)offset];
offset = (w3dcgb_u8)(offset + 1);
w3dcgb_line_x1 = line_xy[(__safe_index w3dcgb_u8)offset];
offset = (w3dcgb_u8)(offset + 1);
w3dcgb_line_y1 = line_xy[(__safe_index w3dcgb_u8)offset];
offset = (w3dcgb_u8)(offset + 1);
if (w3dcgb_full_mode != 0) w3dcgb_full_line_fast_asm();
else w3dcgb_line_stage_asm();
i = (w3dcgb_u8)(i + 1);
}
w3dcgb_line_color = old_color;
}Wire3DCGB_DrawMaskedModel2D
依預先投影的頂點與邊位元遮罩,繪製啟用的模型邊。
語法
void Wire3DCGB_DrawMaskedModel2D(const Wire3DCGB_Model* model, const w3dcgb_i8* vertex_x, const w3dcgb_i8* vertex_y, const w3dcgb_u8* edge_mask, w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_u8 color);參數
model包含頂點、邊、面陣列及數量的模型;呼叫期間須保持各表可讀。
vertex_x預先投影的頂點 X 偏移陣列。
vertex_y預先投影的頂點 Y 偏移陣列。
edge_mask每條邊一個可見位元的位元組陣列,最低有效位元在前。
x中心 X 座標,以視埠像素為單位。
y中心 Y 座標,以視埠像素為單位。
color繪圖色彩索引;範例調色盤使用 1=紅、2=藍、3=綠。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
使用相對於 (x,y) 的預先投影有號位元組偏移,繪製啟用的模型邊。遮罩從最低有效位元開始,每位元組對應八條邊。所有指標與頂點索引須有效;即使邊數為零仍會讀取 edge_mask[0]。不限制任何計數上限。平移後端點在轉成位元組前須位於視埠內,負值會回繞。保留先前線色,並依目前模式分派。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Preprojected edge arrays, a clipped square, a tiny marker and a projectile.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Edge edges[4]={{0,1},{1,2},{2,3},{3,0}};
__prg_rom s8 vx8[4]={-8,8,8,-8};
__prg_rom s8 vy8[4]={-8,-8,8,8};
__prg_rom s16 vx16[4]={-12,12,12,-12};
__prg_rom s16 vy16[4]={-8,-8,8,8};
__prg_rom u8 mask[1]={5};
Wire3DCGB_Model shape;
void main() {
wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
shape.vertices=0;shape.edges=edges;shape.faces=0;shape.edge_faces=0;
shape.vertex_count=4;shape.edge_count=4;shape.face_count=0;shape.flags=0;
Wire3DCGB_SetLineColor(2);
Wire3DCGB_DrawMaskedModel2D(&shape,vx8,vy8,mask,24,24,1);
Wire3DCGB_DrawEdgeList2D(edges,4,vx8,vy8,64,24,2);
Wire3DCGB_DrawEdgeListClipped2D(edges,4,vx16,vy16,4,4,64,3);
Wire3DCGB_DrawTinyModel2D(104,24,16,3);
result[0]=Wire3DCGB_ProjectAxis48(48,96);
result[1]=Wire3DCGB_ProjectAxis48(-48,96);
Wire3DCGB_DrawFastProjectile(96,64,64,0,1);
result[2]=Wire3DCGB_GetLineColor();
Wire3DCGB_EndFrame();result[7]=0xA55A;
while(1) {}
}預期結果
以兩條紅色水平邊、藍色正方形、經裁切的綠框、綠色六像素標記與紅色投射物,比較各種列表格式。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_lists.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_lists.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:179
kitaqgb/lib/wire3d_cgb.c:8392
void Wire3DCGB_DrawMaskedModel2D(const Wire3DCGB_Model* model,
const w3dcgb_i8* vertex_x, const w3dcgb_i8* vertex_y,
const w3dcgb_u8* edge_mask,
w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_u8 color)
{
w3dcgb_u8 i;
w3dcgb_u8 bit;
w3dcgb_u8 mask_index;
w3dcgb_u8 mask;
w3dcgb_u8 a;
w3dcgb_u8 b;
w3dcgb_u8 old_color;
old_color = w3dcgb_line_color;
w3dcgb_line_color = (w3dcgb_u8)(color & 3);
i = 0;
bit = 1;
mask_index = 0;
mask = edge_mask[0];
while (i < model->edge_count)
{
if ((mask & bit) != 0)
{
a = model->edges[(__safe_index w3dcgb_u8)i].a;
b = model->edges[(__safe_index w3dcgb_u8)i].b;
w3dcgb_line_x0 = (w3dcgb_u8)((w3dcgb_i16)x + (w3dcgb_i16)vertex_x[(__safe_index w3dcgb_u8)a]);
w3dcgb_line_y0 = (w3dcgb_u8)((w3dcgb_i16)y + (w3dcgb_i16)vertex_y[(__safe_index w3dcgb_u8)a]);
w3dcgb_line_x1 = (w3dcgb_u8)((w3dcgb_i16)x + (w3dcgb_i16)vertex_x[(__safe_index w3dcgb_u8)b]);
w3dcgb_line_y1 = (w3dcgb_u8)((w3dcgb_i16)y + (w3dcgb_i16)vertex_y[(__safe_index w3dcgb_u8)b]);
if (w3dcgb_full_mode != 0) w3dcgb_full_line_fast_asm();
else w3dcgb_line_stage_asm();
}
i = (w3dcgb_u8)(i + 1);
bit = (w3dcgb_u8)(bit << 1);
if ((bit == 0) && (i < model->edge_count))
{
bit = 1;
mask_index = (w3dcgb_u8)(mask_index + 1);
mask = edge_mask[(__safe_index w3dcgb_u8)mask_index];
}
}
w3dcgb_line_color = old_color;
}Wire3DCGB_DrawModel
以指定位置與旋轉,按原倍率繪製 3D 模型。
語法
void Wire3DCGB_DrawModel(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz);參數
model包含頂點、邊、面陣列及數量的模型;呼叫期間須保持各表可讀。
x點或物件原點的世界座標 X 分量。
y點或物件原點的世界座標 Y 分量。
z點或物件原點的世界座標 Z 分量。
rx繞 X 軸旋轉;十六步為一整圈。
ry繞 Y 軸旋轉;十六步為一整圈。
rz繞 Z 軸旋轉;十六步為一整圈。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
依 DrawModelScaled 的使用約定,以 Q8 一倍倍率(256)繪製模型。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Four cubes compare unity/half scale and persistent/temporary line colors.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Vec3 vertices[8]={
{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},
{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}
};
__prg_rom Wire3DCGB_Edge edges[12]={
{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},
{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}
};
Wire3DCGB_Model cube;
u8 sx;
u8 sy;
void main() {
wire_results_clear();
cube.vertices=vertices; cube.edges=edges;
cube.faces=0; cube.edge_faces=0;
cube.vertex_count=8; cube.edge_count=12; cube.face_count=0; cube.flags=0;
Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
Wire3DCGB_DrawModel(&cube,-32,32,96,0,0,0);
Wire3DCGB_DrawModelScaled(&cube,32,32,96,0,0,0,128);
Wire3DCGB_DrawModelColor(&cube,-32,-32,96,0,0,0,2);
Wire3DCGB_DrawModelScaledColor(&cube,32,-32,96,0,0,0,128,3);
result[0]=Wire3DCGB_GetLineColor();
Wire3DCGB_DrawLine3D(0,56,96,0,-56,96);
Wire3DCGB_DrawLine3DColor(-80,0,96,80,0,96,3);
result[1]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
result[2]=sx; result[3]=sy;
// Camera setters affect future projection, leaving the staged cubes intact.
Wire3DCGB_SetCamera(0,0,0,0,4,0);
result[4]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
result[5]=Wire3DCGB_ProjectPointNoRotation(0,0,96,&sx,&sy);
result[6]=sx;
Wire3DCGB_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
比較以紅、藍、綠繪製的原倍率與縮放模型,以及交錯的 3D 線段。RAM 值也用來檢查相機投影及其不旋轉版本。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_models.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:128
kitaqgb/lib/wire3d_cgb.c:9015
void Wire3DCGB_DrawModel(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz)
{
Wire3DCGB_DrawModelScaled(model, x, y, z, rx, ry, rz, 256);
}Wire3DCGB_DrawModelColor
以暫時色彩按原倍率繪製模型。
語法
void Wire3DCGB_DrawModelColor(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz, w3dcgb_u8 color);參數
model包含頂點、邊、面陣列及數量的模型;呼叫期間須保持各表可讀。
x點或物件原點的世界座標 X 分量。
y點或物件原點的世界座標 Y 分量。
z點或物件原點的世界座標 Z 分量。
rx繞 X 軸旋轉;十六步為一整圈。
ry繞 Y 軸旋轉;十六步為一整圈。
rz繞 Z 軸旋轉;十六步為一整圈。
color繪圖色彩索引;範例調色盤使用 1=紅、2=藍、3=綠。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
以暫時色彩和 Q8 一倍倍率繪製模型,完成後恢復原色。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Four cubes compare unity/half scale and persistent/temporary line colors.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Vec3 vertices[8]={
{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},
{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}
};
__prg_rom Wire3DCGB_Edge edges[12]={
{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},
{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}
};
Wire3DCGB_Model cube;
u8 sx;
u8 sy;
void main() {
wire_results_clear();
cube.vertices=vertices; cube.edges=edges;
cube.faces=0; cube.edge_faces=0;
cube.vertex_count=8; cube.edge_count=12; cube.face_count=0; cube.flags=0;
Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
Wire3DCGB_DrawModel(&cube,-32,32,96,0,0,0);
Wire3DCGB_DrawModelScaled(&cube,32,32,96,0,0,0,128);
Wire3DCGB_DrawModelColor(&cube,-32,-32,96,0,0,0,2);
Wire3DCGB_DrawModelScaledColor(&cube,32,-32,96,0,0,0,128,3);
result[0]=Wire3DCGB_GetLineColor();
Wire3DCGB_DrawLine3D(0,56,96,0,-56,96);
Wire3DCGB_DrawLine3DColor(-80,0,96,80,0,96,3);
result[1]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
result[2]=sx; result[3]=sy;
// Camera setters affect future projection, leaving the staged cubes intact.
Wire3DCGB_SetCamera(0,0,0,0,4,0);
result[4]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
result[5]=Wire3DCGB_ProjectPointNoRotation(0,0,96,&sx,&sy);
result[6]=sx;
Wire3DCGB_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
比較以紅、藍、綠繪製的原倍率與縮放模型,以及交錯的 3D 線段。RAM 值也用來檢查相機投影及其不旋轉版本。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_models.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:130
kitaqgb/lib/wire3d_cgb.c:9021
void Wire3DCGB_DrawModelColor(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz, w3dcgb_u8 color)
{
Wire3DCGB_DrawModelScaledColor(model, x, y, z, rx, ry, rz, 256, color);
}Wire3DCGB_DrawModelScaled
縮放、旋轉並投影模型,再以目前色彩繪製選定的邊。
語法
void Wire3DCGB_DrawModelScaled(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz, w3dcgb_i16 scale_q8);參數
model包含頂點、邊、面陣列及數量的模型;呼叫期間須保持各表可讀。
x點或物件原點的世界座標 X 分量。
y點或物件原點的世界座標 Y 分量。
z點或物件原點的世界座標 Z 分量。
rx繞 X 軸旋轉;十六步為一整圈。
ry繞 Y 軸旋轉;十六步為一整圈。
rz繞 Z 軸旋轉;十六步為一整圈。
scale_q8倍率,以 256 表示一倍;非正值也視為一倍。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
以正的 Q8 倍率投影最多 24 個頂點;非正倍率視為一倍。略過一倍乘法與零角度旋轉。中間值須容納於 s16。若可使用鄰接篩選,先建立最多 16 個正面旗標,再繪製深度有效且頂點索引有效的邊。模型邊數不限制為 64。不執行近裁切平面裁切。此操作替換共用投影快取,並將線色以 OR 寫入一般 128×96 暫存區。此路徑不標記稀疏邊界;須安排完整上傳,或在稀疏上傳前明確使影格歷史失效。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Four cubes compare unity/half scale and persistent/temporary line colors.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Vec3 vertices[8]={
{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},
{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}
};
__prg_rom Wire3DCGB_Edge edges[12]={
{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},
{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}
};
Wire3DCGB_Model cube;
u8 sx;
u8 sy;
void main() {
wire_results_clear();
cube.vertices=vertices; cube.edges=edges;
cube.faces=0; cube.edge_faces=0;
cube.vertex_count=8; cube.edge_count=12; cube.face_count=0; cube.flags=0;
Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
Wire3DCGB_DrawModel(&cube,-32,32,96,0,0,0);
Wire3DCGB_DrawModelScaled(&cube,32,32,96,0,0,0,128);
Wire3DCGB_DrawModelColor(&cube,-32,-32,96,0,0,0,2);
Wire3DCGB_DrawModelScaledColor(&cube,32,-32,96,0,0,0,128,3);
result[0]=Wire3DCGB_GetLineColor();
Wire3DCGB_DrawLine3D(0,56,96,0,-56,96);
Wire3DCGB_DrawLine3DColor(-80,0,96,80,0,96,3);
result[1]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
result[2]=sx; result[3]=sy;
// Camera setters affect future projection, leaving the staged cubes intact.
Wire3DCGB_SetCamera(0,0,0,0,4,0);
result[4]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
result[5]=Wire3DCGB_ProjectPointNoRotation(0,0,96,&sx,&sy);
result[6]=sx;
Wire3DCGB_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
比較以紅、藍、綠繪製的原倍率與縮放模型,以及交錯的 3D 線段。RAM 值也用來檢查相機投影及其不旋轉版本。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_models.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:129
kitaqgb/lib/wire3d_cgb.c:9396
void Wire3DCGB_DrawModelScaled(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz, w3dcgb_i16 scale_q8)
{
w3dcgb_u8 i;
w3dcgb_u8 count;
w3dcgb_u8 edge_count;
w3dcgb_u8 face_count;
w3dcgb_u8 camera_unrotated;
w3dcgb_u8 unit_scale;
if (model == 0) return;
if (model->vertices == 0) return;
if (model->edges == 0) return;
if (scale_q8 <= 0) scale_q8 = 256;
count = model->vertex_count;
if (count > WIRE3DCGB_MODEL_VERTEX_LIMIT) count = WIRE3DCGB_MODEL_VERTEX_LIMIT;
unit_scale = 0;
if (scale_q8 == 256) unit_scale = 1;
camera_unrotated = 0;
if ((w3dcgb_cam_yaw == 0) && (w3dcgb_cam_pitch == 0) && (w3dcgb_cam_roll == 0))
{
camera_unrotated = 1;
}
i = 0;
while (i < count)
{
const Wire3DCGB_Vec3* v;
w3dcgb_i16 vx;
w3dcgb_i16 vy;
w3dcgb_i16 vz;
w3dcgb_u8 sx;
w3dcgb_u8 sy;
w3dcgb_u8 projected;
v = &model->vertices[(__safe_index w3dcgb_u8)i];
if (unit_scale != 0)
{
vx = v->x;
vy = v->y;
vz = v->z;
}
else
{
vx = (w3dcgb_i16)((v->x * scale_q8) >> 8);
vy = (w3dcgb_i16)((v->y * scale_q8) >> 8);
vz = (w3dcgb_i16)((v->z * scale_q8) >> 8);
}
if (ry != 0) w3dcgb_rotate_y(&vx, &vz, (w3dcgb_i8)ry);
if (rx != 0) w3dcgb_rotate_x(&vy, &vz, (w3dcgb_i8)rx);
if (rz != 0) w3dcgb_rotate_z(&vx, &vy, (w3dcgb_i8)rz);
vx = (w3dcgb_i16)(vx + x);
vy = (w3dcgb_i16)(vy + y);
vz = (w3dcgb_i16)(vz + z);
if (camera_unrotated != 0)
{
vx = (w3dcgb_i16)(vx - w3dcgb_cam_x);
vy = (w3dcgb_i16)(vy - w3dcgb_cam_y);
vz = (w3dcgb_i16)(vz - w3dcgb_cam_z);
projected = w3dcgb_project_camera_space(vx, vy, vz, &sx, &sy);
}
else
{
projected = w3dcgb_project_world(vx, vy, vz, &sx, &sy);
}
if (projected != 0)
{
w3dcgb_screen_x[(__safe_index w3dcgb_u8)i] = sx;
w3dcgb_screen_y[(__safe_index w3dcgb_u8)i] = sy;
w3dcgb_screen_visible[(__safe_index w3dcgb_u8)i] = 1;
}
else
{
w3dcgb_screen_visible[(__safe_index w3dcgb_u8)i] = 0;
}
i = (w3dcgb_u8)(i + 1);
}
face_count = model->face_count;
if (face_count > WIRE3DCGB_MODEL_FACE_LIMIT) face_count = WIRE3DCGB_MODEL_FACE_LIMIT;
if ((model->flags & WIRE3DCGB_MODEL_HIDDEN_LINES) && (model->faces != 0) && (model->edge_faces != 0))
{
w3dcgb_build_face_visibility(model, count, face_count);
}
edge_count = model->edge_count;
i = 0;
while (i < edge_count)
{
const Wire3DCGB_Edge* e;
e = &model->edges[(__safe_index w3dcgb_u8)i];
if ((e->a < count) && (e->b < count))
{
if (w3dcgb_screen_visible[(__safe_index w3dcgb_u8)e->a] &&
w3dcgb_screen_visible[(__safe_index w3dcgb_u8)e->b] &&
w3dcgb_is_edge_visible(model, i, face_count))
{
w3dcgb_draw_model_line(
w3dcgb_screen_x[(__safe_index w3dcgb_u8)e->a],
w3dcgb_screen_y[(__safe_index w3dcgb_u8)e->a],
w3dcgb_screen_x[(__safe_index w3dcgb_u8)e->b],
w3dcgb_screen_y[(__safe_index w3dcgb_u8)e->b]);
}
}
i = (w3dcgb_u8)(i + 1);
}
}Wire3DCGB_DrawModelScaledColor
以指定倍率與暫時線色繪製模型。
語法
void Wire3DCGB_DrawModelScaledColor(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz, w3dcgb_i16 scale_q8, w3dcgb_u8 color);參數
model包含頂點、邊、面陣列及數量的模型;呼叫期間須保持各表可讀。
x點或物件原點的世界座標 X 分量。
y點或物件原點的世界座標 Y 分量。
z點或物件原點的世界座標 Z 分量。
rx繞 X 軸旋轉;十六步為一整圈。
ry繞 Y 軸旋轉;十六步為一整圈。
rz繞 Z 軸旋轉;十六步為一整圈。
scale_q8倍率,以 256 表示一倍;非正值也視為一倍。
color繪圖色彩索引;範例調色盤使用 1=紅、2=藍、3=綠。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
在呼叫 DrawModelScaled 期間選用 color & 3,結束後恢復進入時的色彩。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Four cubes compare unity/half scale and persistent/temporary line colors.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Vec3 vertices[8]={
{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},
{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}
};
__prg_rom Wire3DCGB_Edge edges[12]={
{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},
{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}
};
Wire3DCGB_Model cube;
u8 sx;
u8 sy;
void main() {
wire_results_clear();
cube.vertices=vertices; cube.edges=edges;
cube.faces=0; cube.edge_faces=0;
cube.vertex_count=8; cube.edge_count=12; cube.face_count=0; cube.flags=0;
Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
Wire3DCGB_DrawModel(&cube,-32,32,96,0,0,0);
Wire3DCGB_DrawModelScaled(&cube,32,32,96,0,0,0,128);
Wire3DCGB_DrawModelColor(&cube,-32,-32,96,0,0,0,2);
Wire3DCGB_DrawModelScaledColor(&cube,32,-32,96,0,0,0,128,3);
result[0]=Wire3DCGB_GetLineColor();
Wire3DCGB_DrawLine3D(0,56,96,0,-56,96);
Wire3DCGB_DrawLine3DColor(-80,0,96,80,0,96,3);
result[1]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
result[2]=sx; result[3]=sy;
// Camera setters affect future projection, leaving the staged cubes intact.
Wire3DCGB_SetCamera(0,0,0,0,4,0);
result[4]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
result[5]=Wire3DCGB_ProjectPointNoRotation(0,0,96,&sx,&sy);
result[6]=sx;
Wire3DCGB_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
比較以紅、藍、綠繪製的原倍率與縮放模型,以及交錯的 3D 線段。RAM 值也用來檢查相機投影及其不旋轉版本。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_models.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:131
kitaqgb/lib/wire3d_cgb.c:9510
void Wire3DCGB_DrawModelScaledColor(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz, w3dcgb_i16 scale_q8, w3dcgb_u8 color)
{
w3dcgb_u8 old_color;
old_color = w3dcgb_line_color;
Wire3DCGB_SetLineColor(color);
Wire3DCGB_DrawModelScaled(model, x, y, z, rx, ry, rz, scale_q8);
w3dcgb_line_color = old_color;
}Wire3DCGB_DrawPoint2D
以目前色彩寫入一個像素。
語法
void Wire3DCGB_DrawPoint2D(w3dcgb_u8 x, w3dcgb_u8 y);參數
x中心 X 座標,以視埠像素為單位。
y中心 Y 座標,以視埠像素為單位。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
一般模式下拒絕 128×96 外的座標、標記稀疏邊界,並以目前色彩(含零)替換暫存像素。全畫面模式則改畫兩端重合的快速線段,因此零表示色彩 3,無效座標會鎖存該影格的溢位旗標。畫面傳輸稍後進行。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DCGB_EnableDoubleSpeed();
Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
result[2]=(u8)(sample_key1&128);
// Palette writes are performed with the LCD off, after entering VBlank.
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0;
Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
sample_lcdc=0x81;
Wire3DCGB_SetScreenOffset(0,0);
Wire3DCGB_SetCamera(0,0,0,0,0,0);
Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
Wire3DCGB_DrawLine2D(8,8,56,8);
Wire3DCGB_DrawLine2D(56,8,56,40);
Wire3DCGB_DrawLine2D(56,40,8,40);
Wire3DCGB_DrawLine2D(8,40,8,8);
Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
Wire3DCGB_SetLineColor(3);
Wire3DCGB_DrawPoint2D(64,48);
Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
Wire3DCGB_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。紅色邊框內有藍色對角線,另有綠點與綠色水平線、藍色 L,以及右上角的綠色數字 0。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:174
kitaqgb/lib/wire3d_cgb.c:8283
void Wire3DCGB_DrawPoint2D(w3dcgb_u8 x, w3dcgb_u8 y)
{
w3dcgb_u8 tile;
if (w3dcgb_full_mode != 0)
{
w3dcgb_line_x0 = x;
w3dcgb_line_y0 = y;
w3dcgb_line_x1 = x;
w3dcgb_line_y1 = y;
w3dcgb_full_line_fast_asm();
return;
}
if (x >= WIRE3DCGB_SCREEN_W) return;
if (y >= WIRE3DCGB_SCREEN_H) return;
if (w3dcgb_full_frame_transfer == 0)
{
tile = (w3dcgb_u8)(((x >> 3) * W3DCGB_TILE_H) + (y >> 3));
if (tile < w3dcgb_dirty_min_tile) w3dcgb_dirty_min_tile = tile;
if (tile > w3dcgb_dirty_max_tile) w3dcgb_dirty_max_tile = tile;
}
w3dcgb_plot_x = x;
w3dcgb_plot_y = y;
w3dcgb_plot_stage_asm();
}Wire3DCGB_DrawScene
由近至遠繪製最多八個物件,以先前模型的面遮住後續線段。
語法
void Wire3DCGB_DrawScene(Wire3DCGB_Object* objects, w3dcgb_u8 count);參數
objects包含位置、旋轉、倍率與可見旗標的物件陣列。
count提供的陣列項目數;處理上限請參閱各操作的說明。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
不改動呼叫端陣列,依相機空間中原點的深度,將最多八個物件由近至遠排序。清空遮罩,依先前覆蓋區域繪製可見模型,再將其面加入遮蔽物。模型陣列與面索引須有效。色彩零繼承目前色彩,可能是前一物件的色彩。結束時恢復進入時的色彩並停用遮蔽。此模型路徑用於一般 128×96 暫存區。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// A near square hides the middle of a farther blue line, regardless of array order.
#include "wire_cgb_example.h"
#include "wire_cgb_plane.h"
__prg_rom Wire3DCGB_Vec3 back_vertices[2]={{-96,0,0},{96,0,0}};
__prg_rom Wire3DCGB_Edge back_edges[1]={{0,1}};
Wire3DCGB_Model back;
Wire3DCGB_Object objects[2];
void main() {
u8 i;
wire_results_clear();wire_plane_setup();
back.vertices=back_vertices;back.edges=back_edges;back.faces=0;back.edge_faces=0;
back.vertex_count=2;back.edge_count=1;back.face_count=0;back.flags=0;
for(i=0;i<2;i++) {
objects[i].x=0;objects[i].y=0;objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
objects[i].scale_q8=256;objects[i].visible=1;
}
objects[0].model=&back;objects[0].z=128;objects[0].color=2;
objects[1].model=&plane;objects[1].z=64;objects[1].color=1;
Wire3DCGB_Init();wire_colors();Wire3DCGB_BeginFrame();Wire3DCGB_SetLineColor(3);
Wire3DCGB_DrawScene(objects,2);
result[0]=objects[0].z;result[1]=objects[1].z;result[2]=Wire3DCGB_GetLineColor();
Wire3DCGB_EndFrame();result[7]=0xA55A;
while(1) {}
}預期結果
位於 (46,30)..(82,66) 的近處紅色正方形遮住較遠藍色水平線的中段,只留下左右兩段可見。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_scene.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_scene.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:155
kitaqgb/lib/wire3d_cgb.c:8918
void Wire3DCGB_DrawScene(Wire3DCGB_Object* objects, w3dcgb_u8 count)
{
w3dcgb_u8 scene_count;
w3dcgb_u8 i;
w3dcgb_u8 old_color;
if (objects == 0) return;
scene_count = count;
if (scene_count > WIRE3DCGB_SCENE_OBJECT_LIMIT) scene_count = WIRE3DCGB_SCENE_OBJECT_LIMIT;
i = 0;
while (i < scene_count)
{
w3dcgb_scene_order[(__safe_index w3dcgb_u8)i] = i;
w3dcgb_scene_depth[(__safe_index w3dcgb_u8)i] = w3dcgb_scene_object_depth(&objects[(__safe_index w3dcgb_u8)i]);
i = (w3dcgb_u8)(i + 1);
}
i = 0;
while (i < scene_count)
{
w3dcgb_u8 j;
j = (w3dcgb_u8)(i + 1);
while (j < scene_count)
{
w3dcgb_u8 oi;
w3dcgb_u8 oj;
oi = w3dcgb_scene_order[(__safe_index w3dcgb_u8)i];
oj = w3dcgb_scene_order[(__safe_index w3dcgb_u8)j];
if (w3dcgb_scene_depth[(__safe_index w3dcgb_u8)oj] < w3dcgb_scene_depth[(__safe_index w3dcgb_u8)oi])
{
w3dcgb_scene_order[(__safe_index w3dcgb_u8)i] = oj;
w3dcgb_scene_order[(__safe_index w3dcgb_u8)j] = oi;
}
j = (w3dcgb_u8)(j + 1);
}
i = (w3dcgb_u8)(i + 1);
}
old_color = w3dcgb_line_color;
w3dcgb_clear_occlusion_mask();
w3dcgb_occlusion_active = 0;
i = 0;
while (i < scene_count)
{
Wire3DCGB_Object* obj;
obj = &objects[(__safe_index w3dcgb_u8)w3dcgb_scene_order[(__safe_index w3dcgb_u8)i]];
if ((obj->visible != 0) && (obj->model != 0))
{
if (i == 0) w3dcgb_occlusion_active = 0;
else w3dcgb_occlusion_active = 1;
if (obj->color != 0) Wire3DCGB_SetLineColor(obj->color);
Wire3DCGB_DrawModelScaled(obj->model, obj->x, obj->y, obj->z, (w3dcgb_i8)obj->rx, (w3dcgb_i8)obj->ry, (w3dcgb_i8)obj->rz, obj->scale_q8);
w3dcgb_occlusion_active = 0;
w3dcgb_mark_model_occluder(obj->model);
}
i = (w3dcgb_u8)(i + 1);
}
w3dcgb_occlusion_active = 0;
w3dcgb_line_color = old_color;
}Wire3DCGB_DrawTinyModel2D
繪製以前端與尾端表示方向的六像素標記。
語法
void Wire3DCGB_DrawTinyModel2D(w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_u8 turn, w3dcgb_u8 color);參數
x中心 X 座標,以視埠像素為單位。
y中心 Y 座標,以視埠像素為單位。
turn以低五位元選擇小型標記方向的值。
color繪圖色彩索引;範例調色盤使用 1=紅、2=藍、3=綠。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
透過 128×96 點繪製器畫出六像素標記,並保留線色。中心超出 X=3..124 或 Y=3..92 則忽略。turn 的低五位元選擇左/直/右的前端與尾端偏移;這不是一般 3D 變換,也不分派至全畫面繪圖器。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Preprojected edge arrays, a clipped square, a tiny marker and a projectile.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Edge edges[4]={{0,1},{1,2},{2,3},{3,0}};
__prg_rom s8 vx8[4]={-8,8,8,-8};
__prg_rom s8 vy8[4]={-8,-8,8,8};
__prg_rom s16 vx16[4]={-12,12,12,-12};
__prg_rom s16 vy16[4]={-8,-8,8,8};
__prg_rom u8 mask[1]={5};
Wire3DCGB_Model shape;
void main() {
wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
shape.vertices=0;shape.edges=edges;shape.faces=0;shape.edge_faces=0;
shape.vertex_count=4;shape.edge_count=4;shape.face_count=0;shape.flags=0;
Wire3DCGB_SetLineColor(2);
Wire3DCGB_DrawMaskedModel2D(&shape,vx8,vy8,mask,24,24,1);
Wire3DCGB_DrawEdgeList2D(edges,4,vx8,vy8,64,24,2);
Wire3DCGB_DrawEdgeListClipped2D(edges,4,vx16,vy16,4,4,64,3);
Wire3DCGB_DrawTinyModel2D(104,24,16,3);
result[0]=Wire3DCGB_ProjectAxis48(48,96);
result[1]=Wire3DCGB_ProjectAxis48(-48,96);
Wire3DCGB_DrawFastProjectile(96,64,64,0,1);
result[2]=Wire3DCGB_GetLineColor();
Wire3DCGB_EndFrame();result[7]=0xA55A;
while(1) {}
}預期結果
以兩條紅色水平邊、藍色正方形、經裁切的綠框、綠色六像素標記與紅色投射物,比較各種列表格式。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_lists.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_lists.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:175
kitaqgb/lib/wire3d_cgb.c:8313
void Wire3DCGB_DrawTinyModel2D(w3dcgb_u8 x, w3dcgb_u8 y,
w3dcgb_u8 turn, w3dcgb_u8 color)
{
w3dcgb_u8 nose_x;
w3dcgb_u8 tail_x;
w3dcgb_u8 old_color;
if ((x < 3) || (x > 124) || (y < 3) || (y > (w3dcgb_u8)(WIRE3DCGB_SCREEN_H - 4))) return;
nose_x = x;
tail_x = x;
turn = (w3dcgb_u8)(turn & 31);
if (turn < 12)
{
nose_x = (w3dcgb_u8)(x + 1);
tail_x = (w3dcgb_u8)(x - 1);
}
else if (turn >= 20)
{
nose_x = (w3dcgb_u8)(x - 1);
tail_x = (w3dcgb_u8)(x + 1);
}
old_color = w3dcgb_line_color;
w3dcgb_line_color = (w3dcgb_u8)(color & 3);
w3dcgb_plot_x = nose_x;
w3dcgb_plot_y = (w3dcgb_u8)(y - 2);
w3dcgb_plot_stage_asm();
w3dcgb_plot_x = x;
w3dcgb_plot_y = (w3dcgb_u8)(y - 1);
w3dcgb_plot_stage_asm();
w3dcgb_plot_x = (w3dcgb_u8)(x - 2);
w3dcgb_plot_y = (w3dcgb_u8)(y + 1);
w3dcgb_plot_stage_asm();
w3dcgb_plot_x = (w3dcgb_u8)(x + 2);
w3dcgb_plot_stage_asm();
w3dcgb_plot_x = x;
w3dcgb_plot_y = y;
w3dcgb_plot_stage_asm();
w3dcgb_plot_x = tail_x;
w3dcgb_plot_y = (w3dcgb_u8)(y + 2);
w3dcgb_plot_stage_asm();
w3dcgb_line_color = old_color;
}Wire3DCGB_DrawWhiteBorderFast
在 128×96 暫存區周圍繪製色彩索引 2、寬一像素的邊框。
語法
void Wire3DCGB_DrawWhiteBorderFast();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
在一般暫存區周圍寫入色彩 2、寬一像素的邊框,保留內部像素與 WRAM 記憶體庫選擇。實際可見色彩取決於調色盤。不標記 dirty 範圍;稀疏傳輸的呼叫端須安排上傳。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// A cleared 24-pixel strip and a palette-index-2 border have distinct purposes.
#include "wire_cgb_example.h"
void main() {
u8 y;
wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
for(y=0;y<96;y++) Wire3DCGB_DrawLine2D(0,y,31,y);
Wire3DCGB_EraseLeftGuard24Fast();
// With this example's palette, color index 2 is blue rather than white.
Wire3DCGB_DrawWhiteBorderFast();
Wire3DCGB_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
左側 24 欄被清空,留下紅色直條;色彩索引 2 的外框為藍色。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_guard.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_guard.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:147
kitaqgb/lib/wire3d_cgb.c:9369
void Wire3DCGB_DrawWhiteBorderFast()
{
w3dcgb_draw_white_border_asm();
}Wire3DCGB_EnableAtomicMaps
設定 128×96 畫面呈現,使其交替使用兩個背景地圖。
語法
void Wire3DCGB_EnableAtomicMaps();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
僅於啟動時使用:保留兩個 BG 地圖,排入佇列的 HUD 圖塊會同步到兩邊。於 128×96 啟動階段啟用地圖交替一次;若為全畫面模式或已啟用則忽略。LCD 開啟時先等待 VBlank 再關閉,將 9800 的兩庫內容複製到 9C00,並分別設定視埠屬性使用圖塊庫 0/1。恢復 LCDC 時選取地圖 9C00,且 VBK 設為零。兩個 BG 地圖皆被保留,佇列中的 HUD 圖塊編號會複製到兩邊。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Reuse both VRAM banks and remove old geometry while presenting sparse frames.
#include "wire_cgb_example.h"
void main() {
wire_results_clear(); Wire3DCGB_Init();
Wire3DCGB_ClearFrameTiles();
Wire3DCGB_EnableAtomicMaps(); wire_colors();
// First frame: red on the left. Fast begin invalidates both bank histories.
Wire3DCGB_BeginFrameFast(); wire_frame(8,8,32,32,1);
Wire3DCGB_EndFrameFast();
// Second frame: blue in the middle, with the old red frame removed.
Wire3DCGB_BeginFrameSparse(); wire_frame(40,40,64,64,2);
Wire3DCGB_EndFrameSparse();
// Third frame: explicitly clearing a stage discards its first green point.
Wire3DCGB_BeginFrameSparse();
Wire3DCGB_SetLineColor(3); Wire3DCGB_DrawPoint2D(4,4);
Wire3DCGB_ClearSparseStageFast();
// The final image contains only this green frame on the right.
wire_frame(80,8,112,32,3);
Wire3DCGB_MarkDirtyRect2D(80,8,112,32);
Wire3DCGB_InvalidateFrameHistory();
Wire3DCGB_EndFrameSparseNow();
result[0]=Wire3DCGB_GetLineColor();
result[7]=0xA55A;
while(1) {}
}預期結果
先前繪製的紅框與藍框消失,只留下 (80,8)..(112,32) 的最後一個綠框,示範稀疏上傳與歷史管理。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_sparse.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_sparse.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:144
Startup-only: reserves both BG maps; queued HUD tiles are mirrored.
kitaqgb/lib/wire3d_cgb.c:7912
void Wire3DCGB_EnableAtomicMaps()
{
if ((w3dcgb_full_mode != 0) || (w3dcgb_atomic_maps != 0)) return;
__asm {
w3dam_wait:
LDH_A_MEM 68
CP_IMM 144
JR_C w3dam_wait
LDH_A_MEM 64
PUSH_AF
XOR_A
LDH_MEM_A 64
LDH_MEM_A 79
LD_HL_IMM 0x9800
LD_DE_IMM 0x9C00
LD_B_IMM 4
w3dam_copy_page:
LD_C_IMM 0
w3dam_copy_byte:
LD_A_HL
INC_HL
LD_DE_A
INC_DE
DEC_C
JR_NZ w3dam_copy_byte
DEC_B
JR_NZ w3dam_copy_page
LDH_A_MEM 79
AND_IMM 1
JR_NZ w3dam_attrs
LD_A_IMM 1
LDH_MEM_A 79
LD_HL_IMM 0x9800
LD_DE_IMM 0x9C00
LD_B_IMM 4
JR w3dam_copy_page
w3dam_attrs:
LD_HL_IMM 0x9800
LD_DE_IMM 0x9C00
LD_B_IMM 12
w3dam_row:
LD_C_IMM 16
w3dam_cell:
XOR_A
LDI_HL_A
LD_A_IMM 8
LD_DE_A
INC_DE
DEC_C
JR_NZ w3dam_cell
LD_A_L
ADD_A_IMM 16
LD_L_A
JR_NC w3dam_hl_ready
INC_H
w3dam_hl_ready:
LD_A_E
ADD_A_IMM 16
LD_E_A
JR_NC w3dam_de_ready
INC_D
w3dam_de_ready:
DEC_B
JR_NZ w3dam_row
LD_A_IMM 1
LD_MEM_A w3dcgb_atomic_maps
XOR_A
LDH_MEM_A 79
POP_AF
OR_IMM 8
LDH_MEM_A 64
RET
}
}Wire3DCGB_EnableDoubleSpeed
將 CGB CPU 切換為倍速運作。
語法
void Wire3DCGB_EnableDoubleSpeed();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
在 CGB 上,若 KEY1 已回報倍速則直接返回;否則要求切換速度並呼叫 STOP 輔助函式。此 API 假定使用 CGB 硬體,不提供單色機種的替代路徑。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DCGB_EnableDoubleSpeed();
Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
result[2]=(u8)(sample_key1&128);
// Palette writes are performed with the LCD off, after entering VBlank.
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0;
Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
sample_lcdc=0x81;
Wire3DCGB_SetScreenOffset(0,0);
Wire3DCGB_SetCamera(0,0,0,0,0,0);
Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
Wire3DCGB_DrawLine2D(8,8,56,8);
Wire3DCGB_DrawLine2D(56,8,56,40);
Wire3DCGB_DrawLine2D(56,40,8,40);
Wire3DCGB_DrawLine2D(8,40,8,8);
Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
Wire3DCGB_SetLineColor(3);
Wire3DCGB_DrawPoint2D(64,48);
Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
Wire3DCGB_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。紅色邊框內有藍色對角線,另有綠點與綠色水平線、藍色 L,以及右上角的綠色數字 0。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:116
kitaqgb/lib/wire3d_cgb.c:1081
void Wire3DCGB_EnableDoubleSpeed()
{
if ((w3dcgb_reg_key1 & 0x80) != 0) return;
w3dcgb_reg_key1 = 1;
w3dcgb_cgb_speed_switch_asm();
}Wire3DCGB_EndFrame
上傳並顯示完成的影格。
語法
void Wire3DCGB_EndFrame();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
一般模式會送出佇列中的 BG 寫入、傳輸整個暫存區,並顯示完成的圖塊庫。全畫面模式傳輸並顯示已配置圖塊,不送出 HUD 佇列。須啟用 LCD,並遵守傳輸輔助函式的記憶體庫與中斷約定;可能跨越多個影格。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
CGB稀疏顯示啟動時,首次使用各目標記憶體區(前兩幀)會更新整個視窗,清除初始化圖塊。量測包含啟動成本。一般DrawLine2D不登記稀疏範圍,請使用DrawLineClipped2D或明確呼叫MarkDirtyRect2D。
使用範例
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DCGB_EnableDoubleSpeed();
Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
result[2]=(u8)(sample_key1&128);
// Palette writes are performed with the LCD off, after entering VBlank.
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0;
Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
sample_lcdc=0x81;
Wire3DCGB_SetScreenOffset(0,0);
Wire3DCGB_SetCamera(0,0,0,0,0,0);
Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
Wire3DCGB_DrawLine2D(8,8,56,8);
Wire3DCGB_DrawLine2D(56,8,56,40);
Wire3DCGB_DrawLine2D(56,40,8,40);
Wire3DCGB_DrawLine2D(8,40,8,8);
Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
Wire3DCGB_SetLineColor(3);
Wire3DCGB_DrawPoint2D(64,48);
Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
Wire3DCGB_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。紅色邊框內有藍色對角線,另有綠點與綠色水平線、藍色 L,以及右上角的綠色數字 0。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:189
kitaqgb/lib/wire3d_cgb.c:9881
void Wire3DCGB_EndFrame()
{
if (w3dcgb_full_mode != 0)
{
w3dcgb_full_transfer_asm();
w3dcgb_full_present_asm();
return;
}
if (w3dcgb_bgq_count != 0)
{
w3dcgb_wait_vblank_start();
w3dcgb_flush_bg_queue();
}
w3dcgb_transfer_stage_asm();
w3dcgb_present_stage_asm();
}Wire3DCGB_EndFrameFast
不送出佇列中的背景寫入,上傳並顯示完整影格。
語法
void Wire3DCGB_EndFrameFast();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
不送出 BG 佇列,直接傳輸並顯示所選模式的完整影格。不消耗待處理的 HUD 寫入。須遵守與 EndFrame 相同的 LCD、記憶體庫及中斷條件,並使用完整執行階段建置。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
CGB稀疏顯示啟動時,首次使用各目標記憶體區(前兩幀)會更新整個視窗,清除初始化圖塊。量測包含啟動成本。一般DrawLine2D不登記稀疏範圍,請使用DrawLineClipped2D或明確呼叫MarkDirtyRect2D。
使用範例
#pragma bank 0
// Reuse both VRAM banks and remove old geometry while presenting sparse frames.
#include "wire_cgb_example.h"
void main() {
wire_results_clear(); Wire3DCGB_Init();
Wire3DCGB_ClearFrameTiles();
Wire3DCGB_EnableAtomicMaps(); wire_colors();
// First frame: red on the left. Fast begin invalidates both bank histories.
Wire3DCGB_BeginFrameFast(); wire_frame(8,8,32,32,1);
Wire3DCGB_EndFrameFast();
// Second frame: blue in the middle, with the old red frame removed.
Wire3DCGB_BeginFrameSparse(); wire_frame(40,40,64,64,2);
Wire3DCGB_EndFrameSparse();
// Third frame: explicitly clearing a stage discards its first green point.
Wire3DCGB_BeginFrameSparse();
Wire3DCGB_SetLineColor(3); Wire3DCGB_DrawPoint2D(4,4);
Wire3DCGB_ClearSparseStageFast();
// The final image contains only this green frame on the right.
wire_frame(80,8,112,32,3);
Wire3DCGB_MarkDirtyRect2D(80,8,112,32);
Wire3DCGB_InvalidateFrameHistory();
Wire3DCGB_EndFrameSparseNow();
result[0]=Wire3DCGB_GetLineColor();
result[7]=0xA55A;
while(1) {}
}預期結果
先前繪製的紅框與藍框消失,只留下 (80,8)..(112,32) 的最後一個綠框,示範稀疏上傳與歷史管理。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_sparse.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_sparse.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:190
kitaqgb/lib/wire3d_cgb.c:9902
void Wire3DCGB_EndFrameFast()
{
if (w3dcgb_full_mode != 0)
{
w3dcgb_full_transfer_asm();
w3dcgb_full_present_asm();
return;
}
w3dcgb_transfer_stage_asm();
w3dcgb_present_stage_asm();
}Wire3DCGB_EndFrameSparse
等待新的 VBlank,再上傳並顯示所需的稀疏範圍。
語法
void Wire3DCGB_EndFrameSparse();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
一般模式等待新的 VBlank 後呼叫 EndFrameSparseNow。全畫面模式改用自身的完整傳輸與顯示路徑。須具備完整執行階段並啟用 LCD;不保證在一個影格內完成。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
CGB稀疏顯示啟動時,首次使用各目標記憶體區(前兩幀)會更新整個視窗,清除初始化圖塊。量測包含啟動成本。一般DrawLine2D不登記稀疏範圍,請使用DrawLineClipped2D或明確呼叫MarkDirtyRect2D。
使用範例
#pragma bank 0
// Reuse both VRAM banks and remove old geometry while presenting sparse frames.
#include "wire_cgb_example.h"
void main() {
wire_results_clear(); Wire3DCGB_Init();
Wire3DCGB_ClearFrameTiles();
Wire3DCGB_EnableAtomicMaps(); wire_colors();
// First frame: red on the left. Fast begin invalidates both bank histories.
Wire3DCGB_BeginFrameFast(); wire_frame(8,8,32,32,1);
Wire3DCGB_EndFrameFast();
// Second frame: blue in the middle, with the old red frame removed.
Wire3DCGB_BeginFrameSparse(); wire_frame(40,40,64,64,2);
Wire3DCGB_EndFrameSparse();
// Third frame: explicitly clearing a stage discards its first green point.
Wire3DCGB_BeginFrameSparse();
Wire3DCGB_SetLineColor(3); Wire3DCGB_DrawPoint2D(4,4);
Wire3DCGB_ClearSparseStageFast();
// The final image contains only this green frame on the right.
wire_frame(80,8,112,32,3);
Wire3DCGB_MarkDirtyRect2D(80,8,112,32);
Wire3DCGB_InvalidateFrameHistory();
Wire3DCGB_EndFrameSparseNow();
result[0]=Wire3DCGB_GetLineColor();
result[7]=0xA55A;
while(1) {}
}預期結果
先前繪製的紅框與藍框消失,只留下 (80,8)..(112,32) 的最後一個綠框,示範稀疏上傳與歷史管理。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_sparse.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_sparse.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:191
kitaqgb/lib/wire3d_cgb.c:9917
void Wire3DCGB_EndFrameSparse()
{
if (w3dcgb_full_mode != 0)
{
w3dcgb_full_transfer_asm();
w3dcgb_full_present_asm();
return;
}
w3dcgb_wait_vblank_start();
Wire3DCGB_EndFrameSparseNow();
}Wire3DCGB_EndFrameSparseNow
不先等待新的 VBlank,送出背景寫入與目前/N−2 的稀疏範圍。
語法
void Wire3DCGB_EndFrameSparseNow();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
送出佇列中的 BG 寫入,將目前/N−2 的稀疏圖塊範圍上傳至後方庫並顯示。略過起始的新 VBlank 等待,但一般地圖模式在恢復空白 HUD 圖塊時仍會等待,DMA/顯示也可能等待。完整執行階段的全畫面模式交由自身路徑處理。須啟用 LCD,且 DMA 執行期間保持 SVBK/VBK 穩定。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
CGB稀疏顯示啟動時,首次使用各目標記憶體區(前兩幀)會更新整個視窗,清除初始化圖塊。量測包含啟動成本。一般DrawLine2D不登記稀疏範圍,請使用DrawLineClipped2D或明確呼叫MarkDirtyRect2D。
使用範例
#pragma bank 0
// Reuse both VRAM banks and remove old geometry while presenting sparse frames.
#include "wire_cgb_example.h"
void main() {
wire_results_clear(); Wire3DCGB_Init();
Wire3DCGB_ClearFrameTiles();
Wire3DCGB_EnableAtomicMaps(); wire_colors();
// First frame: red on the left. Fast begin invalidates both bank histories.
Wire3DCGB_BeginFrameFast(); wire_frame(8,8,32,32,1);
Wire3DCGB_EndFrameFast();
// Second frame: blue in the middle, with the old red frame removed.
Wire3DCGB_BeginFrameSparse(); wire_frame(40,40,64,64,2);
Wire3DCGB_EndFrameSparse();
// Third frame: explicitly clearing a stage discards its first green point.
Wire3DCGB_BeginFrameSparse();
Wire3DCGB_SetLineColor(3); Wire3DCGB_DrawPoint2D(4,4);
Wire3DCGB_ClearSparseStageFast();
// The final image contains only this green frame on the right.
wire_frame(80,8,112,32,3);
Wire3DCGB_MarkDirtyRect2D(80,8,112,32);
Wire3DCGB_InvalidateFrameHistory();
Wire3DCGB_EndFrameSparseNow();
result[0]=Wire3DCGB_GetLineColor();
result[7]=0xA55A;
while(1) {}
}預期結果
先前繪製的紅框與藍框消失,只留下 (80,8)..(112,32) 的最後一個綠框,示範稀疏上傳與歷史管理。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_sparse.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_sparse.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:192
kitaqgb/lib/wire3d_cgb.c:9935
void Wire3DCGB_EndFrameSparseNow()
{
#ifndef WIRE3DCGB_MINIMAL_RUNTIME
if (w3dcgb_full_mode != 0)
{
w3dcgb_full_transfer_asm();
w3dcgb_full_present_asm();
return;
}
#endif
/* Atomic mode never writes a displayed tile and does not need a
frame-long VBlank wait before starting an off-screen upload. */
if (w3dcgb_atomic_maps == 0) w3dcgb_restore_hud_blank_tile_asm();
if (w3dcgb_bgq_count != 0) w3dcgb_flush_bg_queue();
w3dcgb_transfer_dirty_tiles();
w3dcgb_present_stage_asm();
}Wire3DCGB_EraseLeftGuard24Fast
清空一般暫存區最左側 24 欄。
語法
void Wire3DCGB_EraseLeftGuard24Fast();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
以保留記憶體庫選擇的 ASM 清空暫存區最左側 24 欄。不標記 dirty 範圍;使用稀疏傳輸的呼叫端須將清除的圖塊納入傳輸。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// A cleared 24-pixel strip and a palette-index-2 border have distinct purposes.
#include "wire_cgb_example.h"
void main() {
u8 y;
wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
for(y=0;y<96;y++) Wire3DCGB_DrawLine2D(0,y,31,y);
Wire3DCGB_EraseLeftGuard24Fast();
// With this example's palette, color index 2 is blue rather than white.
Wire3DCGB_DrawWhiteBorderFast();
Wire3DCGB_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
左側 24 欄被清空,留下紅色直條;色彩索引 2 的外框為藍色。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_guard.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_guard.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:146
kitaqgb/lib/wire3d_cgb.c:9200
void Wire3DCGB_EraseLeftGuard24Fast()
{
w3dcgb_erase_left_guard24_asm();
}Wire3DCGB_EraseModelFaces
擦除投影後朝前模型面內的暫存像素。
語法
void Wire3DCGB_EraseModelFaces(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz, w3dcgb_i16 scale_q8);參數
model包含頂點、邊、面陣列及數量的模型;呼叫期間須保持各表可讀。
x點或物件原點的世界座標 X 分量。
y點或物件原點的世界座標 Y 分量。
z點或物件原點的世界座標 Z 分量。
rx繞 X 軸旋轉;十六步為一整圈。
ry繞 Y 軸旋轉;十六步為一整圈。
rz繞 Z 軸旋轉;十六步為一整圈。
scale_q8倍率,以 256 表示一倍;非正值也視為一倍。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
對含頂點與面的隱線模型,轉換最多 24 個頂點,並擦除最多 16 個面中朝前的三角形。非正倍率表示一倍;此路徑即使為一倍仍執行乘法,且零角度時仍執行三個旋轉輔助函式。拒絕無效或未通過深度檢查的面。替換共用投影快取,並使用一般 C 暫存區清除器,因此呼叫端或配置過程須提供正確的 WRAM 映射。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Projected model faces erase a square opening; redraw its outline in green.
#include "wire_cgb_example.h"
#include "wire_cgb_plane.h"
void main() {
u8 y;u8 bank;
wire_results_clear();wire_plane_setup();Wire3DCGB_Init();wire_colors();Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
for(y=8;y<=88;y++) Wire3DCGB_DrawLine2D(24,y,104,y);
bank=sample_svbk;sample_svbk=2;
Wire3DCGB_EraseModelFaces(&plane,0,0,64,0,0,0,256);
sample_svbk=bank;
Wire3DCGB_DrawModelColor(&plane,0,0,64,0,0,0,3);
result[0]=Wire3DCGB_GetLineColor();
Wire3DCGB_EndFrame();result[7]=0xA55A;
while(1) {}
}預期結果
投影後的面會擦除填滿區域,可看出保留與清除的部分。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_faces.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_faces.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:132
kitaqgb/lib/wire3d_cgb.c:9033
void Wire3DCGB_EraseModelFaces(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz, w3dcgb_i16 scale_q8)
{
w3dcgb_u8 i;
w3dcgb_u8 count;
w3dcgb_u8 face_count;
if (model == 0) return;
if (model->vertices == 0) return;
if (model->faces == 0) return;
if ((model->flags & WIRE3DCGB_MODEL_HIDDEN_LINES) == 0) return;
if (scale_q8 <= 0) scale_q8 = 256;
count = model->vertex_count;
if (count > WIRE3DCGB_MODEL_VERTEX_LIMIT) count = WIRE3DCGB_MODEL_VERTEX_LIMIT;
i = 0;
while (i < count)
{
const Wire3DCGB_Vec3* v;
w3dcgb_i16 vx;
w3dcgb_i16 vy;
w3dcgb_i16 vz;
w3dcgb_u8 sx;
w3dcgb_u8 sy;
v = &model->vertices[(__safe_index w3dcgb_u8)i];
vx = (w3dcgb_i16)((v->x * scale_q8) >> 8);
vy = (w3dcgb_i16)((v->y * scale_q8) >> 8);
vz = (w3dcgb_i16)((v->z * scale_q8) >> 8);
w3dcgb_rotate_y(&vx, &vz, (w3dcgb_i8)ry);
w3dcgb_rotate_x(&vy, &vz, (w3dcgb_i8)rx);
w3dcgb_rotate_z(&vx, &vy, (w3dcgb_i8)rz);
vx = (w3dcgb_i16)(vx + x);
vy = (w3dcgb_i16)(vy + y);
vz = (w3dcgb_i16)(vz + z);
if (w3dcgb_project_world(vx, vy, vz, &sx, &sy))
{
w3dcgb_screen_x[(__safe_index w3dcgb_u8)i] = sx;
w3dcgb_screen_y[(__safe_index w3dcgb_u8)i] = sy;
w3dcgb_screen_visible[(__safe_index w3dcgb_u8)i] = 1;
}
else
{
w3dcgb_screen_visible[(__safe_index w3dcgb_u8)i] = 0;
}
i = (w3dcgb_u8)(i + 1);
}
face_count = model->face_count;
if (face_count > WIRE3DCGB_MODEL_FACE_LIMIT) face_count = WIRE3DCGB_MODEL_FACE_LIMIT;
w3dcgb_build_face_visibility(model, count, face_count);
i = 0;
while (i < face_count)
{
const Wire3DCGB_Face* f;
f = &model->faces[(__safe_index w3dcgb_u8)i];
if (w3dcgb_face_visible[(__safe_index w3dcgb_u8)i] &&
w3dcgb_screen_visible[(__safe_index w3dcgb_u8)f->a] &&
w3dcgb_screen_visible[(__safe_index w3dcgb_u8)f->b] &&
w3dcgb_screen_visible[(__safe_index w3dcgb_u8)f->c])
{
w3dcgb_clear_triangle(
w3dcgb_screen_x[(__safe_index w3dcgb_u8)f->a],
w3dcgb_screen_y[(__safe_index w3dcgb_u8)f->a],
w3dcgb_screen_x[(__safe_index w3dcgb_u8)f->b],
w3dcgb_screen_y[(__safe_index w3dcgb_u8)f->b],
w3dcgb_screen_x[(__safe_index w3dcgb_u8)f->c],
w3dcgb_screen_y[(__safe_index w3dcgb_u8)f->c]);
}
i = (w3dcgb_u8)(i + 1);
}
}Wire3DCGB_ErasePackedSilhouette2D
從一般暫存區的兩個色彩平面擦除封裝剪影。
語法
void Wire3DCGB_ErasePackedSilhouette2D(const w3dcgb_u8* profile, w3dcgb_u8 count, w3dcgb_i8 y0, w3dcgb_u8 x, w3dcgb_u8 y);參數
profile每列一位元組的剪影陣列;0xFF 略過該列。
count提供的陣列項目數;處理上限請參閱各操作的說明。
y0從中心 Y 到剪影第一列的有號偏移。
x中心 X 座標,以視埠像素為單位。
y中心 Y 座標,以視埠像素為單位。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
從兩個暫存位元平面擦除最多 29 列封裝剪影。格式、位置、兩像素保護範圍及裁切與 MarkPackedSilhouette2D 相同;null 會被忽略。ASM 跨度寫入器會選取 WRAM 記憶體庫 2,完成後恢復原先選擇,但不標記 dirty 圖塊。稀疏模式下,呼叫端須確保擦除的圖塊包含於上傳範圍。此 API 用於 128×96 暫存區。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Colored panels expose triangle, span, rectangle and packed-silhouette erasure.
#include "wire_cgb_example.h"
__prg_rom u8 silhouette[5]={0x73,0x74,0xFF,0x75,0x73};
void main() {
u8 y;
u8 bank;
wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
for(y=8;y<=40;y++) Wire3DCGB_DrawLine2DColor(8,y,40,y,1);
for(y=8;y<=40;y++) Wire3DCGB_DrawLine2DColor(48,y,80,y,2);
for(y=64;y<=72;y++) Wire3DCGB_DrawLine2DColor(88,y,120,y,3);
// The C triangle/rectangle clearers access the stage through the current
// WRAM window. Select bank 2 around them and restore the caller's bank.
bank=sample_svbk; sample_svbk=2;
Wire3DCGB_EraseTriangle2D(12,12,36,12,12,36);
Wire3DCGB_EraseSpan2D(36,40,24);
Wire3DCGB_EraseRect2D(56,16,72,32);
Wire3DCGB_ErasePackedSilhouette2D(silhouette,5,-2,104,68);
sample_svbk=bank;
Wire3DCGB_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
三角形、水平跨度、矩形與封裝的剪影在填滿紅、藍、綠色的面板中挖出黑色空洞。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_erase.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_erase.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:153
kitaqgb/lib/wire3d_cgb.c:2038
void Wire3DCGB_ErasePackedSilhouette2D(const w3dcgb_u8* profile, w3dcgb_u8 count,
w3dcgb_i8 y0, w3dcgb_u8 x, w3dcgb_u8 y)
{
w3dcgb_u8 i;
w3dcgb_u8 packed;
w3dcgb_u8 half_width;
w3dcgb_i16 center;
w3dcgb_i16 left;
w3dcgb_i16 right;
w3dcgb_i16 row;
if (profile == 0) return;
if (count > 29) count = 29;
i = 0;
while (i < count)
{
packed = profile[(__safe_index w3dcgb_u8)i];
if (packed != 0xFF)
{
row = (w3dcgb_i16)((w3dcgb_i16)y + (w3dcgb_i16)y0 + (w3dcgb_i16)i);
if ((row >= 0) && (row < WIRE3DCGB_SCREEN_H))
{
center = (w3dcgb_i16)((w3dcgb_i16)x + (w3dcgb_i16)(packed >> 4) - 7);
half_width = (w3dcgb_u8)(packed & 15);
left = (w3dcgb_i16)(center - (w3dcgb_i16)half_width - 2);
right = (w3dcgb_i16)(center + (w3dcgb_i16)half_width + 2);
if ((right >= 0) && (left < WIRE3DCGB_SCREEN_W))
{
if (left < 0) left = 0;
if (right >= WIRE3DCGB_SCREEN_W) right = WIRE3DCGB_SCREEN_W - 1;
w3dcgb_mask_span_y = (w3dcgb_u8)row;
w3dcgb_mask_span_min_x = (w3dcgb_u8)left;
w3dcgb_mask_span_max_x = (w3dcgb_u8)right;
w3dcgb_stage_clear_span_asm();
}
}
}
i = (w3dcgb_u8)(i + 1);
}
}Wire3DCGB_EraseRect2D
從一般暫存區擦除矩形。
語法
void Wire3DCGB_EraseRect2D(w3dcgb_u8 x0, w3dcgb_u8 y0, w3dcgb_u8 x1, w3dcgb_u8 y1);參數
x0較小的 X 端點,以視埠像素為單位;排序與裁切依此操作的注意事項。
y0較小的 Y 端點,以視埠像素為單位;排序與裁切依此操作的注意事項。
x1較大的 X 端點,以視埠像素為單位;排序與裁切依此操作的注意事項。
y1較大的 Y 端點,以視埠像素為單位;排序與裁切依此操作的注意事項。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
排序矩形端點並裁切至 128×96。涵蓋完整高度、寬 16 或 24 像素的左側直條,使用保留記憶體庫選擇的 ASM 清除與 dirty 標記。其他矩形使用 C 逐列清除,須由呼叫端提供正確的暫存區 WRAM 映射。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Colored panels expose triangle, span, rectangle and packed-silhouette erasure.
#include "wire_cgb_example.h"
__prg_rom u8 silhouette[5]={0x73,0x74,0xFF,0x75,0x73};
void main() {
u8 y;
u8 bank;
wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
for(y=8;y<=40;y++) Wire3DCGB_DrawLine2DColor(8,y,40,y,1);
for(y=8;y<=40;y++) Wire3DCGB_DrawLine2DColor(48,y,80,y,2);
for(y=64;y<=72;y++) Wire3DCGB_DrawLine2DColor(88,y,120,y,3);
// The C triangle/rectangle clearers access the stage through the current
// WRAM window. Select bank 2 around them and restore the caller's bank.
bank=sample_svbk; sample_svbk=2;
Wire3DCGB_EraseTriangle2D(12,12,36,12,12,36);
Wire3DCGB_EraseSpan2D(36,40,24);
Wire3DCGB_EraseRect2D(56,16,72,32);
Wire3DCGB_ErasePackedSilhouette2D(silhouette,5,-2,104,68);
sample_svbk=bank;
Wire3DCGB_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
三角形、水平跨度、矩形與封裝的剪影在填滿紅、藍、綠色的面板中挖出黑色空洞。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_erase.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_erase.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:145
kitaqgb/lib/wire3d_cgb.c:9146
void Wire3DCGB_EraseRect2D(w3dcgb_u8 x0, w3dcgb_u8 y0, w3dcgb_u8 x1, w3dcgb_u8 y1)
{
w3dcgb_u8 t;
w3dcgb_u8 y;
if (x0 > x1)
{
t = x0;
x0 = x1;
x1 = t;
}
if (y0 > y1)
{
t = y0;
y0 = y1;
y1 = t;
}
if (x0 >= WIRE3DCGB_SCREEN_W) return;
if (y0 >= WIRE3DCGB_SCREEN_H) return;
if (x1 >= WIRE3DCGB_SCREEN_W) x1 = (w3dcgb_u8)(WIRE3DCGB_SCREEN_W - 1);
if (y1 >= WIRE3DCGB_SCREEN_H) y1 = (w3dcgb_u8)(WIRE3DCGB_SCREEN_H - 1);
if ((x0 == 0) &&
(x1 == 15) &&
(y0 == 0) &&
(y1 == (w3dcgb_u8)(WIRE3DCGB_SCREEN_H - 1)))
{
w3dcgb_erase_left_guard16_asm();
w3dcgb_mark_dirty_rect(0, 0, 15, (w3dcgb_u8)(WIRE3DCGB_SCREEN_H - 1));
return;
}
if ((x0 == 0) &&
(x1 == 23) &&
(y0 == 0) &&
(y1 == (w3dcgb_u8)(WIRE3DCGB_SCREEN_H - 1)))
{
w3dcgb_erase_left_guard24_asm();
w3dcgb_mark_dirty_rect(0, 0, 23, (w3dcgb_u8)(WIRE3DCGB_SCREEN_H - 1));
return;
}
y = y0;
while (y <= y1)
{
w3dcgb_stage_clear_span(y, x0, x1);
if (y == y1) break;
y = (w3dcgb_u8)(y + 1);
}
}Wire3DCGB_EraseSpan2D
儲存並恢復 WRAM 記憶體庫選擇,同時擦除水平跨度。
語法
void Wire3DCGB_EraseSpan2D(w3dcgb_u8 y, w3dcgb_u8 x0, w3dcgb_u8 x1);參數
y要擦除之列的像素 Y 座標。
x0較小的 X 端點,以視埠像素為單位;排序與裁切依此操作的注意事項。
x1較大的 X 端點,以視埠像素為單位;排序與裁切依此操作的注意事項。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
排序 X 端點,拒絕畫面外的列或左端,並將右端限制為 127。將範圍標為 dirty,再使用 ASM 跨度清除器,先選取 WRAM 記憶體庫 2,完成後恢復原先的記憶體庫選擇。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Colored panels expose triangle, span, rectangle and packed-silhouette erasure.
#include "wire_cgb_example.h"
__prg_rom u8 silhouette[5]={0x73,0x74,0xFF,0x75,0x73};
void main() {
u8 y;
u8 bank;
wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
for(y=8;y<=40;y++) Wire3DCGB_DrawLine2DColor(8,y,40,y,1);
for(y=8;y<=40;y++) Wire3DCGB_DrawLine2DColor(48,y,80,y,2);
for(y=64;y<=72;y++) Wire3DCGB_DrawLine2DColor(88,y,120,y,3);
// The C triangle/rectangle clearers access the stage through the current
// WRAM window. Select bank 2 around them and restore the caller's bank.
bank=sample_svbk; sample_svbk=2;
Wire3DCGB_EraseTriangle2D(12,12,36,12,12,36);
Wire3DCGB_EraseSpan2D(36,40,24);
Wire3DCGB_EraseRect2D(56,16,72,32);
Wire3DCGB_ErasePackedSilhouette2D(silhouette,5,-2,104,68);
sample_svbk=bank;
Wire3DCGB_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
三角形、水平跨度、矩形與封裝的剪影在填滿紅、藍、綠色的面板中挖出黑色空洞。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_erase.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_erase.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:134
kitaqgb/lib/wire3d_cgb.c:9123
void Wire3DCGB_EraseSpan2D(w3dcgb_u8 y, w3dcgb_u8 x0, w3dcgb_u8 x1)
{
w3dcgb_u8 tx;
if (x0 > x1)
{
tx = x0;
x0 = x1;
x1 = tx;
}
if ((y >= WIRE3DCGB_SCREEN_H) || (x0 >= WIRE3DCGB_SCREEN_W)) return;
if (x1 >= WIRE3DCGB_SCREEN_W) x1 = WIRE3DCGB_SCREEN_W - 1;
w3dcgb_mark_dirty_rect(x0, y, x1, y);
w3dcgb_mask_span_y = y;
w3dcgb_mask_span_min_x = x0;
w3dcgb_mask_span_max_x = x1;
w3dcgb_stage_clear_span_asm();
}Wire3DCGB_EraseTriangle2D
從一般暫存區的兩個色彩位元平面擦除三角形。
語法
void Wire3DCGB_EraseTriangle2D(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by, w3dcgb_u8 cx, w3dcgb_u8 cy);參數
ax頂點 A 的 X 座標,以視埠像素為單位。
ay頂點 A 的 Y 座標,以視埠像素為單位。
bx頂點 B 的 X 座標,以視埠像素為單位。
by頂點 B 的 Y 座標,以視埠像素為單位。
cx頂點 C 的 X 座標,以視埠像素為單位。
cy頂點 C 的 Y 座標,以視埠像素為單位。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
透過一般 C 暫存區清除器擦除三角形。裁切後的跨度會將觸及的圖塊標為 dirty;呼叫端或配置過程須提供暫存區的 WRAM 映射。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Colored panels expose triangle, span, rectangle and packed-silhouette erasure.
#include "wire_cgb_example.h"
__prg_rom u8 silhouette[5]={0x73,0x74,0xFF,0x75,0x73};
void main() {
u8 y;
u8 bank;
wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
for(y=8;y<=40;y++) Wire3DCGB_DrawLine2DColor(8,y,40,y,1);
for(y=8;y<=40;y++) Wire3DCGB_DrawLine2DColor(48,y,80,y,2);
for(y=64;y<=72;y++) Wire3DCGB_DrawLine2DColor(88,y,120,y,3);
// The C triangle/rectangle clearers access the stage through the current
// WRAM window. Select bank 2 around them and restore the caller's bank.
bank=sample_svbk; sample_svbk=2;
Wire3DCGB_EraseTriangle2D(12,12,36,12,12,36);
Wire3DCGB_EraseSpan2D(36,40,24);
Wire3DCGB_EraseRect2D(56,16,72,32);
Wire3DCGB_ErasePackedSilhouette2D(silhouette,5,-2,104,68);
sample_svbk=bank;
Wire3DCGB_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
三角形、水平跨度、矩形與封裝的剪影在填滿紅、藍、綠色的面板中挖出黑色空洞。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_erase.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_erase.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:133
kitaqgb/lib/wire3d_cgb.c:9113
void Wire3DCGB_EraseTriangle2D(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by, w3dcgb_u8 cx, w3dcgb_u8 cy)
{
w3dcgb_clear_triangle(ax, ay, bx, by, cx, cy);
}Wire3DCGB_FastMapBegin
清空 16×12 FastMap 視埠的圖塊編號與屬性。
語法
void Wire3DCGB_FastMapBegin();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
將 FastMap 標為已準備,並清空 16×12 視埠內的圖塊編號與屬性。即使 flush 每列複製 32 欄,影子緩衝區的第 16..31 欄仍保留。須具備完整執行階段與穩定的 FastMap WRAM 映射;此操作不初始化硬體,也不上傳地圖。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// FastMap uses precomputed outline tiles rather than a pixel stage upload.
#include "wire_cgb_example.h"
void main() {
u8 bank;
wire_results_clear(); Wire3DCGB_InitFastMapLite(); wire_colors();
bank=sample_svbk;sample_svbk=2;
Wire3DCGB_FastMapBegin();
Wire3DCGB_FastMapCell(1,1,1,15); // This first red square must disappear.
Wire3DCGB_FastMapFlush();
Wire3DCGB_FastMapBeginTilesOnly();
Wire3DCGB_FastMapCell(13,1,1,1);
Wire3DCGB_FastMapCell(13,1,1,4); // Same-color top and left sides combine.
Wire3DCGB_FastMapRect(4,2,9,7,2,15);
Wire3DCGB_FastMapCell(2,9,3,15);
Wire3DCGB_FastMapFlushTilesOnly();
sample_svbk=bank;result[7]=0xA55A;
while(1) {}
}預期結果
紅色轉角、大型藍色矩形與一個圖塊大小的綠色框示範外框格。最初左上角的紅色格會消失,而僅更新圖塊的操作會保留屬性。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_fastmap.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_fastmap.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:160
kitaqgb/lib/wire3d_cgb.c:10137
void Wire3DCGB_FastMapBegin()
{
w3dcgb_fast_map_ready = 1;
w3dcgb_fast_map_clear_rect(0, 0, 16, 12);
}Wire3DCGB_FastMapBeginTilesOnly
僅清空 16×12 FastMap 視埠的圖塊編號。
語法
void Wire3DCGB_FastMapBeginTilesOnly();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
將 FastMap 標為已準備,只清空 16×12 視埠的圖塊編號。保留屬性與第 16..31 欄。須使用完整執行階段及預期的 WRAM 映射;硬體初始化與上傳須另行處理。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// FastMap uses precomputed outline tiles rather than a pixel stage upload.
#include "wire_cgb_example.h"
void main() {
u8 bank;
wire_results_clear(); Wire3DCGB_InitFastMapLite(); wire_colors();
bank=sample_svbk;sample_svbk=2;
Wire3DCGB_FastMapBegin();
Wire3DCGB_FastMapCell(1,1,1,15); // This first red square must disappear.
Wire3DCGB_FastMapFlush();
Wire3DCGB_FastMapBeginTilesOnly();
Wire3DCGB_FastMapCell(13,1,1,1);
Wire3DCGB_FastMapCell(13,1,1,4); // Same-color top and left sides combine.
Wire3DCGB_FastMapRect(4,2,9,7,2,15);
Wire3DCGB_FastMapCell(2,9,3,15);
Wire3DCGB_FastMapFlushTilesOnly();
sample_svbk=bank;result[7]=0xA55A;
while(1) {}
}預期結果
紅色轉角、大型藍色矩形與一個圖塊大小的綠色框示範外框格。最初左上角的紅色格會消失,而僅更新圖塊的操作會保留屬性。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_fastmap.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_fastmap.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:161
kitaqgb/lib/wire3d_cgb.c:10146
void Wire3DCGB_FastMapBeginTilesOnly()
{
w3dcgb_fast_map_ready = 1;
w3dcgb_fm_x0 = 0;
w3dcgb_fm_y0 = 0;
w3dcgb_fm_count_x = 16;
w3dcgb_fm_count_y = 12;
w3dcgb_fast_map_clear_rect_asm();
}Wire3DCGB_FastMapCell
將所選的上、下、左、右外框邊加入一個地圖格。
語法
void Wire3DCGB_FastMapCell(w3dcgb_u8 tx, w3dcgb_u8 ty, w3dcgb_u8 color, w3dcgb_u8 mask);參數
tx以圖塊座標表示的 X 位置。
ty以圖塊座標表示的 Y 位置。
color繪圖色彩索引;範例調色盤使用 1=紅、2=藍、3=綠。
mask格子邊遮罩:1=上、2=下、4=左、8=右。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
在格子中加入外框邊:位元 1/2/4/8 表示上/下/左/右。同色遮罩合併;不同色彩則取代舊遮罩。忽略零遮罩,色彩零表示 MAIN,大於 3 則限制為 3。目標為 16×12 影子緩衝區,須維持穩定的 WRAM 映射,並使用完整執行階段。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// FastMap uses precomputed outline tiles rather than a pixel stage upload.
#include "wire_cgb_example.h"
void main() {
u8 bank;
wire_results_clear(); Wire3DCGB_InitFastMapLite(); wire_colors();
bank=sample_svbk;sample_svbk=2;
Wire3DCGB_FastMapBegin();
Wire3DCGB_FastMapCell(1,1,1,15); // This first red square must disappear.
Wire3DCGB_FastMapFlush();
Wire3DCGB_FastMapBeginTilesOnly();
Wire3DCGB_FastMapCell(13,1,1,1);
Wire3DCGB_FastMapCell(13,1,1,4); // Same-color top and left sides combine.
Wire3DCGB_FastMapRect(4,2,9,7,2,15);
Wire3DCGB_FastMapCell(2,9,3,15);
Wire3DCGB_FastMapFlushTilesOnly();
sample_svbk=bank;result[7]=0xA55A;
while(1) {}
}預期結果
紅色轉角、大型藍色矩形與一個圖塊大小的綠色框示範外框格。最初左上角的紅色格會消失,而僅更新圖塊的操作會保留屬性。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_fastmap.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_fastmap.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:162
kitaqgb/lib/wire3d_cgb.c:10160
void Wire3DCGB_FastMapCell(w3dcgb_u8 tx, w3dcgb_u8 ty, w3dcgb_u8 color, w3dcgb_u8 mask)
{
w3dcgb_fast_map_or_cell((w3dcgb_i16)tx, (w3dcgb_i16)ty, color, mask);
}Wire3DCGB_FastMapFlush
將影子緩衝區前十二個完整列的圖塊編號與屬性上傳至 VRAM。
語法
void Wire3DCGB_FastMapFlush();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
LCD 啟用時等待新的 VBlank,再將地圖前十二個完整列的圖塊編號與屬性上傳至地圖 9800。LCD 關閉時立即執行。須具備完整執行階段、穩定的 WRAM 映射,以及足以完成兩次立即 GDMA 傳輸的安全時段。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// FastMap uses precomputed outline tiles rather than a pixel stage upload.
#include "wire_cgb_example.h"
void main() {
u8 bank;
wire_results_clear(); Wire3DCGB_InitFastMapLite(); wire_colors();
bank=sample_svbk;sample_svbk=2;
Wire3DCGB_FastMapBegin();
Wire3DCGB_FastMapCell(1,1,1,15); // This first red square must disappear.
Wire3DCGB_FastMapFlush();
Wire3DCGB_FastMapBeginTilesOnly();
Wire3DCGB_FastMapCell(13,1,1,1);
Wire3DCGB_FastMapCell(13,1,1,4); // Same-color top and left sides combine.
Wire3DCGB_FastMapRect(4,2,9,7,2,15);
Wire3DCGB_FastMapCell(2,9,3,15);
Wire3DCGB_FastMapFlushTilesOnly();
sample_svbk=bank;result[7]=0xA55A;
while(1) {}
}預期結果
紅色轉角、大型藍色矩形與一個圖塊大小的綠色框示範外框格。最初左上角的紅色格會消失,而僅更新圖塊的操作會保留屬性。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_fastmap.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_fastmap.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:164
kitaqgb/lib/wire3d_cgb.c:10208
void Wire3DCGB_FastMapFlush()
{
w3dcgb_wait_vblank_start();
w3dcgb_fast_map_flush_gdma_asm();
}Wire3DCGB_FastMapFlushTilesOnly
僅上傳影子地圖前十二個完整列的圖塊編號。
語法
void Wire3DCGB_FastMapFlushTilesOnly();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
LCD 啟用時等待新的 VBlank,只將前十二個完整列的圖塊編號上傳至地圖 9800。保留屬性。須使用完整執行階段、穩定的 WRAM 映射及安全的 GDMA 時段。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// FastMap uses precomputed outline tiles rather than a pixel stage upload.
#include "wire_cgb_example.h"
void main() {
u8 bank;
wire_results_clear(); Wire3DCGB_InitFastMapLite(); wire_colors();
bank=sample_svbk;sample_svbk=2;
Wire3DCGB_FastMapBegin();
Wire3DCGB_FastMapCell(1,1,1,15); // This first red square must disappear.
Wire3DCGB_FastMapFlush();
Wire3DCGB_FastMapBeginTilesOnly();
Wire3DCGB_FastMapCell(13,1,1,1);
Wire3DCGB_FastMapCell(13,1,1,4); // Same-color top and left sides combine.
Wire3DCGB_FastMapRect(4,2,9,7,2,15);
Wire3DCGB_FastMapCell(2,9,3,15);
Wire3DCGB_FastMapFlushTilesOnly();
sample_svbk=bank;result[7]=0xA55A;
while(1) {}
}預期結果
紅色轉角、大型藍色矩形與一個圖塊大小的綠色框示範外框格。最初左上角的紅色格會消失,而僅更新圖塊的操作會保留屬性。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_fastmap.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_fastmap.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:165
kitaqgb/lib/wire3d_cgb.c:10217
void Wire3DCGB_FastMapFlushTilesOnly()
{
w3dcgb_wait_vblank_start();
w3dcgb_fast_map_flush_tiles_gdma_asm();
}Wire3DCGB_FastMapRect
沿圖塊座標矩形放置所選外框邊。
語法
void Wire3DCGB_FastMapRect(w3dcgb_u8 tx0, w3dcgb_u8 ty0, w3dcgb_u8 tx1, w3dcgb_u8 ty1, w3dcgb_u8 color, w3dcgb_u8 sides);參數
tx0以圖塊座標表示的 X 位置。
ty0以圖塊座標表示的 Y 位置。
tx1以圖塊座標表示的 X 位置。
ty1以圖塊座標表示的 Y 位置。
color繪圖色彩索引;範例調色盤使用 1=紅、2=藍、3=綠。
sides矩形邊遮罩:1=上、2=下、4=左、8=右。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
排序位元組圖塊座標並裁切至 16×12,再取代所選邊框格。邊位元 1/2/4/8 表示上/下/左/右。色彩零表示 MAIN;大於 3 的值限制為 3。保留屬性與內部格。若要有不同的角,至少須使用兩列與兩欄;重合的角會依序覆寫。須使用完整執行階段與穩定的 WRAM 映射。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// FastMap uses precomputed outline tiles rather than a pixel stage upload.
#include "wire_cgb_example.h"
void main() {
u8 bank;
wire_results_clear(); Wire3DCGB_InitFastMapLite(); wire_colors();
bank=sample_svbk;sample_svbk=2;
Wire3DCGB_FastMapBegin();
Wire3DCGB_FastMapCell(1,1,1,15); // This first red square must disappear.
Wire3DCGB_FastMapFlush();
Wire3DCGB_FastMapBeginTilesOnly();
Wire3DCGB_FastMapCell(13,1,1,1);
Wire3DCGB_FastMapCell(13,1,1,4); // Same-color top and left sides combine.
Wire3DCGB_FastMapRect(4,2,9,7,2,15);
Wire3DCGB_FastMapCell(2,9,3,15);
Wire3DCGB_FastMapFlushTilesOnly();
sample_svbk=bank;result[7]=0xA55A;
while(1) {}
}預期結果
紅色轉角、大型藍色矩形與一個圖塊大小的綠色框示範外框格。最初左上角的紅色格會消失,而僅更新圖塊的操作會保留屬性。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_fastmap.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_fastmap.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:163
kitaqgb/lib/wire3d_cgb.c:10170
void Wire3DCGB_FastMapRect(w3dcgb_u8 tx0, w3dcgb_u8 ty0, w3dcgb_u8 tx1, w3dcgb_u8 ty1, w3dcgb_u8 color, w3dcgb_u8 sides)
{
w3dcgb_u8 t;
if (tx0 > tx1)
{
t = tx0;
tx0 = tx1;
tx1 = t;
}
if (ty0 > ty1)
{
t = ty0;
ty0 = ty1;
ty1 = t;
}
if (tx0 >= 16) return;
if (ty0 >= 12) return;
if (tx1 >= 16) tx1 = 15;
if (ty1 >= 12) ty1 = 11;
if (color == 0) color = WIRE3DCGB_COLOR_MAIN;
if (color > 3) color = 3;
w3dcgb_fm_x0 = tx0;
w3dcgb_fm_y0 = ty0;
w3dcgb_fm_x1 = tx1;
w3dcgb_fm_y1 = ty1;
w3dcgb_fm_count_x = (w3dcgb_u8)(tx1 - tx0 + 1);
w3dcgb_fm_count_y = (w3dcgb_u8)(ty1 - ty0 + 1);
w3dcgb_fm_tile_base = (w3dcgb_u8)(W3DCGB_FAST_TILE_BASE + ((color - 1) << 4));
w3dcgb_fm_sides = (w3dcgb_u8)(sides & 15);
w3dcgb_fast_map_rect_asm();
}Wire3DCGB_GetFullScreenOverflow
回報全畫面繪製中的無效座標或圖塊配置耗盡。
語法
w3dcgb_u8 Wire3DCGB_GetFullScreenOverflow();回傳值
無錯誤時為零;配置耗盡或座標無效後為一。
使用條件與限制
傳回全畫面影格錯誤旗標:快速線段路徑在圖塊配置耗盡或座標無效時設定。一旦設定,後續快速路徑的像素繪製會受抑制,直到 BeginFrame 重設。這不是一般硬體狀態旗標;讀取函式需要完整執行階段。
全畫面配置先於遮蔽與溢位對像素寫入的抑制執行。已配置圖塊可能仍為黑色,發生錯誤後繼續繪製仍可能增加圖塊數。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// One point per tile exposes the 127-tile limit without relying on text alone.
#include "wire_cgb_example.h"
void main() {
u8 i;
wire_results_clear();
Wire3DCGB_InitFullScreen(); wire_colors();
Wire3DCGB_BeginFrame(); Wire3DCGB_SetLineColor(3);
for(i=0;i<128;i++) Wire3DCGB_DrawPoint2D((i%20)*8+4,(i/20)*8+4);
result[0]=Wire3DCGB_GetFullScreenTileCount();
result[1]=Wire3DCGB_GetFullScreenOverflow();
Wire3DCGB_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
127 個紅點各占不同圖塊。嘗試第 128 次配置時,計數維持 127,overflow 設為一。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_capacity.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_capacity.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:194
kitaqgb/lib/wire3d_cgb.c:9965
w3dcgb_u8 Wire3DCGB_GetFullScreenOverflow()
{
return w3dcgb_full_overflow;
}Wire3DCGB_GetFullScreenTileCount
傳回目前影格中已配置的全畫面圖塊數。
語法
w3dcgb_u8 Wire3DCGB_GetFullScreenTileCount();回傳值
已配置圖塊數,範圍 0..127。
使用條件與限制
傳回目前全畫面的配置數,最多 127。這不是位元組數,也不是可見或非零像素數。僅限完整執行階段。
全畫面配置先於遮蔽與溢位對像素寫入的抑制執行。已配置圖塊可能仍為黑色,發生錯誤後繼續繪製仍可能增加圖塊數。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// One point per tile exposes the 127-tile limit without relying on text alone.
#include "wire_cgb_example.h"
void main() {
u8 i;
wire_results_clear();
Wire3DCGB_InitFullScreen(); wire_colors();
Wire3DCGB_BeginFrame(); Wire3DCGB_SetLineColor(3);
for(i=0;i<128;i++) Wire3DCGB_DrawPoint2D((i%20)*8+4,(i/20)*8+4);
result[0]=Wire3DCGB_GetFullScreenTileCount();
result[1]=Wire3DCGB_GetFullScreenOverflow();
Wire3DCGB_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
127 個紅點各占不同圖塊。嘗試第 128 次配置時,計數維持 127,overflow 設為一。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_capacity.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_capacity.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:193
kitaqgb/lib/wire3d_cgb.c:9956
w3dcgb_u8 Wire3DCGB_GetFullScreenTileCount()
{
return w3dcgb_full_tile_count;
}Wire3DCGB_GetLineColor
讀取目前儲存的線色索引。
語法
w3dcgb_u8 Wire3DCGB_GetLineColor();回傳值
目前儲存的線色值。
使用條件與限制
傳回目前儲存的兩位元線色,不改變繪圖狀態。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DCGB_EnableDoubleSpeed();
Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
result[2]=(u8)(sample_key1&128);
// Palette writes are performed with the LCD off, after entering VBlank.
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0;
Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
sample_lcdc=0x81;
Wire3DCGB_SetScreenOffset(0,0);
Wire3DCGB_SetCamera(0,0,0,0,0,0);
Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
Wire3DCGB_DrawLine2D(8,8,56,8);
Wire3DCGB_DrawLine2D(56,8,56,40);
Wire3DCGB_DrawLine2D(56,40,8,40);
Wire3DCGB_DrawLine2D(8,40,8,8);
Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
Wire3DCGB_SetLineColor(3);
Wire3DCGB_DrawPoint2D(64,48);
Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
Wire3DCGB_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。紅色邊框內有藍色對角線,另有綠點與綠色水平線、藍色 L,以及右上角的綠色數字 0。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:120
kitaqgb/lib/wire3d_cgb.c:1147
w3dcgb_u8 Wire3DCGB_GetLineColor()
{
return w3dcgb_line_color;
}Wire3DCGB_Init
初始化 CGB 128×96 像素繪圖器。
語法
void Wire3DCGB_Init();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
初始化 CGB 專用的 128×96 繪圖器:啟用倍速、於 VBlank 關閉 LCD、清空兩個圖塊庫、載入 HUD/產生的圖塊,並建立以欄為主序的 16×12 視埠。起始設定使用空白圖塊庫 1、零捲動、預設 BG 調色盤、色彩 2 與歸零的相機。重設佇列,並清空記憶體庫 2 的暫存區。繪製前須呼叫 BeginFrame 初始化遮蔽狀態。初始化會全面改寫 LCD、圖塊與地圖狀態。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
CGB稀疏顯示啟動時,首次使用各目標記憶體區(前兩幀)會更新整個視窗,清除初始化圖塊。量測包含啟動成本。一般DrawLine2D不登記稀疏範圍,請使用DrawLineClipped2D或明確呼叫MarkDirtyRect2D。
使用範例
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DCGB_EnableDoubleSpeed();
Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
result[2]=(u8)(sample_key1&128);
// Palette writes are performed with the LCD off, after entering VBlank.
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0;
Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
sample_lcdc=0x81;
Wire3DCGB_SetScreenOffset(0,0);
Wire3DCGB_SetCamera(0,0,0,0,0,0);
Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
Wire3DCGB_DrawLine2D(8,8,56,8);
Wire3DCGB_DrawLine2D(56,8,56,40);
Wire3DCGB_DrawLine2D(56,40,8,40);
Wire3DCGB_DrawLine2D(8,40,8,8);
Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
Wire3DCGB_SetLineColor(3);
Wire3DCGB_DrawPoint2D(64,48);
Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
Wire3DCGB_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。紅色邊框內有藍色對角線,另有綠點與綠色水平線、藍色 L,以及右上角的綠色數字 0。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:113
kitaqgb/lib/wire3d_cgb.c:7994
void Wire3DCGB_Init()
{
w3dcgb_u8 row;
w3dcgb_u8 col;
w3dcgb_u8 tid;
w3dcgb_u8 tile_index;
w3dcgb_u16 off;
w3dcgb_full_mode = 0;
w3dcgb_atomic_maps = 0;
Wire3DCGB_EnableDoubleSpeed();
w3dcgb_wait_vblank_start();
w3dcgb_reg_lcdc = 0;
w3dcgb_clear_vram_asm();
w3dcgb_load_hud_tiles();
#ifndef WIRE3DCGB_MINIMAL_RUNTIME
w3dcgb_load_fast_map_tiles();
w3dcgb_load_fast_stamp_tiles();
#endif
w3dcgb_fill_bg_map_asm();
w3dcgb_fill_attr_map_asm();
row = 0;
while (row < W3DCGB_TILE_H)
{
off = (w3dcgb_u16)((w3dcgb_u16)row << 5);
tile_index = row;
col = 0;
while (col < W3DCGB_TILE_W)
{
if (tile_index < 112) tid = (w3dcgb_u8)(0x90 + tile_index);
else tid = (w3dcgb_u8)(tile_index - 112);
w3dcgb_bg_map_9800[(w3dcgb_u16)(off + (w3dcgb_u16)col)] = tid;
tile_index = (w3dcgb_u8)(tile_index + W3DCGB_TILE_H);
col = (w3dcgb_u8)(col + 1);
}
row = (w3dcgb_u8)(row + 1);
}
w3dcgb_select_blank_render_bank_asm();
w3dcgb_reg_scx = 0;
w3dcgb_reg_scy = 0;
w3dcgb_reg_bgp = 0xB4;
Wire3DCGB_SetPaletteRGB15(
WIRE3DCGB_RGB15(0, 0, 2),
WIRE3DCGB_RGB15(10, 20, 31),
WIRE3DCGB_RGB15(31, 31, 31),
WIRE3DCGB_RGB15(31, 14, 4));
w3dcgb_line_color = WIRE3DCGB_COLOR_DEFAULT;
w3dcgb_reg_lcdc = 0x81;
w3dcgb_bgq_count = 0;
w3dcgb_dirty_count = 0;
w3dcgb_prev_dirty_count = 0;
w3dcgb_dirty_min_tile = 0xFF;
w3dcgb_dirty_max_tile = 0;
// Both back banks may contain generated fast-map/stamp tiles. Refresh
// the whole pixel viewport on their first sparse use, including empty rows.
w3dcgb_prev_dirty_min_tile = 0;
w3dcgb_prev_dirty_max_tile = (w3dcgb_u8)(WIRE3DCGB_TILE_COUNT - 1);
w3dcgb_older_dirty_min_tile = 0;
w3dcgb_older_dirty_max_tile = (w3dcgb_u8)(WIRE3DCGB_TILE_COUNT - 1);
w3dcgb_display_tile_bank = 1;
w3dcgb_pending_tile_bank = 1;
Wire3DCGB_SetCamera((w3dcgb_i16)0, (w3dcgb_i16)0, (w3dcgb_i16)0, 0, 0, 0);
w3dcgb_clear_stage_asm();
}Wire3DCGB_InitFastMapLite
以預先計算的外框圖塊初始化 FastMap 繪製。
語法
void Wire3DCGB_InitFastMapLite();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
初始化含 HUD 與 48 個預先計算之外框圖塊的 CGB 圖塊地圖繪圖器。清空圖塊 VRAM 與地圖,重設捲動、調色盤及相機,並選擇一般模式。此初始化不建立一般像素視埠的地圖配置,也不產生立方體圖樣;此模式應使用 FastMap API。清空記憶體庫 2 的暫存區,並將快速地圖準備標為待處理。須使用完整執行階段建置。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// FastMap uses precomputed outline tiles rather than a pixel stage upload.
#include "wire_cgb_example.h"
void main() {
u8 bank;
wire_results_clear(); Wire3DCGB_InitFastMapLite(); wire_colors();
bank=sample_svbk;sample_svbk=2;
Wire3DCGB_FastMapBegin();
Wire3DCGB_FastMapCell(1,1,1,15); // This first red square must disappear.
Wire3DCGB_FastMapFlush();
Wire3DCGB_FastMapBeginTilesOnly();
Wire3DCGB_FastMapCell(13,1,1,1);
Wire3DCGB_FastMapCell(13,1,1,4); // Same-color top and left sides combine.
Wire3DCGB_FastMapRect(4,2,9,7,2,15);
Wire3DCGB_FastMapCell(2,9,3,15);
Wire3DCGB_FastMapFlushTilesOnly();
sample_svbk=bank;result[7]=0xA55A;
while(1) {}
}預期結果
紅色轉角、大型藍色矩形與一個圖塊大小的綠色框示範外框格。最初左上角的紅色格會消失,而僅更新圖塊的操作會保留屬性。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_fastmap.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_fastmap.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:115
kitaqgb/lib/wire3d_cgb.c:8108
void Wire3DCGB_InitFastMapLite()
{
w3dcgb_atomic_maps = 0;
w3dcgb_full_mode = 0;
Wire3DCGB_EnableDoubleSpeed();
w3dcgb_wait_vblank_start();
w3dcgb_reg_lcdc = 0;
w3dcgb_clear_vram_asm();
w3dcgb_load_hud_tiles();
w3dcgb_load_fast_map_tiles_lite_asm();
w3dcgb_fill_bg_map_asm();
w3dcgb_fill_attr_map_asm();
w3dcgb_reg_scx = 0;
w3dcgb_reg_scy = 0;
w3dcgb_reg_bgp = 0xB4;
Wire3DCGB_SetPaletteRGB15(
WIRE3DCGB_RGB15(0, 0, 2),
WIRE3DCGB_RGB15(10, 20, 31),
WIRE3DCGB_RGB15(31, 31, 31),
WIRE3DCGB_RGB15(31, 14, 4));
w3dcgb_line_color = WIRE3DCGB_COLOR_DEFAULT;
w3dcgb_reg_lcdc = 0x81;
w3dcgb_bgq_count = 0;
w3dcgb_dirty_count = 0;
w3dcgb_prev_dirty_count = 0;
w3dcgb_dirty_min_tile = 0xFF;
w3dcgb_dirty_max_tile = 0;
w3dcgb_prev_dirty_min_tile = 0xFF;
w3dcgb_prev_dirty_max_tile = 0;
w3dcgb_fast_map_ready = 0;
w3dcgb_display_tile_bank = 0;
w3dcgb_pending_tile_bank = 0;
Wire3DCGB_SetCamera((w3dcgb_i16)0, (w3dcgb_i16)0, (w3dcgb_i16)0, 0, 0, 0);
w3dcgb_clear_stage_asm();
}Wire3DCGB_InitFullScreen
初始化在繪製像素時配置圖塊的 160×144 繪圖器。
語法
void Wire3DCGB_InitFullScreen();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
初始化 CGB 專用的 160×144 圖塊配置器。清空兩個圖塊庫與地圖 9800,設定捲動、調色盤、色彩及相機,重設圖塊數與查表/跨度狀態,再啟用無號 BG 圖塊定址。不載入 HUD 圖塊。須保留其固定 WRAM 查表、資料內容與位址清單,且在全畫面繪製期間維持映射同一個 WRAM 記憶體庫。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// A large frame demonstrates the 160x144 renderer and its allocated-tile count.
#include "wire_cgb_example.h"
void main() {
wire_results_clear();
Wire3DCGB_InitFullScreen(); wire_colors();
Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
Wire3DCGB_DrawLine2D(8,8,151,8);
Wire3DCGB_DrawLine2D(8,8,8,135);
Wire3DCGB_DrawLine2DColor(8,135,151,135,2);
Wire3DCGB_DrawLine2DColor(151,8,151,135,3);
result[0]=Wire3DCGB_GetFullScreenTileCount();
result[1]=Wire3DCGB_GetFullScreenOverflow();
Wire3DCGB_EndFrameFast();
result[7]=0xA55A;
while(1) {}
}預期結果
大型邊框涵蓋 (8,8)..(151,135):上邊與左邊為紅色、下邊為藍色、右邊為綠色。使用 64 個圖塊,overflow 為零。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_full.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_full.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:114
kitaqgb/lib/wire3d_cgb.c:8070
void Wire3DCGB_InitFullScreen()
{
w3dcgb_atomic_maps = 0;
Wire3DCGB_EnableDoubleSpeed();
w3dcgb_wait_vblank_start();
w3dcgb_reg_lcdc = 0;
w3dcgb_clear_vram_asm();
w3dcgb_full_clear_map_asm();
w3dcgb_reg_scx = 0;
w3dcgb_reg_scy = 0;
w3dcgb_reg_bgp = 0xB4;
Wire3DCGB_SetPaletteRGB15(
WIRE3DCGB_RGB15(0, 0, 2),
WIRE3DCGB_RGB15(10, 20, 31),
WIRE3DCGB_RGB15(31, 31, 31),
WIRE3DCGB_RGB15(31, 14, 4));
w3dcgb_line_color = WIRE3DCGB_COLOR_DEFAULT;
w3dcgb_bgq_count = 0;
w3dcgb_dirty_count = 0;
w3dcgb_prev_dirty_count = 0;
w3dcgb_display_tile_bank = 0;
w3dcgb_pending_tile_bank = 0;
w3dcgb_full_tile_count = 0;
w3dcgb_full_prev_tile_count = 0;
w3dcgb_full_overflow = 0;
w3dcgb_full_mode = 1;
Wire3DCGB_SetCamera((w3dcgb_i16)0, (w3dcgb_i16)0, (w3dcgb_i16)0, 0, 0, 0);
w3dcgb_full_begin_asm();
w3dcgb_reg_lcdc = 0x91;
}Wire3DCGB_InvalidateFrameHistory
將目前及前兩次傳輸範圍擴大為一般模式的全部 192 個圖塊。
語法
void Wire3DCGB_InvalidateFrameHistory();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
將目前及前兩次稀疏範圍標為一般模式的全部 192 個圖塊。不清除像素資料;後續上傳不可依賴舊範圍。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
CGB稀疏顯示啟動時,首次使用各目標記憶體區(前兩幀)會更新整個視窗,清除初始化圖塊。量測包含啟動成本。一般DrawLine2D不登記稀疏範圍,請使用DrawLineClipped2D或明確呼叫MarkDirtyRect2D。
使用範例
#pragma bank 0
// Reuse both VRAM banks and remove old geometry while presenting sparse frames.
#include "wire_cgb_example.h"
void main() {
wire_results_clear(); Wire3DCGB_Init();
Wire3DCGB_ClearFrameTiles();
Wire3DCGB_EnableAtomicMaps(); wire_colors();
// First frame: red on the left. Fast begin invalidates both bank histories.
Wire3DCGB_BeginFrameFast(); wire_frame(8,8,32,32,1);
Wire3DCGB_EndFrameFast();
// Second frame: blue in the middle, with the old red frame removed.
Wire3DCGB_BeginFrameSparse(); wire_frame(40,40,64,64,2);
Wire3DCGB_EndFrameSparse();
// Third frame: explicitly clearing a stage discards its first green point.
Wire3DCGB_BeginFrameSparse();
Wire3DCGB_SetLineColor(3); Wire3DCGB_DrawPoint2D(4,4);
Wire3DCGB_ClearSparseStageFast();
// The final image contains only this green frame on the right.
wire_frame(80,8,112,32,3);
Wire3DCGB_MarkDirtyRect2D(80,8,112,32);
Wire3DCGB_InvalidateFrameHistory();
Wire3DCGB_EndFrameSparseNow();
result[0]=Wire3DCGB_GetLineColor();
result[7]=0xA55A;
while(1) {}
}預期結果
先前繪製的紅框與藍框消失,只留下 (80,8)..(112,32) 的最後一個綠框,示範稀疏上傳與歷史管理。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_sparse.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_sparse.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:142
kitaqgb/lib/wire3d_cgb.c:9712
void Wire3DCGB_InvalidateFrameHistory()
{
w3dcgb_dirty_min_tile = 0;
w3dcgb_dirty_max_tile = (w3dcgb_u8)(WIRE3DCGB_TILE_COUNT - 1);
w3dcgb_prev_dirty_min_tile = 0;
w3dcgb_prev_dirty_max_tile = (w3dcgb_u8)(WIRE3DCGB_TILE_COUNT - 1);
w3dcgb_older_dirty_min_tile = 0;
w3dcgb_older_dirty_max_tile = (w3dcgb_u8)(WIRE3DCGB_TILE_COUNT - 1);
}Wire3DCGB_MarkDirtyRect2D
將像素矩形加入稍後須上傳的範圍。
語法
void Wire3DCGB_MarkDirtyRect2D(w3dcgb_u8 min_x, w3dcgb_u8 min_y, w3dcgb_u8 max_x, w3dcgb_u8 max_y);參數
min_x較小的 X 端點,以視埠像素為單位;排序與裁切依此操作的注意事項。
min_y較小的 Y 端點,以視埠像素為單位;排序與裁切依此操作的注意事項。
max_x較大的 X 端點,以視埠像素為單位;排序與裁切依此操作的注意事項。
max_y較大的 X 端點,以視埠像素為單位;排序與裁切依此操作的注意事項。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
將包含端點的像素矩形標為稍後傳輸,但不繪製它。須按大小順序提供端點;超過 127/95 的值會限制到邊界。此操作追蹤 128×96 圖塊範圍,不是全畫面圖塊配置器。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Reuse both VRAM banks and remove old geometry while presenting sparse frames.
#include "wire_cgb_example.h"
void main() {
wire_results_clear(); Wire3DCGB_Init();
Wire3DCGB_ClearFrameTiles();
Wire3DCGB_EnableAtomicMaps(); wire_colors();
// First frame: red on the left. Fast begin invalidates both bank histories.
Wire3DCGB_BeginFrameFast(); wire_frame(8,8,32,32,1);
Wire3DCGB_EndFrameFast();
// Second frame: blue in the middle, with the old red frame removed.
Wire3DCGB_BeginFrameSparse(); wire_frame(40,40,64,64,2);
Wire3DCGB_EndFrameSparse();
// Third frame: explicitly clearing a stage discards its first green point.
Wire3DCGB_BeginFrameSparse();
Wire3DCGB_SetLineColor(3); Wire3DCGB_DrawPoint2D(4,4);
Wire3DCGB_ClearSparseStageFast();
// The final image contains only this green frame on the right.
wire_frame(80,8,112,32,3);
Wire3DCGB_MarkDirtyRect2D(80,8,112,32);
Wire3DCGB_InvalidateFrameHistory();
Wire3DCGB_EndFrameSparseNow();
result[0]=Wire3DCGB_GetLineColor();
result[7]=0xA55A;
while(1) {}
}預期結果
先前繪製的紅框與藍框消失,只留下 (80,8)..(112,32) 的最後一個綠框,示範稀疏上傳與歷史管理。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_sparse.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_sparse.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:126
kitaqgb/lib/wire3d_cgb.c:1288
void Wire3DCGB_MarkDirtyRect2D(w3dcgb_u8 min_x, w3dcgb_u8 min_y, w3dcgb_u8 max_x, w3dcgb_u8 max_y)
{
w3dcgb_mark_dirty_rect(min_x, min_y, max_x, max_y);
}Wire3DCGB_MarkPackedSilhouette2D
在 128×96 遮蔽點陣中標記逐列封裝的剪影。
語法
void Wire3DCGB_MarkPackedSilhouette2D(const w3dcgb_u8* profile, w3dcgb_u8 count, w3dcgb_i8 y0, w3dcgb_u8 x, w3dcgb_u8 y);參數
profile每列一位元組的剪影陣列;0xFF 略過該列。
count提供的陣列項目數;處理上限請參閱各操作的說明。
y0從中心 Y 到剪影第一列的有號偏移。
x中心 X 座標,以視埠像素為單位。
y中心 Y 座標,以視埠像素為單位。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
在 128×96 點陣遮罩中標記最多 29 列剪影。每個封裝位元組的高半位元組表示中心偏移(nibble−7),低半位元組表示半寬;0xFF 略過該列。各列放於 y+y0+i,跨度向外擴張兩像素後裁切至視埠。profile 須包含 count 個可讀位元組;null 會被忽略。不更新全畫面跨度,也不啟用遮蔽。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Red/blue scanlines stop inside masks; green outlines identify the triangle.
#include "wire_cgb_example.h"
__prg_rom u8 silhouette[5]={0x73,0x74,0xFF,0x75,0x73};
void main() {
u8 y;
wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
// Clearing this first test mask must leave the upper-left scanline intact.
Wire3DCGB_MarkTriangle2D(8,8,16,8,8,16);
Wire3DCGB_ClearOcclusionMask();
Wire3DCGB_MarkTriangle2D(32,16,64,16,32,48);
Wire3DCGB_MarkPackedSilhouette2D(silhouette,5,-2,104,32);
Wire3DCGB_SetOcclusionActive(1);
for(y=8;y<=56;y=y+4) Wire3DCGB_DrawLine2DColor(8,y,88,y,1);
for(y=28;y<=36;y++) Wire3DCGB_DrawLine2DColor(92,y,120,y,2);
Wire3DCGB_SetOcclusionActive(0);
Wire3DCGB_DrawLine2DColor(32,16,64,16,3);
Wire3DCGB_DrawLine2DColor(64,16,32,48,3);
Wire3DCGB_DrawLine2DColor(32,48,32,16,3);
Wire3DCGB_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
三角形遮住紅色掃描線的中段,封裝的剪影遮住藍線;綠色外框標示遮蔽區域的位置。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_mask.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_mask.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:151
kitaqgb/lib/wire3d_cgb.c:1991
void Wire3DCGB_MarkPackedSilhouette2D(const w3dcgb_u8* profile, w3dcgb_u8 count,
w3dcgb_i8 y0, w3dcgb_u8 x, w3dcgb_u8 y)
{
w3dcgb_u8 i;
w3dcgb_u8 packed;
w3dcgb_u8 half_width;
w3dcgb_i16 center;
w3dcgb_i16 left;
w3dcgb_i16 right;
w3dcgb_i16 row;
if (profile == 0) return;
if (count > 29) count = 29;
i = 0;
while (i < count)
{
packed = profile[(__safe_index w3dcgb_u8)i];
if (packed != 0xFF)
{
row = (w3dcgb_i16)((w3dcgb_i16)y + (w3dcgb_i16)y0 + (w3dcgb_i16)i);
if ((row >= 0) && (row < WIRE3DCGB_SCREEN_H))
{
center = (w3dcgb_i16)((w3dcgb_i16)x + (w3dcgb_i16)(packed >> 4) - 7);
half_width = (w3dcgb_u8)(packed & 15);
/* Two-pixel guard covers rasterized endpoints at 22.5-degree views. */
left = (w3dcgb_i16)(center - (w3dcgb_i16)half_width - 2);
right = (w3dcgb_i16)(center + (w3dcgb_i16)half_width + 2);
if ((right >= 0) && (left < WIRE3DCGB_SCREEN_W))
{
if (left < 0) left = 0;
if (right >= WIRE3DCGB_SCREEN_W) right = WIRE3DCGB_SCREEN_W - 1;
w3dcgb_mask_span_y = (w3dcgb_u8)row;
w3dcgb_mask_span_min_x = (w3dcgb_u8)left;
w3dcgb_mask_span_max_x = (w3dcgb_u8)right;
w3dcgb_mask_set_span_asm();
}
}
}
i = (w3dcgb_u8)(i + 1);
}
}Wire3DCGB_MarkTriangle2D
將三角形登錄為可遮住後續線段的覆蓋區域。
語法
void Wire3DCGB_MarkTriangle2D(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by, w3dcgb_u8 cx, w3dcgb_u8 cy);參數
ax頂點 A 的 X 座標,以視埠像素為單位。
ay頂點 A 的 Y 座標,以視埠像素為單位。
bx頂點 B 的 X 座標,以視埠像素為單位。
by頂點 B 的 Y 座標,以視埠像素為單位。
cx頂點 C 的 X 座標,以視埠像素為單位。
cy頂點 C 的 Y 座標,以視埠像素為單位。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
在畫面空間標記三角形,不繪製像素,也不啟用遮蔽。頂點須位於所選視埠內。使用中的 ASM 會在 X 方向增加一像素保護範圍,128×96 模式限制於 0..127,160×144 模式限制於 0..159。此函式不會裁切任意越界三角形。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Red/blue scanlines stop inside masks; green outlines identify the triangle.
#include "wire_cgb_example.h"
__prg_rom u8 silhouette[5]={0x73,0x74,0xFF,0x75,0x73};
void main() {
u8 y;
wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
// Clearing this first test mask must leave the upper-left scanline intact.
Wire3DCGB_MarkTriangle2D(8,8,16,8,8,16);
Wire3DCGB_ClearOcclusionMask();
Wire3DCGB_MarkTriangle2D(32,16,64,16,32,48);
Wire3DCGB_MarkPackedSilhouette2D(silhouette,5,-2,104,32);
Wire3DCGB_SetOcclusionActive(1);
for(y=8;y<=56;y=y+4) Wire3DCGB_DrawLine2DColor(8,y,88,y,1);
for(y=28;y<=36;y++) Wire3DCGB_DrawLine2DColor(92,y,120,y,2);
Wire3DCGB_SetOcclusionActive(0);
Wire3DCGB_DrawLine2DColor(32,16,64,16,3);
Wire3DCGB_DrawLine2DColor(64,16,32,48,3);
Wire3DCGB_DrawLine2DColor(32,48,32,16,3);
Wire3DCGB_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
三角形遮住紅色掃描線的中段,封裝的剪影遮住藍線;綠色外框標示遮蔽區域的位置。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_mask.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_mask.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:150
kitaqgb/lib/wire3d_cgb.c:1980
void Wire3DCGB_MarkTriangle2D(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by, w3dcgb_u8 cx, w3dcgb_u8 cy)
{
w3dcgb_mark_triangle(ax, ay, bx, by, cx, cy);
}Wire3DCGB_ProjectAxis48
以焦距 48 近似計算一個投影偏移。
語法
w3dcgb_i16 Wire3DCGB_ProjectAxis48(w3dcgb_i16 value, w3dcgb_i16 z);參數
value要投影的有號 16 位元分量。
z用於選擇大小或計算投影的深度。
回傳值
近似計算出的有號 16 位元投影偏移。
使用條件與限制
不套用相機或畫面中心偏移,近似計算 value*48/z。負的或極小的 Z 視為 4。Z 大於 255 時,同時將深度與大小右移,直到深度可容納於一個位元組,再將大小上限設為 160。傳回有號偏移;此輔助函式不因近端或遠端深度而拒絕輸入。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Preprojected edge arrays, a clipped square, a tiny marker and a projectile.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Edge edges[4]={{0,1},{1,2},{2,3},{3,0}};
__prg_rom s8 vx8[4]={-8,8,8,-8};
__prg_rom s8 vy8[4]={-8,-8,8,8};
__prg_rom s16 vx16[4]={-12,12,12,-12};
__prg_rom s16 vy16[4]={-8,-8,8,8};
__prg_rom u8 mask[1]={5};
Wire3DCGB_Model shape;
void main() {
wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
shape.vertices=0;shape.edges=edges;shape.faces=0;shape.edge_faces=0;
shape.vertex_count=4;shape.edge_count=4;shape.face_count=0;shape.flags=0;
Wire3DCGB_SetLineColor(2);
Wire3DCGB_DrawMaskedModel2D(&shape,vx8,vy8,mask,24,24,1);
Wire3DCGB_DrawEdgeList2D(edges,4,vx8,vy8,64,24,2);
Wire3DCGB_DrawEdgeListClipped2D(edges,4,vx16,vy16,4,4,64,3);
Wire3DCGB_DrawTinyModel2D(104,24,16,3);
result[0]=Wire3DCGB_ProjectAxis48(48,96);
result[1]=Wire3DCGB_ProjectAxis48(-48,96);
Wire3DCGB_DrawFastProjectile(96,64,64,0,1);
result[2]=Wire3DCGB_GetLineColor();
Wire3DCGB_EndFrame();result[7]=0xA55A;
while(1) {}
}預期結果
以兩條紅色水平邊、藍色正方形、經裁切的綠框、綠色六像素標記與紅色投射物,比較各種列表格式。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_lists.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_lists.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:141
kitaqgb/lib/wire3d_cgb.c:9702
w3dcgb_i16 Wire3DCGB_ProjectAxis48(w3dcgb_i16 value, w3dcgb_i16 z)
{
w3dcgb_projection_value = value;
w3dcgb_projection_z = z;
w3dcgb_project_axis48_asm();
return w3dcgb_projection_result;
}Wire3DCGB_ProjectPoint
將世界座標點透過相機投影至 128×96 視埠。
語法
w3dcgb_u8 Wire3DCGB_ProjectPoint(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_u8* sx, w3dcgb_u8* sy);參數
x點或物件原點的世界座標 X 分量。
y點或物件原點的世界座標 Y 分量。
z點或物件原點的世界座標 Z 分量。
sx接收投影 X 座標的有效可寫入 u8 指標。
sy接收投影 Y 座標的有效可寫入 u8 指標。
回傳值
投影成功傳回 1,深度遭拒傳回 0。
使用條件與限制
將世界座標點透過目前相機投影至 128×96 視埠。深度遭拒時傳回零且不改變輸出;成功時寫入限制於視埠內的位元組座標。須提供有效且可寫入的指標。這不是 160×144 全畫面投影器。MINIMAL_RUNTIME 建置不提供此函式。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Four cubes compare unity/half scale and persistent/temporary line colors.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Vec3 vertices[8]={
{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},
{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}
};
__prg_rom Wire3DCGB_Edge edges[12]={
{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},
{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}
};
Wire3DCGB_Model cube;
u8 sx;
u8 sy;
void main() {
wire_results_clear();
cube.vertices=vertices; cube.edges=edges;
cube.faces=0; cube.edge_faces=0;
cube.vertex_count=8; cube.edge_count=12; cube.face_count=0; cube.flags=0;
Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
Wire3DCGB_DrawModel(&cube,-32,32,96,0,0,0);
Wire3DCGB_DrawModelScaled(&cube,32,32,96,0,0,0,128);
Wire3DCGB_DrawModelColor(&cube,-32,-32,96,0,0,0,2);
Wire3DCGB_DrawModelScaledColor(&cube,32,-32,96,0,0,0,128,3);
result[0]=Wire3DCGB_GetLineColor();
Wire3DCGB_DrawLine3D(0,56,96,0,-56,96);
Wire3DCGB_DrawLine3DColor(-80,0,96,80,0,96,3);
result[1]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
result[2]=sx; result[3]=sy;
// Camera setters affect future projection, leaving the staged cubes intact.
Wire3DCGB_SetCamera(0,0,0,0,4,0);
result[4]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
result[5]=Wire3DCGB_ProjectPointNoRotation(0,0,96,&sx,&sy);
result[6]=sx;
Wire3DCGB_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
比較以紅、藍、綠繪製的原倍率與縮放模型,以及交錯的 3D 線段。RAM 值也用來檢查相機投影及其不旋轉版本。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_models.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:169
kitaqgb/lib/wire3d_cgb.c:589
w3dcgb_u8 Wire3DCGB_ProjectPoint(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_u8* sx, w3dcgb_u8* sy)
{
return w3dcgb_project_world(x, y, z, sx, sy);
}Wire3DCGB_ProjectPointNoRotation
扣除相機位置後,不套用相機旋轉而投影點。
語法
w3dcgb_u8 Wire3DCGB_ProjectPointNoRotation(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_u8* sx, w3dcgb_u8* sy);參數
x點或物件原點的世界座標 X 分量。
y點或物件原點的世界座標 Y 分量。
z點或物件原點的世界座標 Z 分量。
sx接收投影 X 座標的有效可寫入 u8 指標。
sy接收投影 Y 座標的有效可寫入 u8 指標。
回傳值
投影成功傳回 1,深度遭拒傳回 0。
使用條件與限制
適用於相機俯仰、偏航與滾轉皆維持零的遊戲之快速路徑。扣除相機位置後,忽略所有相機角度並投影至 128×96。須在相機俯仰、偏航、滾轉均為零時使用。深度無效時拒絕且不改變輸出指標所指的值;成功座標會限制於視埠內。MINIMAL_RUNTIME 建置不提供此函式。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Four cubes compare unity/half scale and persistent/temporary line colors.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Vec3 vertices[8]={
{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},
{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}
};
__prg_rom Wire3DCGB_Edge edges[12]={
{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},
{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}
};
Wire3DCGB_Model cube;
u8 sx;
u8 sy;
void main() {
wire_results_clear();
cube.vertices=vertices; cube.edges=edges;
cube.faces=0; cube.edge_faces=0;
cube.vertex_count=8; cube.edge_count=12; cube.face_count=0; cube.flags=0;
Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
Wire3DCGB_DrawModel(&cube,-32,32,96,0,0,0);
Wire3DCGB_DrawModelScaled(&cube,32,32,96,0,0,0,128);
Wire3DCGB_DrawModelColor(&cube,-32,-32,96,0,0,0,2);
Wire3DCGB_DrawModelScaledColor(&cube,32,-32,96,0,0,0,128,3);
result[0]=Wire3DCGB_GetLineColor();
Wire3DCGB_DrawLine3D(0,56,96,0,-56,96);
Wire3DCGB_DrawLine3DColor(-80,0,96,80,0,96,3);
result[1]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
result[2]=sx; result[3]=sy;
// Camera setters affect future projection, leaving the staged cubes intact.
Wire3DCGB_SetCamera(0,0,0,0,4,0);
result[4]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
result[5]=Wire3DCGB_ProjectPointNoRotation(0,0,96,&sx,&sy);
result[6]=sx;
Wire3DCGB_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
比較以紅、藍、綠繪製的原倍率與縮放模型,以及交錯的 3D 線段。RAM 值也用來檢查相機投影及其不旋轉版本。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_models.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:171
Fast path for games whose camera pitch, yaw, and roll stay at zero.
kitaqgb/lib/wire3d_cgb.c:598
w3dcgb_u8 Wire3DCGB_ProjectPointNoRotation(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z,
w3dcgb_u8* sx, w3dcgb_u8* sy)
{
return w3dcgb_project_camera_space((w3dcgb_i16)(x - w3dcgb_cam_x),
(w3dcgb_i16)(y - w3dcgb_cam_y),
(w3dcgb_i16)(z - w3dcgb_cam_z), sx, sy);
}Wire3DCGB_PutBgTile
將背景圖塊編號變更排入佇列,交由 EndFrame 處理。
語法
void Wire3DCGB_PutBgTile(w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_u8 tile);參數
x32×32 背景地圖中的 X 圖塊座標。
y32×32 背景地圖中的 Y 圖塊座標。
tile背景格的八位元圖塊編號。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
將 32×32 BG 地圖的圖塊編號寫入排入佇列。忽略無效座標,以及已有 48 筆待寫入時的新增要求。EndFrame 會送出此私有佇列;atomic-map 模式將寫入複製至兩個 BG 地圖。不將屬性排入佇列。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DCGB_EnableDoubleSpeed();
Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
result[2]=(u8)(sample_key1&128);
// Palette writes are performed with the LCD off, after entering VBlank.
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0;
Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
sample_lcdc=0x81;
Wire3DCGB_SetScreenOffset(0,0);
Wire3DCGB_SetCamera(0,0,0,0,0,0);
Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
Wire3DCGB_DrawLine2D(8,8,56,8);
Wire3DCGB_DrawLine2D(56,8,56,40);
Wire3DCGB_DrawLine2D(56,40,8,40);
Wire3DCGB_DrawLine2D(8,40,8,8);
Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
Wire3DCGB_SetLineColor(3);
Wire3DCGB_DrawPoint2D(64,48);
Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
Wire3DCGB_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。紅色邊框內有藍色對角線,另有綠點與綠色水平線、藍色 L,以及右上角的綠色數字 0。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:188
kitaqgb/lib/wire3d_cgb.c:1067
void Wire3DCGB_PutBgTile(w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_u8 tile)
{
if (x >= 32) return;
if (y >= 32) return;
if (w3dcgb_bgq_count >= W3DCGB_BG_QUEUE_LIMIT) return;
w3dcgb_bgq_x[(__safe_index w3dcgb_u8)w3dcgb_bgq_count] = x;
w3dcgb_bgq_y[(__safe_index w3dcgb_u8)w3dcgb_bgq_count] = y;
w3dcgb_bgq_tile[(__safe_index w3dcgb_u8)w3dcgb_bgq_count] = tile;
w3dcgb_bgq_count = (w3dcgb_u8)(w3dcgb_bgq_count + 1);
}WIRE3DCGB_RGB15
將五位元紅、綠、藍通道封裝為 CGB 15 位元色彩。
語法
#define WIRE3DCGB_RGB15(r5, g5, b5) ((w3dcgb_u16)((w3dcgb_u16)((r5) & 31) | ((w3dcgb_u16)((g5) & 31) << 5) | ((w3dcgb_u16)((b5) & 31) << 10)))參數
r5紅色通道,0..31。
g5綠色通道,0..31。
b5藍色通道,0..31。
回傳值
以 u16 表示的封裝 RGB15 值。
使用條件與限制
將各色彩通道的低五位元封裝為 RGB15;每個引數只求值一次。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DCGB_EnableDoubleSpeed();
Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
result[2]=(u8)(sample_key1&128);
// Palette writes are performed with the LCD off, after entering VBlank.
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0;
Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
sample_lcdc=0x81;
Wire3DCGB_SetScreenOffset(0,0);
Wire3DCGB_SetCamera(0,0,0,0,0,0);
Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
Wire3DCGB_DrawLine2D(8,8,56,8);
Wire3DCGB_DrawLine2D(56,8,56,40);
Wire3DCGB_DrawLine2D(56,40,8,40);
Wire3DCGB_DrawLine2D(8,40,8,8);
Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
Wire3DCGB_SetLineColor(3);
Wire3DCGB_DrawPoint2D(64,48);
Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
Wire3DCGB_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。紅色邊框內有藍色對角線,另有綠點與綠色水平線、藍色 L,以及右上角的綠色數字 0。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:50
Wire3DCGB_SetCamera
儲存投影使用的相機位置與朝向,每圈使用 16 個角度步階。
語法
void Wire3DCGB_SetCamera(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 pitch, w3dcgb_i8 yaw, w3dcgb_i8 roll);參數
x相機的世界座標 X 分量。
y相機的世界座標 Y 分量。
z相機的世界座標 Z 分量。
pitch繞 X 軸旋轉;十六步為一整圈。
yaw繞 Y 軸旋轉;十六步為一整圈。
roll繞 Z 軸旋轉;十六步為一整圈。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
儲存相機位置與角度,不改變既有像素。旋轉輔助函式使用角度的低四位元,即每圈 16 段。畫面偏移由獨立 LCD 暫存器控制,此呼叫不改動它們。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Four cubes compare unity/half scale and persistent/temporary line colors.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Vec3 vertices[8]={
{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},
{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}
};
__prg_rom Wire3DCGB_Edge edges[12]={
{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},
{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}
};
Wire3DCGB_Model cube;
u8 sx;
u8 sy;
void main() {
wire_results_clear();
cube.vertices=vertices; cube.edges=edges;
cube.faces=0; cube.edge_faces=0;
cube.vertex_count=8; cube.edge_count=12; cube.face_count=0; cube.flags=0;
Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
Wire3DCGB_DrawModel(&cube,-32,32,96,0,0,0);
Wire3DCGB_DrawModelScaled(&cube,32,32,96,0,0,0,128);
Wire3DCGB_DrawModelColor(&cube,-32,-32,96,0,0,0,2);
Wire3DCGB_DrawModelScaledColor(&cube,32,-32,96,0,0,0,128,3);
result[0]=Wire3DCGB_GetLineColor();
Wire3DCGB_DrawLine3D(0,56,96,0,-56,96);
Wire3DCGB_DrawLine3DColor(-80,0,96,80,0,96,3);
result[1]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
result[2]=sx; result[3]=sy;
// Camera setters affect future projection, leaving the staged cubes intact.
Wire3DCGB_SetCamera(0,0,0,0,4,0);
result[4]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
result[5]=Wire3DCGB_ProjectPointNoRotation(0,0,96,&sx,&sy);
result[6]=sx;
Wire3DCGB_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
比較以紅、藍、綠繪製的原倍率與縮放模型,以及交錯的 3D 線段。RAM 值也用來檢查相機投影及其不旋轉版本。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_models.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:127
kitaqgb/lib/wire3d_cgb.c:8266
void Wire3DCGB_SetCamera(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 pitch, w3dcgb_i8 yaw, w3dcgb_i8 roll)
{
w3dcgb_cam_x = x;
w3dcgb_cam_y = y;
w3dcgb_cam_z = z;
w3dcgb_cam_pitch = pitch;
w3dcgb_cam_yaw = yaw;
w3dcgb_cam_roll = roll;
}Wire3DCGB_SetLineColor
選擇後續線段繪製使用的色彩索引。
語法
void Wire3DCGB_SetLineColor(w3dcgb_u8 color);參數
color繪圖色彩索引;範例調色盤使用 1=紅、2=藍、3=綠。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
儲存 color & 3。請使用具名的線色 1..3:一般線段對位元平面做 OR,因此交會的色彩會合併;全畫面快速線段則替換像素色彩。線色 0 視為 3,不用於擦除。一般模式的點繪製另行支援以色彩 0 擦除。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DCGB_EnableDoubleSpeed();
Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
result[2]=(u8)(sample_key1&128);
// Palette writes are performed with the LCD off, after entering VBlank.
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0;
Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
sample_lcdc=0x81;
Wire3DCGB_SetScreenOffset(0,0);
Wire3DCGB_SetCamera(0,0,0,0,0,0);
Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
Wire3DCGB_DrawLine2D(8,8,56,8);
Wire3DCGB_DrawLine2D(56,8,56,40);
Wire3DCGB_DrawLine2D(56,40,8,40);
Wire3DCGB_DrawLine2D(8,40,8,8);
Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
Wire3DCGB_SetLineColor(3);
Wire3DCGB_DrawPoint2D(64,48);
Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
Wire3DCGB_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。紅色邊框內有藍色對角線,另有綠點與綠色水平線、藍色 L,以及右上角的綠色數字 0。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:119
kitaqgb/lib/wire3d_cgb.c:1140
void Wire3DCGB_SetLineColor(w3dcgb_u8 color)
{
w3dcgb_line_color = (w3dcgb_u8)(color & 3);
}Wire3DCGB_SetOcclusionActive
啟用或停用後續線段的遮蔽檢查。
語法
void Wire3DCGB_SetOcclusionActive(w3dcgb_u8 active);參數
active零停用遮蔽檢查,其他值均啟用。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
將 active 正規化為零或一,並儲存為遮蔽開關。不清除遮罩,也不標記幾何圖形。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Red/blue scanlines stop inside masks; green outlines identify the triangle.
#include "wire_cgb_example.h"
__prg_rom u8 silhouette[5]={0x73,0x74,0xFF,0x75,0x73};
void main() {
u8 y;
wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
// Clearing this first test mask must leave the upper-left scanline intact.
Wire3DCGB_MarkTriangle2D(8,8,16,8,8,16);
Wire3DCGB_ClearOcclusionMask();
Wire3DCGB_MarkTriangle2D(32,16,64,16,32,48);
Wire3DCGB_MarkPackedSilhouette2D(silhouette,5,-2,104,32);
Wire3DCGB_SetOcclusionActive(1);
for(y=8;y<=56;y=y+4) Wire3DCGB_DrawLine2DColor(8,y,88,y,1);
for(y=28;y<=36;y++) Wire3DCGB_DrawLine2DColor(92,y,120,y,2);
Wire3DCGB_SetOcclusionActive(0);
Wire3DCGB_DrawLine2DColor(32,16,64,16,3);
Wire3DCGB_DrawLine2DColor(64,16,32,48,3);
Wire3DCGB_DrawLine2DColor(32,48,32,16,3);
Wire3DCGB_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
三角形遮住紅色掃描線的中段,封裝的剪影遮住藍線;綠色外框標示遮蔽區域的位置。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_mask.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_mask.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:149
kitaqgb/lib/wire3d_cgb.c:1970
void Wire3DCGB_SetOcclusionActive(w3dcgb_u8 active)
{
if (active == 0) w3dcgb_occlusion_active = 0;
else w3dcgb_occlusion_active = 1;
}Wire3DCGB_SetPaletteRGB15
設定四個繪圖色彩,以及用於替圖樣著色的背景調色盤。
語法
void Wire3DCGB_SetPaletteRGB15(w3dcgb_u16 color0, w3dcgb_u16 color1, w3dcgb_u16 color2, w3dcgb_u16 color3);參數
color0調色盤項目 0 的 RGB15 色彩。
color1調色盤項目 1 的 RGB15 色彩。
color2調色盤項目 2 的 RGB15 色彩。
color3調色盤項目 3 的 RGB15 色彩。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
將提供的四個 RGB15 色彩設為 BG 調色盤 0。調色盤 1..3 共用 color0,並在各自的項目 1..3 重複填入對應的非零色彩,因此可透過屬性替單色圖樣圖塊換色。須在可存取調色盤的時段呼叫,通常是關閉 LCD 的設定階段或 VBlank。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DCGB_EnableDoubleSpeed();
Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
result[2]=(u8)(sample_key1&128);
// Palette writes are performed with the LCD off, after entering VBlank.
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0;
Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
sample_lcdc=0x81;
Wire3DCGB_SetScreenOffset(0,0);
Wire3DCGB_SetCamera(0,0,0,0,0,0);
Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
Wire3DCGB_DrawLine2D(8,8,56,8);
Wire3DCGB_DrawLine2D(56,8,56,40);
Wire3DCGB_DrawLine2D(56,40,8,40);
Wire3DCGB_DrawLine2D(8,40,8,8);
Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
Wire3DCGB_SetLineColor(3);
Wire3DCGB_DrawPoint2D(64,48);
Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
Wire3DCGB_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。紅色邊框內有藍色對角線,另有綠點與綠色水平線、藍色 L,以及右上角的綠色數字 0。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:118
kitaqgb/lib/wire3d_cgb.c:1112
void Wire3DCGB_SetPaletteRGB15(w3dcgb_u16 color0, w3dcgb_u16 color1, w3dcgb_u16 color2, w3dcgb_u16 color3)
{
w3dcgb_write_bg_color(0, color0);
w3dcgb_write_bg_color(1, color1);
w3dcgb_write_bg_color(2, color2);
w3dcgb_write_bg_color(3, color3);
w3dcgb_write_bg_color(4, color0);
w3dcgb_write_bg_color(5, color1);
w3dcgb_write_bg_color(6, color1);
w3dcgb_write_bg_color(7, color1);
w3dcgb_write_bg_color(8, color0);
w3dcgb_write_bg_color(9, color2);
w3dcgb_write_bg_color(10, color2);
w3dcgb_write_bg_color(11, color2);
w3dcgb_write_bg_color(12, color0);
w3dcgb_write_bg_color(13, color3);
w3dcgb_write_bg_color(14, color3);
w3dcgb_write_bg_color(15, color3);
}Wire3DCGB_SetScreenOffset
直接設定 LCD 捲動暫存器 SCX 與 SCY。
語法
void Wire3DCGB_SetScreenOffset(w3dcgb_u8 scx, w3dcgb_u8 scy);參數
scx寫入 SCX 的像素捲動偏移量。
scy寫入 SCY 的像素捲動偏移量。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
立即寫入 SCX/SCY,不等待 VBlank,也不改變投影座標。呼叫端須自行選擇何時可接受可見的捲動變化。
僅限 CGB。一般暫存區保留 WRAM 記憶體庫 2 的 D300..DEFF。共用狀態使這些常式不可重入;不可從中斷中遞迴呼叫。範例使用固定堆疊與完整執行階段。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DCGB_EnableDoubleSpeed();
Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
result[2]=(u8)(sample_key1&128);
// Palette writes are performed with the LCD off, after entering VBlank.
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0;
Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
sample_lcdc=0x81;
Wire3DCGB_SetScreenOffset(0,0);
Wire3DCGB_SetCamera(0,0,0,0,0,0);
Wire3DCGB_BeginFrame();
Wire3DCGB_SetLineColor(1);
Wire3DCGB_DrawLine2D(8,8,56,8);
Wire3DCGB_DrawLine2D(56,8,56,40);
Wire3DCGB_DrawLine2D(56,40,8,40);
Wire3DCGB_DrawLine2D(8,40,8,8);
Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
Wire3DCGB_SetLineColor(3);
Wire3DCGB_DrawPoint2D(64,48);
Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
Wire3DCGB_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。紅色邊框內有藍色對角線,另有綠點與綠色水平線、藍色 L,以及右上角的綠色數字 0。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_cgb.h:117
kitaqgb/lib/wire3d_cgb.c:1091
void Wire3DCGB_SetScreenOffset(w3dcgb_u8 scx, w3dcgb_u8 scy)
{
w3dcgb_reg_scx = scx;
w3dcgb_reg_scy = scy;
}Wire3D耗時、88列設定與獨立時鐘
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
88列完整上傳量為DMG 1,408位元組、CGB 2,816位元組。相較DMG 120列減少26.67%,相較96列減少8.33%;這不是fps提升比例。DMG保留256位元組的欄間距,CGB緊密排列11磚塊欄。CGB仍預留3,072位元組暫存區,以相容全螢幕模式。
ProjectCameraPoint直接投影攝影機座標,不扣除攝影機位置或旋轉。Z不在8..255時回傳0,輸出不變。X/Y限制在±120;逆深度表乘積以帶正負號的向下取整除以32,再限制至畫面邊界。這不是線段的幾何裁切。一般CGB ProjectPoint在零角度下仍保留旋轉的±220限制。
DMG EndFrameNow只省略起始等待新的VBlank,仍處理BG佇列、傳輸開關與dirty歷史。CGB EndFrameSparseNow也同步執行。Now仍須等待STAT存取時段、DMA完成及安全顯示切換。DMG更新不是原子的。CGB稀疏清除包含目前範圍及目標記憶體區兩幀前的範圍。低階CGB線段繪製須登記dirty。
CGB稀疏顯示啟動時,首次使用各目標記憶體區(前兩幀)會更新整個視窗,清除初始化圖塊。量測包含啟動成本。一般DrawLine2D不登記稀疏範圍,請使用DrawLineClipped2D或明確呼叫MarkDirtyRect2D。
範例使用獨立創作的移動方盒、長條儀表與四音BGM。移動依audio_vblank經過的tick更新,儀表由簡短安全的VBlank處理更新。不要從ISR呼叫共用狀態的繪圖器。wire3d_audio_vblank.c將80位元組佇列置於固定WRAM,控制函式置於ROM區5。不要同時編譯一般audio_vblank.c。CGB範例使用WIRE3DCGB_STAGE_BANK2_ALLOCATION。8位元tick差須在255幀內讀取。
測量工具統計上傳與顯示完成後的標記。以PPU dot(每秒4,194,304;每幀70,224)記錄清除、投影、光柵化、上傳加顯示及外部等待,並報告平均、中位數、最大間隔與超時次數。上傳加顯示包含內部STAT/DMA/VBlank等待。不要直接比較CGB雙速CPU與DMG的原始週期。平均fps相同不能證明沒有超時。尚未實機驗證。
7種自行編寫的範例設定各完成48次上傳,共336次暫存區/VRAM比較與84次空幀殘影清除檢查。5種設定通過25,700項投影邊界測試。5種Rust建置也完成48幀並輸出非零BGM。部分間隔超過4個PPU幀期限,平均fps無法證明無掉幀。此為模擬器驗證,非實機驗證。
KOKURA對自行編寫的DMG/CGB範例各執行400幀,SARAKURA分析與嚴格模式驗證通過。各設定錯誤0項,待機迴圈的PC重複警告1項,另保留DAC/混音器爆音風險等3項資訊。這不驗證音質或實機表現。
公開範例、圖像與驗證資料僅使用獨立創作的幾何圖形、儀表與音型。不含商業遊戲ROM、擷取的程式碼、圖形、畫面、音樂或狀態檔。
| 設定 | fps | 中位數 / 最差(PPU幀) | 期限超過 / 47 |
|---|---|---|---|
clocked_dmg_88_sparse | 13.852 | 4.449 / 4.732 | 35 |
clocked_dmg_96_sparse | 13.186 | 4.669 / 4.891 | 39 |
clocked_dmg_120_sparse | 13.434 | 4.453 / 7.176 | 35 |
clocked_cgb_88_sparse | 15.012 | 4.000 / 5.000 | 28 |
clocked_cgb_96_sparse | 15.092 | 4.000 / 5.000 | 26 |
clocked_cgb_88_full | 12.532 | 5.000 / 6.000 | 41 |
clocked_cgb_96_full | 12.588 | 5.000 / 5.020 | 41 |


Wire3DDMG_ProjectCameraPoint
ProjectCameraPoint直接投影攝影機座標,不扣除攝影機位置或旋轉。Z不在8..255時回傳0,輸出不變。X/Y限制在±120;逆深度表乘積以帶正負號的向下取整除以32,再限制至畫面邊界。這不是線段的幾何裁切。一般CGB ProjectPoint在零角度下仍保留旋轉的±220限制。
語法
w3ddmg_u8 Wire3DDMG_ProjectCameraPoint(w3ddmg_i16 x,w3ddmg_i16 y,w3ddmg_i16 z,w3ddmg_u8* sx,w3ddmg_u8* sy);參數
x帶正負號的16位元攝影機座標X/Y/Z。sx、sy須為有效可寫的u8指標。
y帶正負號的16位元攝影機座標X/Y/Z。sx、sy須為有效可寫的u8指標。
z帶正負號的16位元攝影機座標X/Y/Z。sx、sy須為有效可寫的u8指標。
sx帶正負號的16位元攝影機座標X/Y/Z。sx、sy須為有效可寫的u8指標。
sy帶正負號的16位元攝影機座標X/Y/Z。sx、sy須為有效可寫的u8指標。
回傳值
投影成功回傳1,深度拒絕回傳0。拒絕時sx、sy不變。
使用條件與限制
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
範例使用獨立創作的移動方盒、長條儀表與四音BGM。移動依audio_vblank經過的tick更新,儀表由簡短安全的VBlank處理更新。不要從ISR呼叫共用狀態的繪圖器。wire3d_audio_vblank.c將80位元組佇列置於固定WRAM,控制函式置於ROM區5。不要同時編譯一般audio_vblank.c。CGB範例使用WIRE3DCGB_STAGE_BANK2_ALLOCATION。8位元tick差須在255幀內讀取。
測量工具統計上傳與顯示完成後的標記。以PPU dot(每秒4,194,304;每幀70,224)記錄清除、投影、光柵化、上傳加顯示及外部等待,並報告平均、中位數、最大間隔與超時次數。上傳加顯示包含內部STAT/DMA/VBlank等待。不要直接比較CGB雙速CPU與DMG的原始週期。平均fps相同不能證明沒有超時。尚未實機驗證。
使用範例
#define WIRE3D_DMG_HEIGHT 88
#include "wire3d_dmg.h"
void project_one() {
u8 sx; u8 sy;
if (Wire3DDMG_ProjectCameraPoint(-24, 20, 96, &sx, &sy)) {
// Use the projected coordinates in a main-thread drawing routine.
}
}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
7種自行編寫的範例設定各完成48次上傳,共336次暫存區/VRAM比較與84次空幀殘影清除檢查。5種設定通過25,700項投影邊界測試。5種Rust建置也完成48幀並輸出非零BGM。部分間隔超過4個PPU幀期限,平均fps無法證明無掉幀。此為模擬器驗證,非實機驗證。
實作與原始碼
kitaqgb/lib/wire3d_dmg.h:146
Validate depth and project coordinates already in camera space.
kitaqgb/lib/wire3d_dmg.c:720
w3ddmg_u8 Wire3DDMG_ProjectCameraPoint(w3ddmg_i16 x,w3ddmg_i16 y,w3ddmg_i16 z,w3ddmg_u8* sx,w3ddmg_u8* sy)
{
return w3ddmg_project_camera_space(x,y,z,sx,sy);
}Wire3DCGB_ProjectCameraPoint
ProjectCameraPoint直接投影攝影機座標,不扣除攝影機位置或旋轉。Z不在8..255時回傳0,輸出不變。X/Y限制在±120;逆深度表乘積以帶正負號的向下取整除以32,再限制至畫面邊界。這不是線段的幾何裁切。一般CGB ProjectPoint在零角度下仍保留旋轉的±220限制。
語法
w3dcgb_u8 Wire3DCGB_ProjectCameraPoint(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_u8* sx, w3dcgb_u8* sy);參數
x帶正負號的16位元攝影機座標X/Y/Z。sx、sy須為有效可寫的u8指標。
y帶正負號的16位元攝影機座標X/Y/Z。sx、sy須為有效可寫的u8指標。
z帶正負號的16位元攝影機座標X/Y/Z。sx、sy須為有效可寫的u8指標。
sx帶正負號的16位元攝影機座標X/Y/Z。sx、sy須為有效可寫的u8指標。
sy帶正負號的16位元攝影機座標X/Y/Z。sx、sy須為有效可寫的u8指標。
回傳值
投影成功回傳1,深度拒絕回傳0。拒絕時sx、sy不變。
使用條件與限制
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
範例使用獨立創作的移動方盒、長條儀表與四音BGM。移動依audio_vblank經過的tick更新,儀表由簡短安全的VBlank處理更新。不要從ISR呼叫共用狀態的繪圖器。wire3d_audio_vblank.c將80位元組佇列置於固定WRAM,控制函式置於ROM區5。不要同時編譯一般audio_vblank.c。CGB範例使用WIRE3DCGB_STAGE_BANK2_ALLOCATION。8位元tick差須在255幀內讀取。
測量工具統計上傳與顯示完成後的標記。以PPU dot(每秒4,194,304;每幀70,224)記錄清除、投影、光柵化、上傳加顯示及外部等待,並報告平均、中位數、最大間隔與超時次數。上傳加顯示包含內部STAT/DMA/VBlank等待。不要直接比較CGB雙速CPU與DMG的原始週期。平均fps相同不能證明沒有超時。尚未實機驗證。
使用範例
#define WIRE3DCGB_HEIGHT 88
#include "wire3d_cgb.h"
void project_one() {
u8 sx; u8 sy;
if (Wire3DCGB_ProjectCameraPoint(-24, 20, 96, &sx, &sy)) {
// Use the projected coordinates in a main-thread drawing routine.
}
}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
7種自行編寫的範例設定各完成48次上傳,共336次暫存區/VRAM比較與84次空幀殘影清除檢查。5種設定通過25,700項投影邊界測試。5種Rust建置也完成48幀並輸出非零BGM。部分間隔超過4個PPU幀期限,平均fps無法證明無掉幀。此為模擬器驗證,非實機驗證。
實作與原始碼
kitaqgb/lib/wire3d_cgb.h:168
Project camera-space coordinates without subtracting/rotating the camera. Depth 8..255; outputs unchanged on rejection. Shared scratch: no ISR calls.
kitaqgb/lib/wire3d_cgb.c:552
w3dcgb_u8 Wire3DCGB_ProjectCameraPoint(w3dcgb_i16 x,w3dcgb_i16 y,w3dcgb_i16 z,w3dcgb_u8* sx,w3dcgb_u8* sy)
{
return w3dcgb_project_camera_space(x,y,z,sx,sy);
}Wire3DDMG_EndFrameNow
DMG EndFrameNow只省略起始等待新的VBlank,仍處理BG佇列、傳輸開關與dirty歷史。CGB EndFrameSparseNow也同步執行。Now仍須等待STAT存取時段、DMA完成及安全顯示切換。DMG更新不是原子的。CGB稀疏清除包含目前範圍及目標記憶體區兩幀前的範圍。低階CGB線段繪製須登記dirty。
語法
void Wire3DDMG_EndFrameNow();回傳值
無回傳值;上傳與必要同步完成後返回。
使用條件與限制
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
範例使用獨立創作的移動方盒、長條儀表與四音BGM。移動依audio_vblank經過的tick更新,儀表由簡短安全的VBlank處理更新。不要從ISR呼叫共用狀態的繪圖器。wire3d_audio_vblank.c將80位元組佇列置於固定WRAM,控制函式置於ROM區5。不要同時編譯一般audio_vblank.c。CGB範例使用WIRE3DCGB_STAGE_BANK2_ALLOCATION。8位元tick差須在255幀內讀取。
測量工具統計上傳與顯示完成後的標記。以PPU dot(每秒4,194,304;每幀70,224)記錄清除、投影、光柵化、上傳加顯示及外部等待,並報告平均、中位數、最大間隔與超時次數。上傳加顯示包含內部STAT/DMA/VBlank等待。不要直接比較CGB雙速CPU與DMG的原始週期。平均fps相同不能證明沒有超時。尚未實機驗證。
使用範例
#define WIRE3D_DMG_HEIGHT 88
#include "wire3d_dmg.h"
void draw_one() {
Wire3DDMG_BeginFrame();
Wire3DDMG_DrawLine2D(8,8,32,32);
Wire3DDMG_PutBgTile(18,16,128);
Wire3DDMG_EndFrameNow();
}這是呼叫部分的程式碼範例。放入完整程式前,請滿足所述初始化與緩衝區條件。
預期結果
7種自行編寫的範例設定各完成48次上傳,共336次暫存區/VRAM比較與84次空幀殘影清除檢查。5種設定通過25,700項投影邊界測試。5種Rust建置也完成48幀並輸出非零BGM。部分間隔超過4個PPU幀期限,平均fps無法證明無掉幀。此為模擬器驗證,非實機驗證。
實作與原始碼
kitaqgb/lib/wire3d_dmg.h:289
Same queue/gate/history lifecycle, without the initial fresh-VBlank wait. Synchronous STAT-safe upload; not an atomic swap. LCD must remain enabled.
kitaqgb/lib/wire3d_dmg.c:3826
void Wire3DDMG_EndFrameNow()
{
w3ddmg_flush_bg_queue();
if (w3ddmg_aux_transfer_enabled)
{
w3ddmg_transfer_stage_aux_asm();
}
if (w3ddmg_dirty_transfer_enabled)
{
w3ddmg_transfer_dirty_stage();
}
else
{
w3ddmg_transfer_stage_asm();
}
}wire3d_dmg.h — DMG 線框
使用高速繪圖路徑
視埠內的線條會逐步更新繪圖位址與像素位元,並將剩餘像素數與誤差保存在 CPU 暫存器中。這可避免逐像素計算圖塊座標,也會補畫連接像素,讓斜線相連。啟用遮蔽時,沿線取五個點判斷是否需要繪製;通過判定的線條使用相同高速路徑。遮罩各列以位元組為單位填入,同時保留邊界的部分位元。面的包圍矩形與五點剔除都是近似,不是精確的逐像素三角形或線條遮蔽。0、90、180、270 度旋轉先限制輸入範圍,再以座標交換及符號變更處理。整體遊戲效能也取決於頂點數、邊長、遮蔽與 VRAM 傳輸。請分別測量各操作與完成一張顯示影像所需的時間。
單色 3D 線段繪製。須提供模型頂點、邊、面,以及物件位置、旋轉與倍率。依初始化、影格開始、繪製、上傳的順序使用。物理另行處理。角度每圈 16 步;模型倍率 256 為一倍。
Vec3 儲存 x/y/z,Edge 儲存頂點索引 a/b,Face 儲存三角形索引 a/b/c。Model 的 vertices、edges、faces 指向這些陣列,各計數表示其長度。edge_faces 包含相鄰面索引 f0/f1,缺少的面以 FACE_NONE 表示。flags 中的 MODEL_HIDDEN_LINES 要求依面選擇邊。投影後的有號面積決定面朝向,因此頂點順序很重要。
Object 儲存模型參照、位置 x/y/z、角度 rx/ry/rz、scale_q8 與 visible。物件可共用模型,但繪製不會複製表或自動切換其 ROM 記憶體庫。整個繪製期間須保持參照資料可讀。CGB 的 Object 另有色彩索引。
高度 96 的 Model 另含 edge_masks 與 edge_mask_count。請提供依物件偏航選取之 16 位元邊遮罩的 RAM 表;不使用時將兩欄位皆設為零。
Wire3DDMG_BeginFrame
開始繪製影格並停用遮蔽檢查。
語法
void Wire3DDMG_BeginFrame();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_BeginFrame(); 清空暫存像素與遮蔽遮罩,並停用遮蔽篩選。不改變目前顯示的 VRAM 影格與待處理 BG 圖塊佇列。 WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_BeginFrame(); 僅停用遮蔽篩選。暫存區通常在傳輸期間清空,首次空白暫存區由 Init 提供。不丟棄尚未提交的影格,不清除遮罩,也不重設待處理 BG 寫入或 dirty 旗標。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
WIRE3D_DMG_HEIGHT 預設為 120。高度 96 請使用 wire3d_dmg_96.c。SelectEdgeMask 可用於高度 96;RotatePoint、DrawIndexedEdges、傳輸閘控與直接傳輸則需要高度 120。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DDMG_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
Wire3DDMG_SetCamera(8,0,0,0,0,0);
result[1]=Wire3DDMG_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=Wire3DDMG_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
Wire3DDMG_SetCamera(0,0,0,0,0,0);
Wire3DDMG_BeginFrame();
Wire3DDMG_DrawLine2D(8,8,56,8);
Wire3DDMG_DrawLine2D(56,8,56,40);
Wire3DDMG_DrawLine2D(56,40,8,40);
Wire3DDMG_DrawLine2D(8,40,8,8);
Wire3DDMG_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
Wire3DDMG_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
Wire3DDMG_PutBgTile(1,1,160);
Wire3DDMG_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_raster.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_dmg.h:144
Disable occlusion filtering only. Stage clearing normally happens during transfer, and Init supplies the first clean stage. This does not discard an unsubmitted frame, clear the mask, or reset pending BG writes/dirty flags.
kitaqgb/lib/wire3d_dmg.c:3379
void Wire3DDMG_BeginFrame()
{
/* The consuming stage transfer clears D000 as it uploads, so BeginFrame only
resets draw state. Wire3DDMG_Init supplies the first clean buffer. */
w3ddmg_occlusion_active = 0;
}Wire3DDMG_DrawIndexedEdges
依頂點與兩位元組邊索引配對,以整數倍率繪製線段模型。
語法
void Wire3DDMG_DrawIndexedEdges(const Wire3DDMG_Vec3* vertices, w3ddmg_u8 vertex_count, const w3ddmg_u8* edges, w3ddmg_u8 edge_count, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 scale);參數
vertices3D 頂點陣列。
vertex_count頂點陣列的項目數。
edges每條邊的頂點索引,採用所宣告的結構或位元組配對格式。
edge_count邊的數量。
x點或物件原點的世界座標 X 分量。
y點或物件原點的世界座標 Y 分量。
z點或物件原點的世界座標 Z 分量。
scale整數倍率;零視為一。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_DrawIndexedEdges(const Wire3DDMG_Vec3* vertices, w3ddmg_u8 vertex_count, const w3ddmg_u8* edges, w3ddmg_u8 edge_count, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 scale); 整數縮放與平移後繪製位元組配對的邊索引;倍率零表示一,沒有物件旋轉或面篩選。最多投影 24 個頂點。位元組偏移超過 255 後會回繞,因此最多提供 128 對邊。略過無效頂點 ID 或深度遭拒的端點,忽略 null 陣列。座標乘積與加總須可由 s16 表示。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
WIRE3D_DMG_HEIGHT 預設為 120。高度 96 請使用 wire3d_dmg_96.c。SelectEdgeMask 可用於高度 96;RotatePoint、DrawIndexedEdges、傳輸閘控與直接傳輸則需要高度 120。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Upload a main line and an auxiliary block separately; verify source consumption.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3DDMG_Vec3 vertices[2]={{-32,0,0},{32,0,0}};
__prg_rom u8 edge_pairs[2]={0,1};
u8* stage_byte;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DDMG_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
Wire3DDMG_BeginFrame();
Wire3DDMG_DrawIndexedEdges(vertices,2,edge_pairs,1,-64,104,96,1);
Wire3DDMG_TransferMainNow();
// Direct auxiliary transfer writes a separate tile after the main upload.
for(i=24;i<=31;i++) Wire3DDMG_DrawLine2D(40,i,47,i);
stage_byte=(u8*)0xD518;result[1]=*stage_byte;
Wire3DDMG_TransferAuxNow();result[2]=*stage_byte;
// Do not upload the consumed stage again.
result[7]=0xA55A; while(1) {}
}預期結果
以投影水平線與輔助 8×8 區塊示範直接傳輸;來源位元組被消耗時由 255 變為 0。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_direct.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_direct.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_dmg.h:253
Draw byte-pair edge indices after integer scaling and translation; scale zero means one, and there is no object rotation or face filtering. Project at most 24 vertices. Supply at most 128 edge pairs because byte offsets wrap after 255. Invalid vertex IDs/depth-rejected endpoints are skipped; null arrays are ignored. Keep coordinate products/sums representable as s16.
kitaqgb/lib/wire3d_dmg.c:4568
void Wire3DDMG_DrawIndexedEdges(const Wire3DDMG_Vec3* vertices, w3ddmg_u8 vertex_count, const w3ddmg_u8* edges, w3ddmg_u8 edge_count, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 scale)
{
w3ddmg_u8 i;
w3ddmg_u8 count;
if (vertices == 0) return;
if (edges == 0) return;
count = vertex_count;
if (count > WIRE3D_DMG_MODEL_VERTEX_LIMIT) count = WIRE3D_DMG_MODEL_VERTEX_LIMIT;
if (scale == 0) scale = 1;
i = 0;
while (i < count)
{
const Wire3DDMG_Vec3* v;
w3ddmg_i16 vx;
w3ddmg_i16 vy;
w3ddmg_i16 vz;
w3ddmg_u8 sx;
w3ddmg_u8 sy;
v = &vertices[(__safe_index w3ddmg_u8)i];
vx = (w3ddmg_i16)(x + (w3ddmg_i16)(v->x * scale));
vy = (w3ddmg_i16)(y + (w3ddmg_i16)(v->y * scale));
vz = (w3ddmg_i16)(z + (w3ddmg_i16)(v->z * scale));
if (w3ddmg_project_world(vx, vy, vz, &sx, &sy))
{
w3ddmg_screen_x[(__safe_index w3ddmg_u8)i] = sx;
w3ddmg_screen_y[(__safe_index w3ddmg_u8)i] = sy;
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 1;
}
else
{
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 0;
}
i = (w3ddmg_u8)(i + 1);
}
i = 0;
while (i < edge_count)
{
w3ddmg_u8 a;
w3ddmg_u8 b;
a = edges[(__safe_index w3ddmg_u8)((w3ddmg_u8)(i << 1))];
b = edges[(__safe_index w3ddmg_u8)((w3ddmg_u8)((i << 1) + 1))];
if ((a < count) && (b < count) &&
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)a] &&
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)b])
{
Wire3DDMG_DrawLine2D(
w3ddmg_screen_x[(__safe_index w3ddmg_u8)a],
w3ddmg_screen_y[(__safe_index w3ddmg_u8)a],
w3ddmg_screen_x[(__safe_index w3ddmg_u8)b],
w3ddmg_screen_y[(__safe_index w3ddmg_u8)b]);
}
i = (w3ddmg_u8)(i + 1);
}
}Wire3DDMG_DrawLine2D
在暫存區繪製包含兩端點、四連通的畫面空間線段。
語法
void Wire3DDMG_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by);參數
ax頂點 A 的 X 座標,以視埠像素為單位。
ay頂點 A 的 Y 座標,以視埠像素為單位。
bx頂點 B 的 X 座標,以視埠像素為單位。
by頂點 B 的 Y 座標,以視埠像素為單位。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by); 在 128×96 暫存區繪製包含端點的連通線。DrawScene 期間採用五點取樣的粗略遮蔽剔除,其他情況直接繪製。須提供視埠座標。VRAM 僅由 EndFrame 更新。 WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by); 啟用 dirty 傳輸時先標記圖塊外接矩形,再繪製暫存連通線。場景繪製可能利用五個遮罩取樣點剔除該線。須提供 128×120 視埠端點;低階像素邊界檢查不會對線段做幾何裁切。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
WIRE3D_DMG_HEIGHT 預設為 120。高度 96 請使用 wire3d_dmg_96.c。SelectEdgeMask 可用於高度 96;RotatePoint、DrawIndexedEdges、傳輸閘控與直接傳輸則需要高度 120。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DDMG_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
Wire3DDMG_SetCamera(8,0,0,0,0,0);
result[1]=Wire3DDMG_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=Wire3DDMG_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
Wire3DDMG_SetCamera(0,0,0,0,0,0);
Wire3DDMG_BeginFrame();
Wire3DDMG_DrawLine2D(8,8,56,8);
Wire3DDMG_DrawLine2D(56,8,56,40);
Wire3DDMG_DrawLine2D(56,40,8,40);
Wire3DDMG_DrawLine2D(8,40,8,8);
Wire3DDMG_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
Wire3DDMG_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
Wire3DDMG_PutBgTile(1,1,160);
Wire3DDMG_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_raster.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_dmg.h:237
Mark the bounding tile rectangle when dirty transfer is enabled, then draw a connected staged line. Scene drawing may reject it using five mask samples. Supply 128x120 viewport endpoints; low-level pixel bounds checks do not clip the segment geometrically.
kitaqgb/lib/wire3d_dmg.c:3423
void Wire3DDMG_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by)
{
w3ddmg_mark_line_dirty(ax, ay, bx, by);
if (w3ddmg_occlusion_active)
{
w3ddmg_line_stage_masked_c(ax, ay, bx, by);
return;
}
w3ddmg_line_x0 = ax;
w3ddmg_line_y0 = ay;
w3ddmg_line_x1 = bx;
w3ddmg_line_y1 = by;
if (ax < 128 && bx < 128 && ay < WIRE3D_DMG_SCREEN_H && by < WIRE3D_DMG_SCREEN_H)
w3ddmg_line_inside_asm();
else
w3ddmg_line_stage_asm();
}Wire3DDMG_DrawLine3D
投影兩個世界座標端點,並在其間繪製線段。
語法
void Wire3DDMG_DrawLine3D(w3ddmg_i16 ax, w3ddmg_i16 ay, w3ddmg_i16 az, w3ddmg_i16 bx, w3ddmg_i16 by, w3ddmg_i16 bz);參數
ax起點的世界座標 X 分量。
ay起點的世界座標 Y 分量。
az起點的世界座標 Z 分量。
bx終點的世界座標 X 分量。
by終點的世界座標 Y 分量。
bz終點的世界座標 Z 分量。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_DrawLine3D(w3ddmg_i16 ax, w3ddmg_i16 ay, w3ddmg_i16 az, w3ddmg_i16 bx, w3ddmg_i16 by, w3ddmg_i16 bz); 投影兩個世界座標端點,僅在兩者均通過深度範圍時繪製。不求跨界線段與近/遠平面的交點;投影後端點各自限制於畫面邊緣。 WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_DrawLine3D(w3ddmg_i16 ax, w3ddmg_i16 ay, w3ddmg_i16 az, w3ddmg_i16 bx, w3ddmg_i16 by, w3ddmg_i16 bz); 投影兩個世界座標端點,僅在兩者均通過深度範圍時繪製。不求跨界線段與近/遠平面的交點;投影後端點各自限制於畫面邊緣。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
WIRE3D_DMG_HEIGHT 預設為 120。高度 96 請使用 wire3d_dmg_96.c。SelectEdgeMask 可用於高度 96;RotatePoint、DrawIndexedEdges、傳輸閘控與直接傳輸則需要高度 120。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DDMG_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
Wire3DDMG_SetCamera(8,0,0,0,0,0);
result[1]=Wire3DDMG_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=Wire3DDMG_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
Wire3DDMG_SetCamera(0,0,0,0,0,0);
Wire3DDMG_BeginFrame();
Wire3DDMG_DrawLine2D(8,8,56,8);
Wire3DDMG_DrawLine2D(56,8,56,40);
Wire3DDMG_DrawLine2D(56,40,8,40);
Wire3DDMG_DrawLine2D(8,40,8,8);
Wire3DDMG_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
Wire3DDMG_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
Wire3DDMG_PutBgTile(1,1,160);
Wire3DDMG_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_raster.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_dmg.h:226
Project both world endpoints and draw only when both pass the depth range. Do not intersect a crossing segment with near/far planes; projected endpoints are independently clamped to the screen edges.
kitaqgb/lib/wire3d_dmg.c:3546
void Wire3DDMG_DrawLine3D(w3ddmg_i16 ax, w3ddmg_i16 ay, w3ddmg_i16 az, w3ddmg_i16 bx, w3ddmg_i16 by, w3ddmg_i16 bz)
{
w3ddmg_u8 sx0;
w3ddmg_u8 sy0;
w3ddmg_u8 sx1;
w3ddmg_u8 sy1;
if (w3ddmg_project_world(ax, ay, az, &sx0, &sy0) == 0) return;
if (w3ddmg_project_world(bx, by, bz, &sx1, &sy1) == 0) return;
Wire3DDMG_DrawLine2D(sx0, sy0, sx1, sy1);
}Wire3DDMG_DrawModel
以指定位置與旋轉,按原倍率繪製頂點與邊組成的模型。
語法
void Wire3DDMG_DrawModel(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz);參數
model包含頂點、邊、面陣列及數量的模型;呼叫期間須保持各表可讀。
x點或物件原點的世界座標 X 分量。
y點或物件原點的世界座標 Y 分量。
z點或物件原點的世界座標 Z 分量。
rx繞 X 軸旋轉;十六步為一整圈。
ry繞 Y 軸旋轉;十六步為一整圈。
rz繞 Z 軸旋轉;十六步為一整圈。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_DrawModel(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz); 以倍率 256 委派給 DrawModelScaled,按原大小繪製模型。 WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_DrawModel(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz); 以倍率 256 委派給 DrawModelScaled,按原大小繪製模型。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
WIRE3D_DMG_HEIGHT 預設為 120。高度 96 請使用 wire3d_dmg_96.c。SelectEdgeMask 可用於高度 96;RotatePoint、DrawIndexedEdges、傳輸閘控與直接傳輸則需要高度 120。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3DDMG_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom Wire3DDMG_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
Wire3DDMG_Model cube;
Wire3DDMG_Object objects[2];
s16 px; s16 py; s16 pz;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DDMG_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;
Wire3DDMG_BeginFrame();
// Upper pair: direct model calls at unity and half scale.
Wire3DDMG_DrawModel(&cube,-32,32,96,0,0,0);
Wire3DDMG_DrawModelScaled(&cube,32,32,96,0,0,0,128);
// Lower pair: the caller owns both object records and the model tables.
for(i=0;i<2;i++) {
objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
objects[i].y=-32;objects[i].z=96;
objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
}
Wire3DDMG_DrawScene(objects,2);
// Numeric checks cover the operation supplied by this viewport profile.
px=16;py=0;pz=0;Wire3DDMG_RotatePoint(&px,&py,&pz,0,4,0);
result[1]=px; result[2]=py; result[3]=pz;
Wire3DDMG_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
原倍率與半倍率模型顯示在相同倍率的物件陣列場景上方,用以示範投影與縮放。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_models.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_dmg.h:164
Draw an unscaled model by delegating to DrawModelScaled with scale 256.
kitaqgb/lib/wire3d_dmg.c:3565
void Wire3DDMG_DrawModel(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz)
{
Wire3DDMG_DrawModelScaled(model, x, y, z, rx, ry, rz, 256);
}kitaqgb/lib/wire3d_dmg.c:3563
void Wire3DDMG_DrawModel(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz)
{
Wire3DDMG_DrawModelScaled(model, x, y, z, rx, ry, rz, 256);
}Wire3DDMG_DrawModelScaled
縮放模型,依 Y/X/Z 順序旋轉,平移並投影頂點,再繪製邊。
語法
void Wire3DDMG_DrawModelScaled(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz, w3ddmg_i16 scale_q8);參數
model包含頂點、邊、面陣列及數量的模型;呼叫期間須保持各表可讀。
x點或物件原點的世界座標 X 分量。
y點或物件原點的世界座標 Y 分量。
z點或物件原點的世界座標 Z 分量。
rx繞 X 軸旋轉;十六步為一整圈。
ry繞 Y 軸旋轉;十六步為一整圈。
rz繞 Z 軸旋轉;十六步為一整圈。
scale_q8倍率,以 256 表示一倍;非正值也視為一倍。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_DrawModelScaled(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz, w3ddmg_i16 scale_q8); 縮放最多 24 個頂點,依 Y/X/Z 順序旋轉、平移並投影,再以偏航遮罩與可選的正面篩選繪製最多 16 條邊。非正倍率轉為一倍(256)。忽略 null 模型/頂點/邊指標;參照的表須保持可讀。縮放乘積與平移結果須在有號 16 位元範圍內。跨越深度邊界的邊會捨棄,不會裁切。 WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_DrawModelScaled(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz, w3ddmg_i16 scale_q8); 縮放最多 24 個頂點,旋轉 Y/X/Z、平移並投影,再遍歷 edge_count(位元組型別的計數)的全部項目,可選擇依相鄰面篩選。面暫存最多 16 個;邊表須包含所有宣告項目。非正倍率視為 256。忽略 null 模型/頂點/邊指標。乘積與平移結果須保持在有號 16 位元範圍內;跨越深度邊界的邊會捨棄。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
WIRE3D_DMG_HEIGHT 預設為 120。高度 96 請使用 wire3d_dmg_96.c。SelectEdgeMask 可用於高度 96;RotatePoint、DrawIndexedEdges、傳輸閘控與直接傳輸則需要高度 120。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3DDMG_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom Wire3DDMG_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
Wire3DDMG_Model cube;
Wire3DDMG_Object objects[2];
s16 px; s16 py; s16 pz;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DDMG_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;
Wire3DDMG_BeginFrame();
// Upper pair: direct model calls at unity and half scale.
Wire3DDMG_DrawModel(&cube,-32,32,96,0,0,0);
Wire3DDMG_DrawModelScaled(&cube,32,32,96,0,0,0,128);
// Lower pair: the caller owns both object records and the model tables.
for(i=0;i<2;i++) {
objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
objects[i].y=-32;objects[i].z=96;
objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
}
Wire3DDMG_DrawScene(objects,2);
// Numeric checks cover the operation supplied by this viewport profile.
px=16;py=0;pz=0;Wire3DDMG_RotatePoint(&px,&py,&pz,0,4,0);
result[1]=px; result[2]=py; result[3]=pz;
Wire3DDMG_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
原倍率與半倍率模型顯示在相同倍率的物件陣列場景上方,用以示範投影與縮放。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_models.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_dmg.h:170
Scale up to 24 vertices, rotate Y/X/Z, translate and project, then traverse all edge_count entries (a byte count) with optional adjacent-face filtering. Face scratch is capped at 16; edge tables must contain all declared entries. Nonpositive scale means 256. Null model/vertex/edge pointers are ignored. Keep products/translations in signed 16-bit range; depth-crossing edges are dropped.
kitaqgb/lib/wire3d_dmg.c:3710
void Wire3DDMG_DrawModelScaled(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz, w3ddmg_i16 scale_q8)
{
w3ddmg_u8 i;
w3ddmg_u8 count;
w3ddmg_u8 edge_count;
w3ddmg_u8 face_count;
if (model == 0) return;
if (model->vertices == 0) return;
if (model->edges == 0) return;
if (scale_q8 <= 0) scale_q8 = 256;
count = model->vertex_count;
if (count > WIRE3D_DMG_MODEL_VERTEX_LIMIT) count = WIRE3D_DMG_MODEL_VERTEX_LIMIT;
i = 0;
while (i < count)
{
const Wire3DDMG_Vec3* v;
w3ddmg_i16 vx;
w3ddmg_i16 vy;
w3ddmg_i16 vz;
w3ddmg_u8 sx;
w3ddmg_u8 sy;
v = &model->vertices[(__safe_index w3ddmg_u8)i];
vx = (w3ddmg_i16)((v->x * scale_q8) >> 8);
vy = (w3ddmg_i16)((v->y * scale_q8) >> 8);
vz = (w3ddmg_i16)((v->z * scale_q8) >> 8);
w3ddmg_rotate_y(&vx, &vz, ry);
w3ddmg_rotate_x(&vy, &vz, rx);
w3ddmg_rotate_z(&vx, &vy, rz);
vx = (w3ddmg_i16)(vx + x);
vy = (w3ddmg_i16)(vy + y);
vz = (w3ddmg_i16)(vz + z);
if (w3ddmg_project_world(vx, vy, vz, &sx, &sy))
{
w3ddmg_screen_x[(__safe_index w3ddmg_u8)i] = sx;
w3ddmg_screen_y[(__safe_index w3ddmg_u8)i] = sy;
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 1;
}
else
{
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 0;
}
i = (w3ddmg_u8)(i + 1);
}
face_count = model->face_count;
if (face_count > WIRE3D_DMG_MODEL_FACE_LIMIT) face_count = WIRE3D_DMG_MODEL_FACE_LIMIT;
if ((model->flags & WIRE3D_DMG_MODEL_HIDDEN_LINES) && (model->faces != 0) && (model->edge_faces != 0))
{
w3ddmg_build_face_visibility(model, count, face_count);
}
edge_count = model->edge_count;
i = 0;
while (i < edge_count)
{
const Wire3DDMG_Edge* e;
e = &model->edges[(__safe_index w3ddmg_u8)i];
if ((e->a < count) && (e->b < count))
{
if (w3ddmg_screen_visible[(__safe_index w3ddmg_u8)e->a] &&
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)e->b] &&
w3ddmg_is_edge_visible(model, i, face_count))
{
Wire3DDMG_DrawLine2D(
w3ddmg_screen_x[(__safe_index w3ddmg_u8)e->a],
w3ddmg_screen_y[(__safe_index w3ddmg_u8)e->a],
w3ddmg_screen_x[(__safe_index w3ddmg_u8)e->b],
w3ddmg_screen_y[(__safe_index w3ddmg_u8)e->b]);
}
}
i = (w3ddmg_u8)(i + 1);
}
}kitaqgb/lib/wire3d_dmg.c:3703
void Wire3DDMG_DrawModelScaled(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz, w3ddmg_i16 scale_q8)
{
w3ddmg_u8 i;
w3ddmg_u8 count;
w3ddmg_u8 edge_count;
w3ddmg_u8 face_count;
if (model == 0) return;
if (model->vertices == 0) return;
if (model->edges == 0) return;
if (scale_q8 <= 0) scale_q8 = 256;
count = model->vertex_count;
if (count > WIRE3D_DMG_MODEL_VERTEX_LIMIT) count = WIRE3D_DMG_MODEL_VERTEX_LIMIT;
i = 0;
while (i < count)
{
const Wire3DDMG_Vec3* v;
w3ddmg_i16 vx;
w3ddmg_i16 vy;
w3ddmg_i16 vz;
w3ddmg_u8 sx;
w3ddmg_u8 sy;
v = &model->vertices[(__safe_index w3ddmg_u8)i];
vx = (w3ddmg_i16)((v->x * scale_q8) >> 8);
vy = (w3ddmg_i16)((v->y * scale_q8) >> 8);
vz = (w3ddmg_i16)((v->z * scale_q8) >> 8);
w3ddmg_rotate_y(&vx, &vz, (w3ddmg_i8)ry);
w3ddmg_rotate_x(&vy, &vz, (w3ddmg_i8)rx);
w3ddmg_rotate_z(&vx, &vy, (w3ddmg_i8)rz);
vx = (w3ddmg_i16)(vx + x);
vy = (w3ddmg_i16)(vy + y);
vz = (w3ddmg_i16)(vz + z);
if (w3ddmg_project_world(vx, vy, vz, &sx, &sy))
{
w3ddmg_screen_x[(__safe_index w3ddmg_u8)i] = sx;
w3ddmg_screen_y[(__safe_index w3ddmg_u8)i] = sy;
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 1;
}
else
{
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 0;
}
i = (w3ddmg_u8)(i + 1);
}
face_count = model->face_count;
if (face_count > WIRE3D_DMG_MODEL_FACE_LIMIT) face_count = WIRE3D_DMG_MODEL_FACE_LIMIT;
if ((model->flags & WIRE3D_DMG_MODEL_HIDDEN_LINES) && (model->faces != 0) && (model->edge_faces != 0))
{
w3ddmg_build_face_visibility(model, count, face_count);
}
edge_count = model->edge_count;
if (edge_count > WIRE3D_DMG_MODEL_EDGE_LIMIT) edge_count = WIRE3D_DMG_MODEL_EDGE_LIMIT;
w3ddmg_build_edge_flags(model, edge_count, face_count, rx, ry, rz);
i = 0;
while (i < edge_count)
{
const Wire3DDMG_Edge* e;
e = &model->edges[(__safe_index w3ddmg_u8)i];
if ((e->a < count) && (e->b < count))
{
if (w3ddmg_screen_visible[(__safe_index w3ddmg_u8)e->a] &&
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)e->b] &&
w3ddmg_edge_flags[(__safe_index w3ddmg_u8)i])
{
Wire3DDMG_DrawLine2D(
w3ddmg_screen_x[(__safe_index w3ddmg_u8)e->a],
w3ddmg_screen_y[(__safe_index w3ddmg_u8)e->a],
w3ddmg_screen_x[(__safe_index w3ddmg_u8)e->b],
w3ddmg_screen_y[(__safe_index w3ddmg_u8)e->b]);
}
}
i = (w3ddmg_u8)(i + 1);
}
}Wire3DDMG_DrawScene
由近至遠繪製最多八個物件,以較近的面遮住後續邊。
語法
void Wire3DDMG_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count);參數
objects包含位置、旋轉、倍率與可見旗標的物件陣列。
count提供的陣列項目數;處理上限請參閱各操作的說明。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count); 最多處理前八個物件,依變換後原點深度由近至遠排序。繪製可見且有效的模型,再標記其正面外接矩形,以拒絕後續取樣點全部被遮住的線段。這是物件間遮蔽的近似,不是深度緩衝區。會清空自身遮罩,但保留既有暫存像素。忽略 null 陣列;物件與其資料須保持可讀。 WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count); 依相機深度將最多八個物件原點由近至遠排序。繪製可見且有效的模型,並為後續物件標記正面外接矩形。排序後第一個槽略過遮罩檢查,最後一個則不需要新遮蔽物。這是粗略的線段剔除,不是深度緩衝區。忽略 null/空輸入;遍歷時呼叫端資料與目前投影快取須維持有效。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
WIRE3D_DMG_HEIGHT 預設為 120。高度 96 請使用 wire3d_dmg_96.c。SelectEdgeMask 可用於高度 96;RotatePoint、DrawIndexedEdges、傳輸閘控與直接傳輸則需要高度 120。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3DDMG_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom Wire3DDMG_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
Wire3DDMG_Model cube;
Wire3DDMG_Object objects[2];
s16 px; s16 py; s16 pz;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DDMG_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;
Wire3DDMG_BeginFrame();
// Upper pair: direct model calls at unity and half scale.
Wire3DDMG_DrawModel(&cube,-32,32,96,0,0,0);
Wire3DDMG_DrawModelScaled(&cube,32,32,96,0,0,0,128);
// Lower pair: the caller owns both object records and the model tables.
for(i=0;i<2;i++) {
objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
objects[i].y=-32;objects[i].z=96;
objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
}
Wire3DDMG_DrawScene(objects,2);
// Numeric checks cover the operation supplied by this viewport profile.
px=16;py=0;pz=0;Wire3DDMG_RotatePoint(&px,&py,&pz,0,4,0);
result[1]=px; result[2]=py; result[3]=pz;
Wire3DDMG_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
原倍率與半倍率模型顯示在相同倍率的物件陣列場景上方,用以示範投影與縮放。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_models.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_dmg.h:201
Sort at most eight object origins by camera depth, near to far. Draw visible valid models and mark front-face bounding rectangles for later objects. The first sorted slot bypasses mask tests and the last needs no new occluder. This is coarse line rejection, not a depth buffer. Null/empty input is ignored; caller data and the current projection cache must remain valid during traversal.
kitaqgb/lib/wire3d_dmg.c:3461
void Wire3DDMG_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count)
{
w3ddmg_u8 scene_count;
w3ddmg_u8 i;
if (objects == 0) return;
scene_count = count;
if (scene_count > WIRE3D_DMG_SCENE_OBJECT_LIMIT) scene_count = WIRE3D_DMG_SCENE_OBJECT_LIMIT;
if (scene_count == 0) return;
i = 0;
while (i < scene_count)
{
w3ddmg_scene_order[(__safe_index w3ddmg_u8)i] = i;
w3ddmg_scene_depth[(__safe_index w3ddmg_u8)i] = w3ddmg_scene_object_depth(&objects[(__safe_index w3ddmg_u8)i]);
i = (w3ddmg_u8)(i + 1);
}
i = 0;
while (i < scene_count)
{
w3ddmg_u8 j;
j = (w3ddmg_u8)(i + 1);
while (j < scene_count)
{
w3ddmg_u8 oi;
w3ddmg_u8 oj;
oi = w3ddmg_scene_order[(__safe_index w3ddmg_u8)i];
oj = w3ddmg_scene_order[(__safe_index w3ddmg_u8)j];
if (w3ddmg_scene_depth[(__safe_index w3ddmg_u8)oj] < w3ddmg_scene_depth[(__safe_index w3ddmg_u8)oi])
{
w3ddmg_scene_order[(__safe_index w3ddmg_u8)i] = oj;
w3ddmg_scene_order[(__safe_index w3ddmg_u8)j] = oi;
}
j = (w3ddmg_u8)(j + 1);
}
i = (w3ddmg_u8)(i + 1);
}
w3ddmg_clear_occlusion_mask();
w3ddmg_occlusion_active = 0;
i = 0;
while (i < scene_count)
{
Wire3DDMG_Object* obj;
obj = &objects[(__safe_index w3ddmg_u8)w3ddmg_scene_order[(__safe_index w3ddmg_u8)i]];
if ((obj->visible != 0) && (obj->model != 0))
{
w3ddmg_occlusion_active = i == 0 ? 0 : 1;
Wire3DDMG_DrawModelScaled(obj->model, obj->x, obj->y, obj->z, obj->rx, obj->ry, obj->rz, obj->scale_q8);
if ((w3ddmg_u8)(i + 1) < scene_count)
{
w3ddmg_mark_model_occluder(obj->model);
}
}
i = (w3ddmg_u8)(i + 1);
}
w3ddmg_occlusion_active = 0;
}Wire3DDMG_EndFrame
將待處理背景寫入與暫存繪圖提交至 VRAM。
語法
void Wire3DDMG_EndFrame();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_EndFrame(); 等待下一次 VBlank,送出待處理的 BG 地圖寫入,再輪詢可存取時段,將暫存區複製至 VRAM。複製會消耗暫存像素。傳輸可能超出 VBlank;這不是原子影格交換。 WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_EndFrame(); 等待下一次 VBlank 並送出 BG 寫入,再依設定先消耗輔助條帶,然後上傳 dirty 圖塊或整個主暫存區。輔助/主來源重疊,因此順序很重要。STAT 輪詢會跨越可存取時段持續進行;更新不一定能在一次 VBlank 內完成。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
WIRE3D_DMG_HEIGHT 預設為 120。高度 96 請使用 wire3d_dmg_96.c。SelectEdgeMask 可用於高度 96;RotatePoint、DrawIndexedEdges、傳輸閘控與直接傳輸則需要高度 120。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DDMG_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
Wire3DDMG_SetCamera(8,0,0,0,0,0);
result[1]=Wire3DDMG_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=Wire3DDMG_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
Wire3DDMG_SetCamera(0,0,0,0,0,0);
Wire3DDMG_BeginFrame();
Wire3DDMG_DrawLine2D(8,8,56,8);
Wire3DDMG_DrawLine2D(56,8,56,40);
Wire3DDMG_DrawLine2D(56,40,8,40);
Wire3DDMG_DrawLine2D(8,40,8,8);
Wire3DDMG_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
Wire3DDMG_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
Wire3DDMG_PutBgTile(1,1,160);
Wire3DDMG_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_raster.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_dmg.h:286
Wait for the next VBlank and flush BG writes, then optionally consume the auxiliary strips before uploading either dirty tiles or the entire main stage. Auxiliary/main source overlap makes that ordering significant. STAT polling continues across access windows; the update need not fit one VBlank.
kitaqgb/lib/wire3d_dmg.c:3819
void Wire3DDMG_EndFrame()
{
w3ddmg_wait_vblank_start();
Wire3DDMG_EndFrameNow();
}Wire3DDMG_EraseModelFaces
投影模型朝前的三角形,並擦除其內部暫存像素。
語法
void Wire3DDMG_EraseModelFaces(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz, w3ddmg_i16 scale_q8);參數
model包含頂點、邊、面陣列及數量的模型;呼叫期間須保持各表可讀。
x點或物件原點的世界座標 X 分量。
y點或物件原點的世界座標 Y 分量。
z點或物件原點的世界座標 Z 分量。
rx繞 X 軸旋轉;十六步為一整圈。
ry繞 Y 軸旋轉;十六步為一整圈。
rz繞 Z 軸旋轉;十六步為一整圈。
scale_q8倍率,以 256 表示一倍;非正值也視為一倍。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_EraseModelFaces(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz, w3ddmg_i16 scale_q8); 對具有隱線旗標與面資料的模型,投影最多 24 個頂點,並從暫存區擦除朝前三角形的內部。非正倍率表示 256(一倍)。最多考慮 16 個面,跨越深度邊界的面會略過。亦會替換共用投影快取,但不更新 VRAM。 WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_EraseModelFaces(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz, w3ddmg_i16 scale_q8); 對具有隱線旗標與面資料的模型,投影最多 24 個頂點,並從暫存區擦除朝前三角形的內部。非正倍率表示 256(一倍)。最多考慮 16 個面,跨越深度邊界的面會略過。亦會替換共用投影快取,但不更新 VRAM。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
WIRE3D_DMG_HEIGHT 預設為 120。高度 96 請使用 wire3d_dmg_96.c。SelectEdgeMask 可用於高度 96;RotatePoint、DrawIndexedEdges、傳輸閘控與直接傳輸則需要高度 120。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Erase a screen triangle and a projected model face from separate filled panels.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3DDMG_Vec3 vertices[4]={{-24,-24,0},{24,-24,0},{24,24,0},{-24,24,0}};
__prg_rom Wire3DDMG_Edge edges[4]={{0,1},{1,2},{2,3},{3,0}};
__prg_rom Wire3DDMG_Face faces[2]={{0,2,1},{0,3,2}};
Wire3DDMG_Model plane;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DDMG_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
plane.vertices=vertices;plane.edges=edges;plane.faces=faces;plane.edge_faces=0;
plane.vertex_count=4;plane.edge_count=4;plane.face_count=2;plane.flags=1;
Wire3DDMG_BeginFrame();
// Separate panels show a direct screen triangle and a projected square face.
for(i=8;i<=32;i++) Wire3DDMG_DrawLine2D(8,i,32,i);
for(i=36;i<=84;i++) Wire3DDMG_DrawLine2D(40,i,88,i);
Wire3DDMG_EraseTriangle2D(12,12,28,12,12,28);
Wire3DDMG_EraseModelFaces(&plane,0,0,64,0,0,0,256);
Wire3DDMG_EndFrame(); result[7]=0xA55A; while(1) {}
}預期結果
投影後的面會擦除填滿區域,可看出保留與清除的部分。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_faces.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_faces.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_dmg.h:179
Project up to 24 vertices and erase front-facing triangle interiors from the stage for a model with hidden-line flags and face data. Nonpositive scale means 256 (unity). Up to 16 faces are considered; depth-crossing faces are skipped. This also replaces shared projection caches, but does not update VRAM.
kitaqgb/lib/wire3d_dmg.c:3581
void Wire3DDMG_EraseModelFaces(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz, w3ddmg_i16 scale_q8)
{
w3ddmg_u8 i;
w3ddmg_u8 count;
w3ddmg_u8 face_count;
if (model == 0) return;
if (model->vertices == 0) return;
if (model->faces == 0) return;
if ((model->flags & WIRE3D_DMG_MODEL_HIDDEN_LINES) == 0) return;
if (scale_q8 <= 0) scale_q8 = 256;
count = model->vertex_count;
if (count > WIRE3D_DMG_MODEL_VERTEX_LIMIT) count = WIRE3D_DMG_MODEL_VERTEX_LIMIT;
i = 0;
while (i < count)
{
const Wire3DDMG_Vec3* v;
w3ddmg_i16 vx;
w3ddmg_i16 vy;
w3ddmg_i16 vz;
w3ddmg_u8 sx;
w3ddmg_u8 sy;
v = &model->vertices[(__safe_index w3ddmg_u8)i];
vx = (w3ddmg_i16)((v->x * scale_q8) >> 8);
vy = (w3ddmg_i16)((v->y * scale_q8) >> 8);
vz = (w3ddmg_i16)((v->z * scale_q8) >> 8);
w3ddmg_rotate_y(&vx, &vz, ry);
w3ddmg_rotate_x(&vy, &vz, rx);
w3ddmg_rotate_z(&vx, &vy, rz);
vx = (w3ddmg_i16)(vx + x);
vy = (w3ddmg_i16)(vy + y);
vz = (w3ddmg_i16)(vz + z);
if (w3ddmg_project_world(vx, vy, vz, &sx, &sy))
{
w3ddmg_screen_x[(__safe_index w3ddmg_u8)i] = sx;
w3ddmg_screen_y[(__safe_index w3ddmg_u8)i] = sy;
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 1;
}
else
{
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 0;
}
i = (w3ddmg_u8)(i + 1);
}
face_count = model->face_count;
if (face_count > WIRE3D_DMG_MODEL_FACE_LIMIT) face_count = WIRE3D_DMG_MODEL_FACE_LIMIT;
w3ddmg_build_face_visibility(model, count, face_count);
i = 0;
while (i < face_count)
{
const Wire3DDMG_Face* f;
f = &model->faces[(__safe_index w3ddmg_u8)i];
if (w3ddmg_face_visible[(__safe_index w3ddmg_u8)i] &&
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)f->a] &&
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)f->b] &&
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)f->c])
{
w3ddmg_clear_triangle(
w3ddmg_screen_x[(__safe_index w3ddmg_u8)f->a],
w3ddmg_screen_y[(__safe_index w3ddmg_u8)f->a],
w3ddmg_screen_x[(__safe_index w3ddmg_u8)f->b],
w3ddmg_screen_y[(__safe_index w3ddmg_u8)f->b],
w3ddmg_screen_x[(__safe_index w3ddmg_u8)f->c],
w3ddmg_screen_y[(__safe_index w3ddmg_u8)f->c]);
}
i = (w3ddmg_u8)(i + 1);
}
}kitaqgb/lib/wire3d_dmg.c:3579
void Wire3DDMG_EraseModelFaces(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz, w3ddmg_i16 scale_q8)
{
w3ddmg_u8 i;
w3ddmg_u8 count;
w3ddmg_u8 face_count;
if (model == 0) return;
if (model->vertices == 0) return;
if (model->faces == 0) return;
if ((model->flags & WIRE3D_DMG_MODEL_HIDDEN_LINES) == 0) return;
if (scale_q8 <= 0) scale_q8 = 256;
count = model->vertex_count;
if (count > WIRE3D_DMG_MODEL_VERTEX_LIMIT) count = WIRE3D_DMG_MODEL_VERTEX_LIMIT;
i = 0;
while (i < count)
{
const Wire3DDMG_Vec3* v;
w3ddmg_i16 vx;
w3ddmg_i16 vy;
w3ddmg_i16 vz;
w3ddmg_u8 sx;
w3ddmg_u8 sy;
v = &model->vertices[(__safe_index w3ddmg_u8)i];
vx = (w3ddmg_i16)((v->x * scale_q8) >> 8);
vy = (w3ddmg_i16)((v->y * scale_q8) >> 8);
vz = (w3ddmg_i16)((v->z * scale_q8) >> 8);
w3ddmg_rotate_y(&vx, &vz, (w3ddmg_i8)ry);
w3ddmg_rotate_x(&vy, &vz, (w3ddmg_i8)rx);
w3ddmg_rotate_z(&vx, &vy, (w3ddmg_i8)rz);
vx = (w3ddmg_i16)(vx + x);
vy = (w3ddmg_i16)(vy + y);
vz = (w3ddmg_i16)(vz + z);
if (w3ddmg_project_world(vx, vy, vz, &sx, &sy))
{
w3ddmg_screen_x[(__safe_index w3ddmg_u8)i] = sx;
w3ddmg_screen_y[(__safe_index w3ddmg_u8)i] = sy;
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 1;
}
else
{
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 0;
}
i = (w3ddmg_u8)(i + 1);
}
face_count = model->face_count;
if (face_count > WIRE3D_DMG_MODEL_FACE_LIMIT) face_count = WIRE3D_DMG_MODEL_FACE_LIMIT;
w3ddmg_build_face_visibility(model, count, face_count);
i = 0;
while (i < face_count)
{
const Wire3DDMG_Face* f;
f = &model->faces[(__safe_index w3ddmg_u8)i];
if (w3ddmg_face_visible[(__safe_index w3ddmg_u8)i] &&
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)f->a] &&
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)f->b] &&
w3ddmg_screen_visible[(__safe_index w3ddmg_u8)f->c])
{
w3ddmg_clear_triangle(
w3ddmg_screen_x[(__safe_index w3ddmg_u8)f->a],
w3ddmg_screen_y[(__safe_index w3ddmg_u8)f->a],
w3ddmg_screen_x[(__safe_index w3ddmg_u8)f->b],
w3ddmg_screen_y[(__safe_index w3ddmg_u8)f->b],
w3ddmg_screen_x[(__safe_index w3ddmg_u8)f->c],
w3ddmg_screen_y[(__safe_index w3ddmg_u8)f->c]);
}
i = (w3ddmg_u8)(i + 1);
}
}Wire3DDMG_EraseSpan2D
在暫存區的一列中擦除包含兩端點的水平跨度。
語法
void Wire3DDMG_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1);參數
y要擦除之列的像素 Y 座標。
x0較小的 X 端點,以視埠像素為單位;排序與裁切依此操作的注意事項。
x1較大的 X 端點,以視埠像素為單位;排序與裁切依此操作的注意事項。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1); 排序 X 端點並擦除包含端點的暫存跨度。兩端點皆須在 0..127;無效 Y 會被忽略。此常式不代為裁切 X。 WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1); 排序 X 端點並擦除包含端點的暫存跨度。兩端點皆須在 0..127;無效 Y 會被忽略。此常式不代為裁切 X。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
WIRE3D_DMG_HEIGHT 預設為 120。高度 96 請使用 wire3d_dmg_96.c。SelectEdgeMask 可用於高度 96;RotatePoint、DrawIndexedEdges、傳輸閘控與直接傳輸則需要高度 120。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DDMG_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
Wire3DDMG_SetCamera(8,0,0,0,0,0);
result[1]=Wire3DDMG_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=Wire3DDMG_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
Wire3DDMG_SetCamera(0,0,0,0,0,0);
Wire3DDMG_BeginFrame();
Wire3DDMG_DrawLine2D(8,8,56,8);
Wire3DDMG_DrawLine2D(56,8,56,40);
Wire3DDMG_DrawLine2D(56,40,8,40);
Wire3DDMG_DrawLine2D(8,40,8,8);
Wire3DDMG_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
Wire3DDMG_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
Wire3DDMG_PutBgTile(1,1,160);
Wire3DDMG_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_raster.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_dmg.h:187
Order the X endpoints and erase the inclusive staged span. Both endpoints must be in 0..127; invalid Y is ignored. The routine does not clip X for you.
kitaqgb/lib/wire3d_dmg.c:3681
void Wire3DDMG_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1)
{
w3ddmg_u8 tx;
if (x0 > x1)
{
tx = x0;
x0 = x1;
x1 = tx;
}
w3ddmg_stage_clear_span(y, x0, x1);
}Wire3DDMG_EraseTriangle2D
使用水平掃描線跨度,從暫存區擦除畫面空間三角形。
語法
void Wire3DDMG_EraseTriangle2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by, w3ddmg_u8 cx, w3ddmg_u8 cy);參數
ax頂點 A 的 X 座標,以視埠像素為單位。
ay頂點 A 的 Y 座標,以視埠像素為單位。
bx頂點 B 的 X 座標,以視埠像素為單位。
by頂點 B 的 Y 座標,以視埠像素為單位。
cx頂點 C 的 X 座標,以視埠像素為單位。
cy頂點 C 的 Y 座標,以視埠像素為單位。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_EraseTriangle2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by, w3ddmg_u8 cx, w3ddmg_u8 cy); 利用整數掃描線交點,從暫存像素擦除三角形。須提供視埠座標。忽略退化三角形;遮蔽遮罩與 VRAM 不變。 WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_EraseTriangle2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by, w3ddmg_u8 cx, w3ddmg_u8 cy); 利用整數掃描線交點,從暫存像素擦除三角形。須提供視埠座標。忽略退化三角形;遮蔽遮罩與 VRAM 不變。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
WIRE3D_DMG_HEIGHT 預設為 120。高度 96 請使用 wire3d_dmg_96.c。SelectEdgeMask 可用於高度 96;RotatePoint、DrawIndexedEdges、傳輸閘控與直接傳輸則需要高度 120。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Erase a screen triangle and a projected model face from separate filled panels.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3DDMG_Vec3 vertices[4]={{-24,-24,0},{24,-24,0},{24,24,0},{-24,24,0}};
__prg_rom Wire3DDMG_Edge edges[4]={{0,1},{1,2},{2,3},{3,0}};
__prg_rom Wire3DDMG_Face faces[2]={{0,2,1},{0,3,2}};
Wire3DDMG_Model plane;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DDMG_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
plane.vertices=vertices;plane.edges=edges;plane.faces=faces;plane.edge_faces=0;
plane.vertex_count=4;plane.edge_count=4;plane.face_count=2;plane.flags=1;
Wire3DDMG_BeginFrame();
// Separate panels show a direct screen triangle and a projected square face.
for(i=8;i<=32;i++) Wire3DDMG_DrawLine2D(8,i,32,i);
for(i=36;i<=84;i++) Wire3DDMG_DrawLine2D(40,i,88,i);
Wire3DDMG_EraseTriangle2D(12,12,28,12,12,28);
Wire3DDMG_EraseModelFaces(&plane,0,0,64,0,0,0,256);
Wire3DDMG_EndFrame(); result[7]=0xA55A; while(1) {}
}預期結果
投影後的面會擦除填滿區域,可看出保留與清除的部分。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_faces.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_faces.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_dmg.h:184
Erase a triangle from staged pixels using integer scanline intersections. Supply viewport coordinates. Degenerate triangles are ignored; the occlusion mask and VRAM are unchanged.
kitaqgb/lib/wire3d_dmg.c:3671
void Wire3DDMG_EraseTriangle2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by, w3ddmg_u8 cx, w3ddmg_u8 cy)
{
w3ddmg_clear_triangle(ax, ay, bx, by, cx, cy);
}Wire3DDMG_Init
為單色線框視埠初始化 LCD、圖塊及背景地圖。
語法
void Wire3DDMG_Init();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_Init(); 接管 LCD:等待 VBlank 後關閉 LCD,清空 6144 個圖塊位元組與 BG 地圖,安裝 HUD 圖塊及採有號圖塊編號的 128×96 視埠,再以零捲動、BGP=0xB4 啟用 BG 顯示。重設相機、BG 佇列與暫存區。須保留 0xD000..0xDFFF 作為暫存區,並保持其 WRAM 記憶體庫映射。繪製前呼叫 BeginFrame,一併初始化遮蔽狀態。 WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_Init(); 接管 LCD 狀態,清空圖塊 VRAM 與 BG 地圖,從地圖圖塊 (3,1) 開始建立 16×15 視埠。設定捲動 (8,0)、BGP=0xB4 與 BG 顯示。重設相機、佇列、傳輸模式、兩份 dirty 表及暫存區。須保留 0xD000..0xDFFF 並維持 WRAM 映射;輔助儲存區與此區域共用位址。繪製前呼叫 BeginFrame 建立遮蔽狀態。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
WIRE3D_DMG_HEIGHT 預設為 120。高度 96 請使用 wire3d_dmg_96.c。SelectEdgeMask 可用於高度 96;RotatePoint、DrawIndexedEdges、傳輸閘控與直接傳輸則需要高度 120。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DDMG_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
Wire3DDMG_SetCamera(8,0,0,0,0,0);
result[1]=Wire3DDMG_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=Wire3DDMG_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
Wire3DDMG_SetCamera(0,0,0,0,0,0);
Wire3DDMG_BeginFrame();
Wire3DDMG_DrawLine2D(8,8,56,8);
Wire3DDMG_DrawLine2D(56,8,56,40);
Wire3DDMG_DrawLine2D(56,40,8,40);
Wire3DDMG_DrawLine2D(8,40,8,8);
Wire3DDMG_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
Wire3DDMG_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
Wire3DDMG_PutBgTile(1,1,160);
Wire3DDMG_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_raster.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_dmg.h:135
Take over LCD state, clear tile VRAM and the BG map, and install a 16x15 viewport beginning at map tile (3,1). Set scroll (8,0), BGP=0xB4 and BG display. Reset camera, queues, transfer modes, both dirty tables and stage. Reserve 0xD000..0xDFFF and retain its WRAM mapping; auxiliary storage aliases it. Call BeginFrame before drawing to establish occlusion state.
kitaqgb/lib/wire3d_dmg.c:3310
void Wire3DDMG_Init()
{
w3ddmg_u8 row;
w3ddmg_u8 col;
w3ddmg_u8 tid;
w3ddmg_u16 off;
w3ddmg_wait_vblank_start();
w3ddmg_reg_lcdc = 0;
w3ddmg_clear_vram_asm();
w3ddmg_fill_bg_map_asm();
row = 0;
tid = 0x90;
while (row < WIRE3D_DMG_TILE_H)
{
off = (w3ddmg_u16)(0x23 + ((w3ddmg_u16)row << 5));
col = 0;
while (col < WIRE3D_DMG_TILE_W)
{
w3ddmg_bg_map_9800[(w3ddmg_u16)(off + (w3ddmg_u16)col)] = tid;
tid = (w3ddmg_u8)(tid + WIRE3D_DMG_TILE_H);
col = (w3ddmg_u8)(col + 1);
}
row = (w3ddmg_u8)(row + 1);
tid = (w3ddmg_u8)(0x90 + row);
}
w3ddmg_reg_scx = 8;
w3ddmg_reg_scy = 0;
w3ddmg_reg_bgp = 0xB4;
w3ddmg_reg_lcdc = 0x81;
w3ddmg_bgq_count = 0;
w3ddmg_aux_transfer_enabled = 0;
w3ddmg_dirty_transfer_enabled = 0;
Wire3DDMG_SetCamera((w3ddmg_i16)0, (w3ddmg_i16)0, (w3ddmg_i16)0, (w3ddmg_u8)0, (w3ddmg_u8)0, (w3ddmg_u8)0);
w3ddmg_clear_stage_asm();
w3ddmg_clear_stage_aux_asm();
w3ddmg_clear_dirty_tables();
}Wire3DDMG_ProjectPoint
將世界座標點透過相機投影至視埠座標。
語法
w3ddmg_u8 Wire3DDMG_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy);參數
x點或物件原點的世界座標 X 分量。
y點或物件原點的世界座標 Y 分量。
z點或物件原點的世界座標 Z 分量。
sx接收投影 X 座標的有效可寫入 u8 指標。
sy接收投影 Y 座標的有效可寫入 u8 指標。
回傳值
投影成功傳回 1,深度遭拒傳回 0。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96 w3ddmg_u8 Wire3DDMG_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy); 以目前相機投影世界座標點。深度遭拒時傳回零並保留輸出;成功時寫入限制於 128×96 的座標。輸出指標須有效。畫面座標限幅不是幾何裁切。 WIRE3D_DMG_HEIGHT = 120 w3ddmg_u8 Wire3DDMG_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy); 以目前相機投影世界座標點。深度無效時傳回零且不改變輸出;成功時寫入限制於 128×120 的座標。兩個輸出指標皆須有效;座標差須容納於 s16。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
WIRE3D_DMG_HEIGHT 預設為 120。高度 96 請使用 wire3d_dmg_96.c。SelectEdgeMask 可用於高度 96;RotatePoint、DrawIndexedEdges、傳輸閘控與直接傳輸則需要高度 120。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DDMG_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
Wire3DDMG_SetCamera(8,0,0,0,0,0);
result[1]=Wire3DDMG_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=Wire3DDMG_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
Wire3DDMG_SetCamera(0,0,0,0,0,0);
Wire3DDMG_BeginFrame();
Wire3DDMG_DrawLine2D(8,8,56,8);
Wire3DDMG_DrawLine2D(56,8,56,40);
Wire3DDMG_DrawLine2D(56,40,8,40);
Wire3DDMG_DrawLine2D(8,40,8,8);
Wire3DDMG_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
Wire3DDMG_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
Wire3DDMG_PutBgTile(1,1,160);
Wire3DDMG_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_raster.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_dmg.h:216
Project a world point with the current camera. Return zero for invalid depth without changing outputs; success writes clamped 128x120 coordinates. Both output pointers must be valid. Coordinate differences must fit s16.
kitaqgb/lib/wire3d_dmg.c:688
w3ddmg_u8 Wire3DDMG_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy)
{
return w3ddmg_project_world(x, y, z, sx, sy);
}Wire3DDMG_PutBgTile
將背景地圖一格的圖塊編號寫入排入佇列。
語法
void Wire3DDMG_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile);參數
x32×32 背景地圖中的 X 圖塊座標。
y32×32 背景地圖中的 Y 圖塊座標。
tile背景格的八位元圖塊編號。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile); 將 0x9800 的 32×32 地圖圖塊寫入排入佇列,交由 EndFrame 處理。無效地圖座標及超過 48 筆待處理寫入的要求會直接忽略,不另行回報。此佇列與一般 vram 函式庫佇列分開。 WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile); 將 0x9800 的 32×32 地圖圖塊寫入排入佇列,交由 EndFrame 處理。無效地圖座標及超過 48 筆待處理寫入的要求會直接忽略,不另行回報。此佇列與一般 vram 函式庫佇列分開。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
WIRE3D_DMG_HEIGHT 預設為 120。高度 96 請使用 wire3d_dmg_96.c。SelectEdgeMask 可用於高度 96;RotatePoint、DrawIndexedEdges、傳輸閘控與直接傳輸則需要高度 120。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DDMG_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
Wire3DDMG_SetCamera(8,0,0,0,0,0);
result[1]=Wire3DDMG_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=Wire3DDMG_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
Wire3DDMG_SetCamera(0,0,0,0,0,0);
Wire3DDMG_BeginFrame();
Wire3DDMG_DrawLine2D(8,8,56,8);
Wire3DDMG_DrawLine2D(56,8,56,40);
Wire3DDMG_DrawLine2D(56,40,8,40);
Wire3DDMG_DrawLine2D(8,40,8,8);
Wire3DDMG_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
Wire3DDMG_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
Wire3DDMG_PutBgTile(1,1,160);
Wire3DDMG_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_raster.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_dmg.h:258
Queue a tile write to the 32x32 map at 0x9800 for EndFrame. Invalid map coordinates and submissions beyond 48 pending writes are silently ignored. This queue is separate from the general vram library queue.
kitaqgb/lib/wire3d_dmg.c:731
void Wire3DDMG_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile)
{
if (x >= 32) return;
if (y >= 32) return;
if (w3ddmg_bgq_count >= WIRE3D_DMG_BG_QUEUE_LIMIT) return;
w3ddmg_bgq_x[(__safe_index w3ddmg_u8)w3ddmg_bgq_count] = x;
w3ddmg_bgq_y[(__safe_index w3ddmg_u8)w3ddmg_bgq_count] = y;
w3ddmg_bgq_tile[(__safe_index w3ddmg_u8)w3ddmg_bgq_count] = tile;
w3ddmg_bgq_count = (w3ddmg_u8)(w3ddmg_bgq_count + 1);
}Wire3DDMG_RotatePoint
依指定角度就地旋轉一個點。
語法
void Wire3DDMG_RotatePoint(w3ddmg_i16* x, w3ddmg_i16* y, w3ddmg_i16* z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz);參數
xX 分量的可寫入 s16 指標,須與其他分量指向不同位置。
yY 分量的可寫入 s16 指標,須與其他分量指向不同位置。
zZ 分量的可寫入 s16 指標,須與其他分量指向不同位置。
rx繞 X 軸旋轉;十六步為一整圈。
ry繞 Y 軸旋轉;十六步為一整圈。
rz繞 Z 軸旋轉;十六步為一整圈。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_RotatePoint(w3ddmg_i16* x, w3ddmg_i16* y, w3ddmg_i16* z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz); 以每圈 16 步依 Y/X/Z 順序就地旋轉。任一分量指標為 null 時,整個呼叫不動作;各指標須指向不同位置。每個軸旋轉會將輸入限制於 ±220。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
WIRE3D_DMG_HEIGHT 預設為 120。高度 96 請使用 wire3d_dmg_96.c。SelectEdgeMask 可用於高度 96;RotatePoint、DrawIndexedEdges、傳輸閘控與直接傳輸則需要高度 120。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3DDMG_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom Wire3DDMG_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
Wire3DDMG_Model cube;
Wire3DDMG_Object objects[2];
s16 px; s16 py; s16 pz;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DDMG_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;
Wire3DDMG_BeginFrame();
// Upper pair: direct model calls at unity and half scale.
Wire3DDMG_DrawModel(&cube,-32,32,96,0,0,0);
Wire3DDMG_DrawModelScaled(&cube,32,32,96,0,0,0,128);
// Lower pair: the caller owns both object records and the model tables.
for(i=0;i<2;i++) {
objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
objects[i].y=-32;objects[i].z=96;
objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
}
Wire3DDMG_DrawScene(objects,2);
// Numeric checks cover the operation supplied by this viewport profile.
px=16;py=0;pz=0;Wire3DDMG_RotatePoint(&px,&py,&pz,0,4,0);
result[1]=px; result[2]=py; result[3]=pz;
Wire3DDMG_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
原倍率與半倍率模型顯示在相同倍率的物件陣列場景上方,用以示範投影與縮放。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_models.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_dmg.h:221
Rotate in place in Y/X/Z order using 16 steps per full turn. A null component pointer makes the whole call a no-op; use distinct pointers. Each axis rotation clamps its inputs to +/-220.
kitaqgb/lib/wire3d_dmg.c:3865
void Wire3DDMG_RotatePoint(w3ddmg_i16* x, w3ddmg_i16* y, w3ddmg_i16* z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz)
{
if (x == 0) return;
if (y == 0) return;
if (z == 0) return;
w3ddmg_rotate_y(x, z, ry);
w3ddmg_rotate_x(y, z, rx);
w3ddmg_rotate_z(x, y, rz);
}Wire3DDMG_SelectEdgeMask
依物件偏航選擇預先計算的邊可見遮罩。
語法
w3ddmg_u16 Wire3DDMG_SelectEdgeMask(const Wire3DDMG_Model* model, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz);參數
model包含頂點、邊、面陣列及數量的模型;呼叫期間須保持各表可讀。
rx繞 X 軸旋轉;十六步為一整圈。
ry繞 Y 軸旋轉;十六步為一整圈。
rz繞 Z 軸旋轉;十六步為一整圈。
回傳值
16 位元邊可見遮罩;未提供表時為 0xFFFF。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96 w3ddmg_u16 Wire3DDMG_SelectEdgeMask(const Wire3DDMG_Model* model, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz); 依物件偏航的低四位元選擇預先計算的遮罩;忽略俯仰、滾轉與相機朝向。使用 16、8、4 或 2 個區段;其他正計數選擇項目零(計數 >=16 時使用前 16 個)。缺少資料時傳回 0xFFFF。須讓遮罩表在目前資料指標映射下保持可讀。
此範例使用 128×96 設定,視埠從畫面 (0,0) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
WIRE3D_DMG_HEIGHT 預設為 120。高度 96 請使用 wire3d_dmg_96.c。SelectEdgeMask 可用於高度 96;RotatePoint、DrawIndexedEdges、傳輸閘控與直接傳輸則需要高度 120。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3DDMG_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom Wire3DDMG_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
Wire3DDMG_Model cube;
Wire3DDMG_Object objects[2];
u16 masks[2];
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DDMG_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;
cube.edge_masks=0; cube.edge_mask_count=0;
Wire3DDMG_BeginFrame();
// Upper pair: direct model calls at unity and half scale.
Wire3DDMG_DrawModel(&cube,-32,32,96,0,0,0);
Wire3DDMG_DrawModelScaled(&cube,32,32,96,0,0,0,128);
// Lower pair: the caller owns both object records and the model tables.
for(i=0;i<2;i++) {
objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
objects[i].y=-32;objects[i].z=96;
objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
}
Wire3DDMG_DrawScene(objects,2);
// Numeric checks cover the operation supplied by this viewport profile.
masks[0]=3;masks[1]=12;cube.edge_masks=masks; cube.edge_mask_count=2;
result[1]=Wire3DDMG_SelectEdgeMask(&cube,0,0,0);
result[2]=Wire3DDMG_SelectEdgeMask(&cube,0,8,0);
Wire3DDMG_EndFrame(); result[7]=0xA55A;
while(1) {}
}預期結果
原倍率與半倍率模型顯示在相同倍率的物件陣列場景上方,用以示範投影與縮放。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg96_models.c .\kitaqgb\lib\wire3d_dmg_96.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg96_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_dmg.h:207
Select a precomputed mask from the low four bits of object yaw; pitch, roll and camera orientation are ignored. Use 16, 8, 4 or 2 bins; other positive counts select entry zero (counts >=16 use the first 16). Missing data returns 0xFFFF. Keep the mask table readable through the current data-pointer mapping.
kitaqgb/lib/wire3d_dmg.c:1258
w3ddmg_u16 Wire3DDMG_SelectEdgeMask(const Wire3DDMG_Model* model, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz)
{
w3ddmg_u8 count;
w3ddmg_u8 bin;
if (model == 0) return 0xFFFF;
if (model->edge_masks == 0) return 0xFFFF;
count = model->edge_mask_count;
if (count == 0) return 0xFFFF;
(void)rx;
(void)rz;
bin = (w3ddmg_u8)(((w3ddmg_u8)ry) & 15);
if (count >= 16) return model->edge_masks[(__safe_index w3ddmg_u8)bin];
if (count == 8) bin = (w3ddmg_u8)(bin >> 1);
else if (count == 4) bin = (w3ddmg_u8)(bin >> 2);
else if (count == 2) bin = (w3ddmg_u8)(bin >> 3);
else bin = 0;
if (bin >= count) bin = (w3ddmg_u8)(count - 1);
return model->edge_masks[(__safe_index w3ddmg_u8)bin];
}Wire3DDMG_SetAuxTransfer
選擇 EndFrame 是否一併傳輸輔助條帶。
語法
void Wire3DDMG_SetAuxTransfer(w3ddmg_u8 flag);參數
flag零停用此傳輸功能,其他值均啟用。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_SetAuxTransfer(w3ddmg_u8 flag); 儲存 EndFrame 的輔助傳輸開關;任何非零值均啟用。此處不複製或清除資料。輔助來源位元組與主暫存區共用位址。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
WIRE3D_DMG_HEIGHT 預設為 120。高度 96 請使用 wire3d_dmg_96.c。SelectEdgeMask 可用於高度 96;RotatePoint、DrawIndexedEdges、傳輸閘控與直接傳輸則需要高度 120。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Use the auxiliary-transfer gate to consume an overlapping stage strip.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DDMG_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
Wire3DDMG_SetDirtyTransfer(1); Wire3DDMG_SetAuxTransfer(1);
Wire3DDMG_BeginFrame();
for(i=24;i<=31;i++) Wire3DDMG_DrawLine2D(40,i,47,i);
// Auxiliary upload consumes this source before the dirty main tile is sent.
Wire3DDMG_EndFrame(); result[7]=0xA55A; while(1) {}
}預期結果
主暫存區的一部分由輔助傳輸消耗,在畫面座標 (80,24) 產生黑色 8×8 區塊。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_aux_gate.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_aux_gate.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_dmg.h:268
Store the EndFrame auxiliary-transfer gate; any nonzero value enables it. No data is copied or cleared here. Auxiliary source bytes alias the main stage.
kitaqgb/lib/wire3d_dmg.c:4639
void Wire3DDMG_SetAuxTransfer(w3ddmg_u8 flag)
{
w3ddmg_aux_transfer_enabled = flag;
}Wire3DDMG_SetCamera
儲存後續投影使用的相機位置與朝向。
語法
void Wire3DDMG_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 pitch, w3ddmg_u8 yaw, w3ddmg_u8 roll);參數
x相機的世界座標 X 分量。
y相機的世界座標 Y 分量。
z相機的世界座標 Z 分量。
pitch繞 X 軸旋轉;十六步為一整圈。
yaw繞 Y 軸旋轉;十六步為一整圈。
roll繞 Z 軸旋轉;十六步為一整圈。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 pitch, w3ddmg_i8 yaw, w3ddmg_i8 roll); 儲存後續繪製使用的相機位置與角度;每圈 16 個角度步階。不重新投影既有繪圖,也不驗證輸入範圍。 WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 pitch, w3ddmg_u8 yaw, w3ddmg_u8 roll); 儲存後續繪製使用的相機位置與角度;每圈 16 個角度步階。不重新投影既有繪圖,也不驗證輸入範圍。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
WIRE3D_DMG_HEIGHT 預設為 120。高度 96 請使用 wire3d_dmg_96.c。SelectEdgeMask 可用於高度 96;RotatePoint、DrawIndexedEdges、傳輸閘控與直接傳輸則需要高度 120。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DDMG_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
Wire3DDMG_SetCamera(8,0,0,0,0,0);
result[1]=Wire3DDMG_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=Wire3DDMG_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
Wire3DDMG_SetCamera(0,0,0,0,0,0);
Wire3DDMG_BeginFrame();
Wire3DDMG_DrawLine2D(8,8,56,8);
Wire3DDMG_DrawLine2D(56,8,56,40);
Wire3DDMG_DrawLine2D(56,40,8,40);
Wire3DDMG_DrawLine2D(8,40,8,8);
Wire3DDMG_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
Wire3DDMG_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
Wire3DDMG_PutBgTile(1,1,160);
Wire3DDMG_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_raster.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_dmg.h:152
Store camera position and angles for later draws; a full turn is 16 angle steps. No existing drawing is reprojected and no input range validation occurs.
kitaqgb/lib/wire3d_dmg.c:3399
void Wire3DDMG_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 pitch, w3ddmg_u8 yaw, w3ddmg_u8 roll)
{
w3ddmg_cam_x = x;
w3ddmg_cam_y = y;
w3ddmg_cam_z = z;
w3ddmg_cam_pitch = pitch;
w3ddmg_cam_yaw = yaw;
w3ddmg_cam_roll = roll;
}kitaqgb/lib/wire3d_dmg.c:3397
void Wire3DDMG_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 pitch, w3ddmg_i8 yaw, w3ddmg_i8 roll)
{
w3ddmg_cam_x = x;
w3ddmg_cam_y = y;
w3ddmg_cam_z = z;
w3ddmg_cam_pitch = pitch;
w3ddmg_cam_yaw = yaw;
w3ddmg_cam_roll = roll;
}Wire3DDMG_SetDirtyTransfer
為高度 120 的主視埠選擇 dirty 圖塊傳輸。
語法
void Wire3DDMG_SetDirtyTransfer(w3ddmg_u8 flag);參數
flag零停用此傳輸功能,其他值均啟用。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_SetDirtyTransfer(w3ddmg_u8 flag); 儲存 dirty 傳輸開關,並清除兩份 dirty 歷史與主暫存區,即使設定值未變也會清除。保留 VRAM;若在舊畫面上啟用,可能留下未標記的舊圖塊,因此須先準備乾淨的顯示基準。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
WIRE3D_DMG_HEIGHT 預設為 120。高度 96 請使用 wire3d_dmg_96.c。SelectEdgeMask 可用於高度 96;RotatePoint、DrawIndexedEdges、傳輸閘控與直接傳輸則需要高度 120。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Remove the previous frame and upload only the tracked current/previous tiles.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DDMG_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
Wire3DDMG_SetDirtyTransfer(1); Wire3DDMG_SetAuxTransfer(0);
Wire3DDMG_BeginFrame();
Wire3DDMG_DrawLine2D(8,8,24,8); Wire3DDMG_DrawLine2D(24,8,24,24);
Wire3DDMG_DrawLine2D(24,24,8,24); Wire3DDMG_DrawLine2D(8,24,8,8);
Wire3DDMG_EndFrame();
Wire3DDMG_BeginFrame();
Wire3DDMG_DrawLine2D(80,80,104,80); Wire3DDMG_DrawLine2D(104,80,104,104);
Wire3DDMG_DrawLine2D(104,104,80,104); Wire3DDMG_DrawLine2D(80,104,80,80);
Wire3DDMG_EndFrame(); result[7]=0xA55A; while(1) {}
}預期結果
原先左上角的框消失,只留下畫面座標 (96,88)..(120,112) 的新框。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_dirty.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_dirty.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_dmg.h:272
Store the dirty-transfer gate and clear both dirty histories and the main stage, even if the value is unchanged. VRAM is retained; enabling this over an old image can leave unmarked old tiles, so arrange a clean displayed baseline.
kitaqgb/lib/wire3d_dmg.c:4699
void Wire3DDMG_SetDirtyTransfer(w3ddmg_u8 flag)
{
w3ddmg_dirty_transfer_enabled = flag;
w3ddmg_clear_dirty_tables();
w3ddmg_clear_stage_asm();
}Wire3DDMG_SetPalette
寫入單色背景調色盤暫存器 BGP 的四階明暗對應。
語法
void Wire3DDMG_SetPalette(w3ddmg_u8 bgp);參數
bgp包含四個兩位元明暗指定的 BGP 暫存器值。
回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_SetPalette(w3ddmg_u8 bgp); 立即寫入原始 DMG BGP 調色盤編碼,不進行影格同步。 WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_SetPalette(w3ddmg_u8 bgp); 立即寫入原始 DMG BGP 調色盤編碼,不進行影格同步。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
WIRE3D_DMG_HEIGHT 預設為 120。高度 96 請使用 wire3d_dmg_96.c。SelectEdgeMask 可用於高度 96;RotatePoint、DrawIndexedEdges、傳輸閘控與直接傳輸則需要高度 120。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DDMG_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
Wire3DDMG_SetCamera(8,0,0,0,0,0);
result[1]=Wire3DDMG_ProjectPoint(0,0,96,&projected_x,&projected_y);
result[2]=projected_x; result[3]=projected_y;
projected_x=91; projected_y=92;
result[4]=Wire3DDMG_ProjectPoint(0,0,7,&projected_x,&projected_y);
result[5]=projected_x; result[6]=projected_y;
Wire3DDMG_SetCamera(0,0,0,0,0,0);
Wire3DDMG_BeginFrame();
Wire3DDMG_DrawLine2D(8,8,56,8);
Wire3DDMG_DrawLine2D(56,8,56,40);
Wire3DDMG_DrawLine2D(56,40,8,40);
Wire3DDMG_DrawLine2D(8,40,8,8);
Wire3DDMG_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
Wire3DDMG_DrawLine3D(-24,-24,96,24,24,96);
// Copy the viewport's top-left frame corner to a separate map cell.
Wire3DDMG_PutBgTile(1,1,160);
Wire3DDMG_EndFrame();
result[7]=0xA55A;
while(1) {}
}預期結果
此範例在同一影格示範基本線段、點、擦除與投影。左上框的上邊中段被擦除,中央附近投影出對角線。被拒絕的投影保留輸出值 91 與 92。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_raster.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_dmg.h:260
Write the raw DMG BGP palette encoding immediately; no frame synchronization occurs.
kitaqgb/lib/wire3d_dmg.c:746
void Wire3DDMG_SetPalette(w3ddmg_u8 bgp)
{
w3ddmg_reg_bgp = bgp;
}Wire3DDMG_TransferAuxNow
立即上傳六個輔助條帶,並清除其來源位元組。
語法
void Wire3DDMG_TransferAuxNow();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_TransferAuxNow(); 不受輔助傳輸開關影響,立即上傳並消耗輔助來源條帶。不等待 VBlank 開始,也不更新 dirty 歷史或 BG 佇列。來源與主暫存區重疊,須協調與主區上傳的順序。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
WIRE3D_DMG_HEIGHT 預設為 120。高度 96 請使用 wire3d_dmg_96.c。SelectEdgeMask 可用於高度 96;RotatePoint、DrawIndexedEdges、傳輸閘控與直接傳輸則需要高度 120。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Upload a main line and an auxiliary block separately; verify source consumption.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3DDMG_Vec3 vertices[2]={{-32,0,0},{32,0,0}};
__prg_rom u8 edge_pairs[2]={0,1};
u8* stage_byte;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DDMG_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
Wire3DDMG_BeginFrame();
Wire3DDMG_DrawIndexedEdges(vertices,2,edge_pairs,1,-64,104,96,1);
Wire3DDMG_TransferMainNow();
// Direct auxiliary transfer writes a separate tile after the main upload.
for(i=24;i<=31;i++) Wire3DDMG_DrawLine2D(40,i,47,i);
stage_byte=(u8*)0xD518;result[1]=*stage_byte;
Wire3DDMG_TransferAuxNow();result[2]=*stage_byte;
// Do not upload the consumed stage again.
result[7]=0xA55A; while(1) {}
}預期結果
以投影水平線與輔助 8×8 區塊示範直接傳輸;來源位元組被消耗時由 255 變為 0。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_direct.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_direct.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_dmg.h:280
Upload and consume auxiliary source strips immediately, independent of the auxiliary gate. No VBlank-start wait or dirty-history/BG-queue update occurs. The source overlaps the main stage and must be coordinated with its upload.
kitaqgb/lib/wire3d_dmg.c:4727
void Wire3DDMG_TransferAuxNow()
{
w3ddmg_transfer_stage_aux_asm();
}Wire3DDMG_TransferMainNow
立即上傳整個主暫存區,並清除已消耗的來源像素。
語法
void Wire3DDMG_TransferMainNow();回傳值
無傳回值;受影響的狀態與顯示時序如上所述。
使用條件與限制
WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_TransferMainNow(); 立即上傳並消耗整個主暫存區,輪詢 STAT 但不等待下一次 VBlank。忽略傳輸開關,不改變 dirty 歷史或 BG 圖塊佇列;呼叫端須協調影格生命週期。
此範例使用 128×120 設定,視埠從畫面 (16,8) 開始。須保留 WRAM D000..DFFF,在 CGB 上也須維持穩定的記憶體庫映射。共用狀態不可重入。
WIRE3D_DMG_HEIGHT 預設為 120。高度 96 請使用 wire3d_dmg_96.c。SelectEdgeMask 可用於高度 96;RotatePoint、DrawIndexedEdges、傳輸閘控與直接傳輸則需要高度 120。
DMG的WIRE3D_DMG_HEIGHT可選88、96、120;CGB的WIRE3DCGB_HEIGHT可選88、96。預設仍為DMG 120、CGB 96。88列視口為128×88,中心Y=44。程式庫與呼叫端須採相同設定,以wire3d_dmg_88.c / wire3d_cgb_88.c替代一般入口編譯。DMG 88沿用96列的模型結構與16條邊限制。CGB 160×144模式維持不變。
使用範例
#pragma bank 0
// Upload a main line and an auxiliary block separately; verify source consumption.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3DDMG_Vec3 vertices[2]={{-32,0,0},{32,0,0}};
__prg_rom u8 edge_pairs[2]={0,1};
u8* stage_byte;
void main() {
u8 i;
for(i=0;i<8;i++) result[i]=0;
Wire3DDMG_Init();
// A CGB-compatible ROM also needs CGB palette and tile-map attributes.
if(__cgb_is_cgb()) {
while(sample_ly>=144) {} while(sample_ly<144) {}
sample_lcdc=0; sample_vbk=1;
__vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
for(i=0;i<6;i++) sample_bgpd=0;
sample_lcdc=0x81;
}
Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
result[0]=sample_bgp;
Wire3DDMG_BeginFrame();
Wire3DDMG_DrawIndexedEdges(vertices,2,edge_pairs,1,-64,104,96,1);
Wire3DDMG_TransferMainNow();
// Direct auxiliary transfer writes a separate tile after the main upload.
for(i=24;i<=31;i++) Wire3DDMG_DrawLine2D(40,i,47,i);
stage_byte=(u8*)0xD518;result[1]=*stage_byte;
Wire3DDMG_TransferAuxNow();result[2]=*stage_byte;
// Do not upload the consumed stage again.
result[7]=0xA55A; while(1) {}
}預期結果
以投影水平線與輔助 8×8 區塊示範直接傳輸;來源位元組被消耗時由 255 變為 0。
建置命令
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_direct.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_direct.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm實作與原始碼
kitaqgb/lib/wire3d_dmg.h:276
Upload and consume the full main stage immediately, polling STAT but not waiting for the next VBlank. Ignore transfer gates and leave dirty histories and BG tile queue unchanged; the caller coordinates the frame lifecycle.
kitaqgb/lib/wire3d_dmg.c:4714
void Wire3DDMG_TransferMainNow()
{
w3ddmg_transfer_stage_asm();
}結構、常數與完整標頭
非函式巨集、結構、陣列上限、列舉和別名,請查看這些標頭。內容依收集的原始碼原樣呈現,也包含原始註解。
asset.h — 素材 ID 與資料描述
#pragma once
#define ASSET_TYPE_RAW ((u8)0)
#define ASSET_TYPE_TILES ((u8)1)
#define ASSET_TYPE_MAP ((u8)2)
#define ASSET_TYPE_SONG ((u8)3)
// Packed ROM descriptor: type tag, payload bank, bank-window address and byte length.
// The table itself may live in a different bank from the payload.
typedef __packed struct {
u8 type;
u8 bank;
const u8* ptr;
u16 len;
} AssetDesc;
void __farmemcpy(void* dst, u8 bank, const void* src, u16 len);
void __vram_copy(u16 dst, const void* src, u16 len);
// Retain the descriptor table address, bank and count; the table is not copied.
void asset_set_table(u8 bank, const AssetDesc* table, u8 count);
// Copy one descriptor from its ROM bank into caller storage. Return zero for a
// null destination or an out-of-range ID; table validity is the caller's responsibility.
u8 asset_get(u8 asset_id, AssetDesc* out_desc);
// Copy at most max_len bytes using the asset's bank. Success means the ID was
// valid, even when the payload was truncated to fit the supplied limit.
u8 asset_load_raw(u8 asset_id, void* dst, u16 max_len);
// Accept tile/raw descriptors and transfer their bytes to VRAM. This path passes
// the descriptor pointer directly; callers must arrange the correct visible ROM bank.
u8 asset_load_tiles(u8 asset_id, u16 vram_dst);
// Return the descriptor bank, or zero on lookup failure; zero can also be a valid bank.
u8 asset_get_bank(u8 asset_id);
// Return the stored address without switching banks. Use the descriptor bank
// with far-data helpers before dereferencing banked assets; failure returns null.
const u8* asset_get_ptr(u8 asset_id);
// Return the descriptor byte length, or zero if its ID cannot be resolved.
u16 asset_get_len(u8 asset_id);kitaqgb/lib/asset.h
audio.h — 音樂、音效與音訊控制
#pragma once
// Shared Game Boy audio driver for KITAQGB projects.
//
// Integration notes:
// - Compile a hardware-register file before audio.c so NR10..NR52 and
// WAVE0..WAVE15 are already declared.
// - Call Audio_Init() once during startup.
// - Call Audio_Update() once per frame, ideally from your VBlank-driven main loop.
// - audio.c is intended to stay in bank 0.
// - Music streams are banked explicitly with Audio_PlayMusic(bank, song).
// - Audio_PlaySFX(sfx, priority) captures the currently visible ROM bank.
// - Audio_PlaySFXBanked(bank, sfx, priority) safely classifies CH1/CH3 data
// after switching to the requested bank, so banked SFX can be started from
// any currently visible ROM bank.
// - GBDAW-Stream v1.2 extends the legacy command set with explicit per-channel
// automation commands that map more directly from GUI and Python tooling.
// Physical APIs and music-stream commands share zero-based CH1..CH4 IDs.
#define AUDIO_CHANNEL_CH1 ((u8)0)
#define AUDIO_CHANNEL_CH2 ((u8)1)
#define AUDIO_CHANNEL_CH3 ((u8)2)
#define AUDIO_CHANNEL_CH4 ((u8)3)
// Music-stream IDs used by NOTE, SET_INST and STOP_CHANNEL.
#define AUDIO_STREAM_CHANNEL_CH1 AUDIO_CHANNEL_CH1
#define AUDIO_STREAM_CHANNEL_CH2 AUDIO_CHANNEL_CH2
#define AUDIO_STREAM_CHANNEL_CH3 AUDIO_CHANNEL_CH3
#define AUDIO_STREAM_CHANNEL_CH4 AUDIO_CHANNEL_CH4
#define AUDIO_PAN_CENTER ((u8)0)
#define AUDIO_PAN_LEFT ((u8)1)
#define AUDIO_PAN_RIGHT ((u8)2)
#define AUDIO_PAN_MUTE ((u8)3)
#define AUDIO_PAN_INHERIT ((u8)0xFF)
#define AUDIO_WAVE_TRIANGLE ((u8)0)
#define AUDIO_WAVE_SAW ((u8)1)
#define AUDIO_WAVE_VOWEL_A ((u8)2)
#define AUDIO_WAVE_VOWEL_I ((u8)3)
#define AUDIO_WAVE_VOWEL_U ((u8)4)
#define AUDIO_WAVE_VOWEL_E ((u8)5)
#define AUDIO_WAVE_VOWEL_O ((u8)6)
#define AUDIO_WAVE_CUSTOM ((u8)7)
#define AUDIO_CH3_LEVEL_MUTE ((u8)0x00)
#define AUDIO_CH3_LEVEL_100 ((u8)0x20)
#define AUDIO_CH3_LEVEL_50 ((u8)0x40)
#define AUDIO_CH3_LEVEL_25 ((u8)0x60)
#define AUDIO_VOLUME_MIN ((u8)0)
#define AUDIO_VOLUME_MAX ((u8)7)
#define AUDIO_NOTE_MAX ((u8)67)
#define AUDIO_CMD_WAIT ((u8)0x00)
#define AUDIO_CMD_NOTE ((u8)0x10)
#define AUDIO_CMD_SET_INST ((u8)0x11)
#define AUDIO_CMD_SET_PAN ((u8)0x12)
#define AUDIO_CMD_SET_SWEEP ((u8)0x13)
#define AUDIO_CMD_SET_WAVE ((u8)0x14)
#define AUDIO_CMD_SET_CH3_CUSTOM_WAVE ((u8)0x15)
#define AUDIO_CMD_SET_CH4_PARAM ((u8)0x16)
#define AUDIO_CMD_SET_MASTER_VOLUME ((u8)0x17)
#define AUDIO_CMD_SET_CH1_DUTY ((u8)0x18)
#define AUDIO_CMD_SET_CH2_DUTY ((u8)0x19)
#define AUDIO_CMD_SET_CH3_LEVEL ((u8)0x1A)
#define AUDIO_CMD_STOP_CHANNEL ((u8)0x20)
#define AUDIO_CMD_LOOP ((u8)0x30)
#define AUDIO_CMD_STOP ((u8)0x40)
#define AUDIO_SFX_CH3_MARKER ((u8)0xFF)
// Enable the APU and reset software streams, instruments, mix and fade state.
// Load the initial triangle wave, then leave every channel silent. Call at startup
// before concurrent interrupt-driven audio service can access these shared fields.
void Audio_Init();
// Advance the master fade first. Unless paused, service both effect streams
// then the optional legacy music decoder. Call once per frame for frame-based timing.
void Audio_Update();
// Retain the bank and song pointer, reset legacy instruments/cursors, and arm
// playback from the beginning. Supply a valid, persistent song; no bytes are copied
// and null is not checked. Existing effect streams remain active.
void __stackcall Audio_PlayMusic(u8 bank, u8 *song);
// Stop legacy music and clear its resume mask, then silence all physical channels.
// Effect pointers remain active and may produce sound on a later update.
void Audio_StopMusic();
// On pause entry, silence hardware while retaining cursors. On resume, retrigger
// eligible legacy CH1, CH2 and CH4 notes; CH3 is not retriggered here. Updates still
// advance master fades while paused, and effect playback resumes on a later update.
void __stackcall Audio_SetPaused(u8 on);
// Capture the currently mapped ROM bank and start an effect with inherited pan.
// Use the explicit-bank API when the pointer belongs to another bank.
void __stackcall Audio_PlaySFX(u8 *sfx, u8 priority);
// Start a banked effect with the channel's base pan, subject to priority arbitration.
void __stackcall Audio_PlaySFXBanked(u8 bank, u8 *sfx, u8 priority);
// Capture the currently mapped ROM bank and request an effect with a pan override.
// Use the explicit-bank API when the pointer belongs to another bank.
void __stackcall Audio_PlaySFXPanned(u8 *sfx, u8 priority, u8 pan);
// Retain a banked effect stream if its priority equals or exceeds the current
// owner's priority, or that slot is empty. A leading CH3 marker selects the wave
// slot and is skipped; other streams use the pulse slot. Paused requests are ignored.
// Keep stream storage valid until completion; acceptance does not trigger a note.
void __stackcall Audio_PlaySFXPannedBanked(u8 bank, u8 *sfx, u8 priority, u8 pan);
// Clear both effect streams and their pan overrides. When not paused, release
// borrowed channels through the configured legacy or VBlank recovery path.
void Audio_StopSfx();
// Stop a physical channel and clear its legacy resume bit. CH1 also clears the
// pulse effect stream; CH3 clears the wave effect stream. This is the legacy
// channel API and does not clear a VBlank driver's independently latched notes.
void __stackcall Audio_StopChannel(u8 ch);
// Set the music-processing gate. This does not silence notes already playing
// or stop the legacy stream cursor from consuming commands.
void __stackcall Audio_SetMusicEnabled(u8 on);
// Enable effect note writes, or disable them and release both effect streams.
// Disabling follows Audio_StopSfx recovery rules rather than silencing all channels.
void __stackcall Audio_SetSfxEnabled(u8 on);
// Clamp both output levels to 0..7, cancel any fade, and write NR50 immediately.
void __stackcall Audio_SetMasterVolume(u8 left, u8 right);
// Move left/right volume toward clamped targets at the requested Audio_Update
// call interval. An interval of zero applies the levels immediately.
void __stackcall Audio_FadeToMasterVolume(u8 left, u8 right, u8 step_frames);
// Cancel further volume steps, retaining the current cached levels and hardware output.
void Audio_CancelMasterVolumeFade();
// Update the base pan for a physical channel and reapply active effect overrides.
// Unknown channel IDs select CH4; unsupported pan values mute the selected channel.
void __stackcall Audio_SetPan(u8 ch, u8 pan);
// Two bits per channel (CH1 in bits 0-1): center, left, right, mute.
// Applies all four positions with one NR51 update for sequencer automation.
void __stackcall Audio_SetPanPacked(u8 packed);
// Install a named preset or the cached custom wave. Unknown IDs are ignored.
// This does not update Audio_Ch3Wave or trigger a new note.
void __stackcall Audio_LoadWave(u8 wave_id);
// Copy 16 packed sample bytes into the persistent custom cache and wave RAM.
// A null pointer is ignored; the source is needed only for this call.
void __stackcall Audio_LoadCustomWave(const u8 *wave16);
// Cache the low two duty bits for the next CH1 note; do not change the active register.
void __stackcall Audio_SetCh1Duty(u8 duty);
// Cache the low two duty bits for the next CH2 note; do not change the active register.
void __stackcall Audio_SetCh2Duty(u8 duty);
// Cache the raw NR32 level encoding for the next CH3 note without writing hardware.
void __stackcall Audio_SetCh3Level(u8 level);
// Cache the raw noise polynomial encoding for the next CH4 note without writing hardware.
void __stackcall Audio_SetCh4Param(u8 param);
// Trigger CH1 with the cached sweep and the supplied raw envelope. Clamp the
// note index; duty values 0, 1 and 3 select their encodings, and all others use 2.
void __stackcall Audio_Ch1NoteOn(u8 note, u8 vol_env, u8 duty2);
// Trigger CH2 with the supplied raw envelope and a clamped note index. Duty
// values 0, 1 and 3 select their encodings; all other values use duty 2.
void __stackcall Audio_Ch2NoteOn(u8 note, u8 vol_env, u8 duty2);
// Clamp the note index, program the raw NR32 output level, and trigger CH3.
// Wave RAM must already contain the desired waveform; this does not load one.
void __stackcall Audio_Ch3NoteOn(u8 note, u8 level);
// Cache the supplied noise parameter, program the raw envelope and polynomial
// registers, then trigger CH4 with the length-enable bit clear.
void __stackcall Audio_Ch4NoteOn(u8 param, u8 vol_env);kitaqgb/lib/audio.h
audio_vblank.h — 透過 VBlank IRQ 播放音樂
#pragma once
// Fixed-bank VBlank BGM driver.
//
// Stream format:
// delay, ch1_note, ch2_note, ch3_note, ch4_noise_param
// IMMEDIATE, ch1_note, ch2_note, ch3_note, ch4_noise_param
// CONTROL, command, arg0, arg1, arg2
//
// Notes are 0..67. To stay inside the useful CGB register range, C6..G6
// (60..67) alias C5..G5 (48..55) in the fixed pitch table. REST leaves a
// channel unchanged, while STOP silences it. END stops either playback mode.
// LOOP jumps to MusicLoopPoint only in direct-pointer mode; a queue producer
// must expand loops itself. IMMEDIATE is recognized only in queue mode.
// Direct streams treat 0xFB as an ordinary delay, and queues treat 0xFE as one.
#define AUDIO_VBLANK_REST ((u8)0xFF)
#define AUDIO_VBLANK_END ((u8)0xFF)
#define AUDIO_VBLANK_LOOP ((u8)0xFE)
#define AUDIO_VBLANK_STOP ((u8)0xFD)
#define AUDIO_VBLANK_CONTROL ((u8)0xFC)
#define AUDIO_VBLANK_IMMEDIATE ((u8)0xFB)
#define AUDIO_VBLANK_CONTROL_RESET ((u8)0x01)
#define AUDIO_VBLANK_W8 ((u8)15)
#define AUDIO_VBLANK_WQ ((u8)30)
#define AUDIO_VBLANK_WH ((u8)60)
#define AUDIO_VBLANK_QUEUE_RECORDS 16
#define AUDIO_VBLANK_QUEUE_BYTES 80
typedef void (*AudioVBlankFrameHook)();
extern __wram u8 AudioVBlank_MusicPlaying;
extern __wram u8 AudioVBlank_MusicEnabled;
extern __wram u8 AudioVBlank_MusicDelay;
extern __wram u8 *AudioVBlank_MusicStart;
extern __wram u8 *AudioVBlank_MusicPointer;
extern __wram u8 *AudioVBlank_MusicLoopPoint;
extern __wram u8 AudioVBlank_Step;
extern __wram u8 AudioVBlank_Ch2Note;
extern __wram u8 AudioVBlank_Ch1Note;
extern __wram u8 AudioVBlank_Ch3Note;
extern __wram u8 AudioVBlank_Ch2LatchedNote;
extern __wram u8 AudioVBlank_Ch1LatchedNote;
extern __wram u8 AudioVBlank_Ch3LatchedNote;
// Sound effects temporarily own CH1/CH2/CH3. A pending value of 1 means a BGM
// note/stop event was suppressed and must be applied once the effect ends;
// value 2 means release the effect channel without retriggering an old note.
extern __wram u8 AudioVBlank_RestoreCh1Pending;
extern __wram u8 AudioVBlank_RestoreCh3Pending;
extern __wram u8 AudioVBlank_Ch4Param;
extern __wram u8 AudioVBlank_Ch1Envelope;
extern __wram u8 AudioVBlank_Ch2Envelope;
extern __wram u8 AudioVBlank_Ch4Envelope;
extern __wram u8 AudioVBlank_Ch1Duty;
extern __wram u8 AudioVBlank_Ch2Duty;
extern __wram u8 AudioVBlank_Ch1Sweep;
extern __wram u8 AudioVBlank_Ch3Level;
extern __wram u8 AudioVBlank_ControlCommand;
extern __wram u8 AudioVBlank_ControlArg0;
extern __wram u8 AudioVBlank_ControlArg1;
extern __wram u8 AudioVBlank_ControlArg2;
// QueueReset/QueueRefill/QueuePlay provide the foreground producer. The ISR owns
// ReadIndex and decreases Count; use the producer APIs instead of editing the
// indices/count while playback is running. Records contain exactly five bytes.
// MusicPlaying and all enable/pause gates still apply in queue mode.
extern __wram u8 AudioVBlank_QueueMode;
extern __wram u8 AudioVBlank_QueueReadIndex;
extern __wram u8 AudioVBlank_QueueWriteIndex;
extern __wram u8 AudioVBlank_QueueCount;
extern __wram u8 AudioVBlank_QueueUnderruns;
// Queue bytes reside in WRAM bank 1. A producer must select that bank while
// writing and restore the caller bank; publish the record only after all bytes
// are complete. The ISR selects bank 1 itself and restores SVBK before returning.
extern __wramx_bank(1) u8 AudioVBlank_QueueBuffer[AUDIO_VBLANK_QUEUE_BYTES];
// The ISR invokes this hook even when music processing is gated off. It runs
// with SVBK=1 using a direct-address call; keep hook code/data accessible in that
// context and synchronize pointer changes with interrupt execution.
extern __wram AudioVBlankFrameHook AudioVBlank_FrameHook;
// Reset software playback state, queue counters, instruments and the frame hook.
// Call before enabling this ISR; the routine does not mask interrupts or
// initialize the APU registers and cannot synchronize with an active handler.
void AudioVBlank_Init();
// Stop music and select an empty WRAM queue; preserve IE, IME and enable/pause gates.
void AudioVBlank_QueueReset();
// Copy complete records from the currently mapped source; return records accepted.
// Each call attempts at most 16 records and stops when full. Null/zero returns 0.
// Supports ROM and RAM sources, restores SVBK and IE, and never changes IME.
// Single foreground producer only: do not call from an ISR or frame hook.
// LOOP must be expanded by the producer. END occupies a full five-byte record.
u8 __stackcall AudioVBlank_QueueRefill(const u8 *records, u8 count);
// Start/resume queued playback; return 1 on success, 0 for an empty/nonqueue mode.
// Does not enable the interrupt, music gate or clear pause. Queue before starting.
u8 AudioVBlank_QueuePlay();
// Select a directly addressed song and reset its cursors, leaving the playing
// flag unchanged. Song storage must remain accessible to the fixed-bank ISR;
// coordinate this multi-field update with interrupt execution.
void __stackcall AudioVBlank_SetMusic(u8 *song);
// Restart the selected direct song at its beginning, leaving queue mode.
// A null song invokes Stop; this does not enable the music or IRQ gates.
void AudioVBlank_Play();
// Select and restart a directly addressed song. This is not the banked WRAM-queue path.
void __stackcall AudioVBlank_PlayMusic(u8 *song);
// Stop software playback and silence pulse/noise envelopes and the wave DAC.
// Song pointers and the IRQ enable remain unchanged; the routine writes the
// physical channels directly, so coordinate ownership with sound effects.
void AudioVBlank_Stop();
// Gate music processing and clear pending CH1/CH3 recovery on disable.
// No audio register is written here: disabling does not itself silence a note
// already playing or disable the VBlank interrupt.
void __stackcall AudioVBlank_SetEnabled(u8 on);
// Enable the VBlank source in IE and execute EI, enabling CPU interrupts globally.
// Install the correct interrupt vector and initialize driver state first.
void AudioVBlank_EnableIrq();
// Clear only the VBlank bit in IE. Other interrupt sources and current sound remain unchanged.
void AudioVBlank_DisableIrq();
// Recover the borrowed pulse channel (CH1 or CH2) from its latched music event.
// Pending value 2, disabled music, or a non-note latch silences it instead.
// The caller must first establish that the effect has released the channel.
void AudioVBlank_RestoreCh1();
// Recover a latched wave-channel music event after effect release, or disable
// the DAC for a release-only request, disabled music, or a non-note latch.
// The caller owns effect arbitration and clearing the pending flag.
void AudioVBlank_RestoreCh3();
// Request deferred pulse-channel release only when no recovery is pending.
// Preserve value 1, which records a music event suppressed while an effect owned it.
void AudioVBlank_RequestRestoreCh1();
// Request a deferred wave-channel release only if no recovery is pending.
// Preserve value 1, which records a new music event suppressed by the effect.
void AudioVBlank_RequestRestoreCh3();kitaqgb/lib/audio_vblank.h
bank.h — 考慮 bank 的程式碼與資料存取
#pragma once
// A bank byte accompanies the CPU-visible ROM address; the pointer alone is not a far address.
typedef __packed struct {
u8 bank;
const u8* ptr;
} BankPtr;
extern u8 kq_bank_current;
void __bankswitch(u8 bank);
u8 __farpeek8(u8 bank, const void* addr);
u16 __farpeek16(u8 bank, const void* addr);
void __farmemcpy(void* dst, u8 bank, const void* src, u16 len);
void __farcall_ptr(u8 bank, const void* func);
// Update both the library bank record and the compiler shadow used by far
// reads and calls. Invoke this permanent bank change from fixed-bank code.
void bank_switch(u8 bank);
// Return the last bank recorded by bank_switch; this does not read cartridge hardware.
u8 bank_get_current();
// Read one byte through the compiler intrinsic that accepts an explicit ROM bank.
u8 far_data_read8(u8 bank, const void* addr);
// Read a 16-bit value from the supplied bank and address through the far-read intrinsic.
u16 far_data_read16(u8 bank, const void* addr);
// Copy len bytes from banked ROM into caller-owned writable storage.
void far_data_read(u8 bank, const void* addr, void* dst, u16 len);
// Invoke a no-argument callback in its ROM bank, then restore the caller
// bank. The pointer must identify executable code; no arguments are forwarded.
void far_call(u8 bank, const void* func);
// Store a bank/address pair without accessing ROM; a null output pointer is ignored.
void farptr_make(BankPtr* out, u8 bank, const u8* ptr);
// Read one byte using both components of the bank-qualified pointer.
u8 farptr_read8(BankPtr ptr);
// Read a 16-bit value using both components of the bank-qualified pointer.
u16 farptr_read16(BankPtr ptr);
// Copy len bytes from a bank-qualified pointer; dst must have room for the full copy.
void farptr_read(BankPtr ptr, void* dst, u16 len);kitaqgb/lib/bank.h
camera.h — 世界座標與可見區域
#pragma once
#include "scroll.h"
// All position, target and bound fields use signed Q8.8 (-128 to just below 128 pixels).
// Pass initialized, non-null storage; world/screen conversion arguments use integer pixels.
typedef struct Camera8_8 {
s16 fx;
s16 fy;
s16 target_fx;
s16 target_fy;
s16 min_fx;
s16 min_fy;
s16 max_fx;
s16 max_fy;
u8 use_target;
u8 use_bounds;
} Camera8_8;
// Zero all position/target/bound fields and disable targeting and bounds.
void Camera_Init(Camera8_8* cam);
// Replace the current Q8.8 position and immediately apply enabled bounds.
void Camera_Set(Camera8_8* cam, s16 fx, s16 fy);
// Store a Q8.8 target and enable subsequent step-toward-target updates.
void Camera_SetTarget(Camera8_8* cam, s16 fx, s16 fy);
// Disable target following without moving the camera or erasing the stored target.
void Camera_ClearTarget(Camera8_8* cam);
// Install ordered Q8.8 bounds, enable them and clamp the current position immediately.
void Camera_SetBounds(Camera8_8* cam, s16 min_fx, s16 min_fy, s16 max_fx, s16 max_fy);
// Disable clamping while retaining the stored bounds and current position.
void Camera_ClearBounds(Camera8_8* cam);
// Add Q8.8 deltas and clamp afterward. Keep the intermediate sums within s16;
// clamping cannot repair arithmetic that already overflowed.
void Camera_Add(Camera8_8* cam, s16 dfx, s16 dfy);
// Move by the signed target delta shifted by 0..7 bits, then apply bounds.
// Quantization can make a small delta produce no movement; only exact equality
// clears targeting, and a target outside the bounds may remain active indefinitely.
void Camera_StepTowardTarget(Camera8_8* cam, u8 shift);
// Discard fractional bits and write the low eight integer bits to background scroll registers.
void Camera_ApplyBg(const Camera8_8* cam);
// Convert the Q8.8 position to byte scroll values and stage them for a later flush.
void Camera_ApplyBgBuffered(const Camera8_8* cam);
// Derive nonnegative camera extents from world minus screen size, then convert
// them to Q8.8 bounds. Extents must fit signed Q8.8; the u16 input type does
// not imply support for arbitrary large worlds.
void Camera_ClampToSize(Camera8_8* cam, u16 world_w_px, u16 world_h_px, u8 screen_w_px, u8 screen_h_px);
// Convert an integer-pixel world X by subtracting the camera's integer X component.
s16 Camera_WorldToScreenX(const Camera8_8* cam, s16 world_x);
// Convert an integer-pixel world Y by subtracting the camera's integer Y component.
s16 Camera_WorldToScreenY(const Camera8_8* cam, s16 world_y);
// Convert integer-pixel screen X back to world X using the camera's integer component.
s16 Camera_ScreenToWorldX(const Camera8_8* cam, s16 screen_x);
// Convert integer-pixel screen Y back to world Y using the camera's integer component.
s16 Camera_ScreenToWorldY(const Camera8_8* cam, s16 screen_y);
// Set the shared camera from integer pixels, converting to the representable Q8.8 range.
void camera_set(s16 x, s16 y);
// Position the shared camera so the world point appears at the requested screen
// anchor. This is an immediate move, not the smoothed target-following path.
void camera_follow_xy(s16 x, s16 y, u8 screen_cx, u8 screen_cy);
// Derive and apply world/screen bounds to the shared convenience camera.
void camera_clamp(u16 world_w_px, u16 world_h_px, u8 screen_w_px, u8 screen_h_px);
// Write the shared camera's current integer position to background scroll registers.
void camera_apply();
// Convert integer-pixel world X using the shared convenience camera.
s16 camera_world_to_screen_x(s16 world_x);
// Convert integer-pixel world Y using the shared convenience camera.
s16 camera_world_to_screen_y(s16 world_y);kitaqgb/lib/camera.h
cgb_palette.h — CGB 背景與 OBJ 調色盤
#pragma once
// High-level CGB palette helpers for KITAQGB.
// Palette writes no-op on DMG; RGB packing works on either hardware model.
// Safe here means CGB hardware gating. Palette data writes still require an accessible
// PPU phase (for example LCD off or a sufficiently short VBlank update).
u8 __cgb_is_cgb();
void __cgb_safe_set_bcps(u8 value);
void __cgb_safe_set_bcpd(u8 value);
void __cgb_safe_set_ocps(u8 value);
void __cgb_safe_set_ocpd(u8 value);
// Mask each component to five bits: red in 0..4, green in 5..9, blue in 10..14.
// These macros wrap oversized components rather than saturating them.
#define CGB_RGB15(r5, g5, b5) ((u16)((u16)((r5) & 31) | ((u16)((g5) & 31) << 5) | ((u16)((b5) & 31) << 10)))
// Pack the red, green and blue components using the public RGB15 macro.
u16 cgb_rgb15(u8 r5, u8 g5, u8 b5);
// Set one background color through the indexed palette wrapper.
void cgb_bg_color(u8 palette_index, u8 color_index, u16 rgb15);
// Set one object color through the indexed palette wrapper.
void cgb_obj_color(u8 palette_index, u8 color_index, u16 rgb15);
// Pack component values and write one background color.
void cgb_bg_rgb(u8 palette_index, u8 color_index, u8 r5, u8 g5, u8 b5);
// Pack component values and write one object color.
void cgb_obj_rgb(u8 palette_index, u8 color_index, u8 r5, u8 g5, u8 b5);
// Write background colors starting at the indexed slot. The range may cross
// palette boundaries and is clamped only at the end of all 32 slots.
void cgb_bg_colors(u8 palette_index, u8 start_color_index, const u16* colors, u8 color_count);
// Write object colors from the indexed slot, potentially crossing into later palettes.
void cgb_obj_colors(u8 palette_index, u8 start_color_index, const u16* colors, u8 color_count);
// Write four consecutive colors for one background palette.
void cgb_bg_palette(u8 palette_index, const u16* colors);
// Write four consecutive colors for one object palette.
void cgb_obj_palette(u8 palette_index, const u16* colors);
// Expose sequential background writes using an absolute color-slot index.
void cgb_bg_colors_raw(u8 start_color_slot, const u16* colors, u8 color_count);
// Expose sequential object writes using an absolute color-slot index.
void cgb_obj_colors_raw(u8 start_color_slot, const u16* colors, u8 color_count);kitaqgb/lib/cgb_palette.h
cgb_tile.h — CGB 圖塊編號與屬性
#pragma once
// Declarations for compiler-intrinsic CGB tile helpers.
// Canonical intrinsic entry points use the "__" prefix.
// Attr writes no-op on DMG. Combined tile+attr writes still write the tile on DMG.
// These helpers emit compiler code; cgb_tile.c has no runtime bodies. Scalar coordinates address 32x32 maps.
// Safe write paths poll VRAM access; LCD-on paths can enable interrupts after writing.
// Use _unsafe/_fast only with caller-managed writable VRAM timing, especially inside an ISR.
// Tile writes use the selected VRAM bank; choose bank zero before combined tile/attribute operations.
#define KQ_CGB_ATTR_PAL_MASK 0x07
#define KQ_CGB_ATTR_BANK1 0x08
#define KQ_CGB_ATTR_XFLIP 0x20
#define KQ_CGB_ATTR_YFLIP 0x40
#define KQ_CGB_ATTR_PRIORITY 0x80
#define KQ_CGB_ATTR_NONE ((u8)0)
#define KQ_CGB_ATTR_PAL(n) ((u8)((n) & KQ_CGB_ATTR_PAL_MASK))
#define KQ_CGB_ATTR_BANK(bank) ((u8)((bank) ? KQ_CGB_ATTR_BANK1 : 0))
#define KQ_CGB_ATTR_XFLIP_IF(enabled) ((u8)((enabled) ? KQ_CGB_ATTR_XFLIP : 0))
#define KQ_CGB_ATTR_YFLIP_IF(enabled) ((u8)((enabled) ? KQ_CGB_ATTR_YFLIP : 0))
#define KQ_CGB_ATTR_PRIORITY_IF(enabled) ((u8)((enabled) ? KQ_CGB_ATTR_PRIORITY : 0))
#define KQ_CGB_ATTR(palette, bank, xflip, yflip, priority) ((u8)(((palette) & KQ_CGB_ATTR_PAL_MASK) | ((bank) ? KQ_CGB_ATTR_BANK1 : 0) | ((xflip) ? KQ_CGB_ATTR_XFLIP : 0) | ((yflip) ? KQ_CGB_ATTR_YFLIP : 0) | ((priority) ? KQ_CGB_ATTR_PRIORITY : 0)))
// Return the compiler/runtime CGB mode test as a byte Boolean.
u8 __cgb_is_cgb();
// Write the VRAM bank selection only on CGB. Safe here means hardware-mode guarded, not PPU-timed.
void __cgb_safe_set_vbk(u8 value);
// Write a tile number to map 9800, waiting for VRAM access when necessary.
void __settile(u8 x, u8 y, u8 tile);
// Write a tile number to map 9800 without waiting for writable VRAM.
void __settile_unsafe(u8 x, u8 y, u8 tile);
// Write at base+32*y+x with VRAM access checks; supply a valid tile-map base.
void __settileat(u16 base, u8 x, u8 y, u8 tile);
// Use an explicit map base without waiting for VRAM access.
void __settileat_unsafe(u16 base, u8 x, u8 y, u8 tile);
// Select the window map from LCDC bit 6, then write a tile with access checks.
void __settilewin(u8 x, u8 y, u8 tile);
// Select the LCDC window map and write without access waits.
void __settilewin_unsafe(u8 x, u8 y, u8 tile);
// Select the background map from LCDC bit 3, then write with access checks.
void __settilebg(u8 x, u8 y, u8 tile);
// Select the LCDC background map and write without access waits.
void __settilebg_unsafe(u8 x, u8 y, u8 tile);
// Copy count sequential bytes to dest using the current VRAM bank and access-checked transfer.
void __settile_bulk(u16 dest, const u8* src, u8 count);
// Copy count sequential bytes to dest without VRAM access waits; retain source-bank visibility.
void __settile_bulk_fast(u16 dest, const u8* src, u8 count);
// Write attributes in bank one at map 9800 on CGB, then leave VBK zero; skip on DMG. Use the access-checked write path.
void __settileattr(u8 x, u8 y, u8 attr);
// Write attributes in bank one at map 9800 on CGB, then leave VBK zero; skip on DMG. No VRAM access waits are inserted.
void __settileattr_unsafe(u8 x, u8 y, u8 attr);
// Write tile and CGB attributes at map 9800; DMG receives only the tile write. Use the access-checked write path.
void __settilecgb(u8 x, u8 y, u8 tile, u8 attr);
// Write tile and CGB attributes at map 9800; DMG receives only the tile write. No VRAM access waits are inserted.
void __settilecgb_unsafe(u8 x, u8 y, u8 tile, u8 attr);
// Write attributes in bank one at the explicit map base on CGB, then leave VBK zero; skip on DMG. Use the access-checked write path.
void __settileatattr(u16 base, u8 x, u8 y, u8 attr);
// Write attributes in bank one at the explicit map base on CGB, then leave VBK zero; skip on DMG. No VRAM access waits are inserted.
void __settileatattr_unsafe(u16 base, u8 x, u8 y, u8 attr);
// Write tile and CGB attributes at the explicit map base; DMG receives only the tile write. Use the access-checked write path.
void __settileatcgb(u16 base, u8 x, u8 y, u8 tile, u8 attr);
// Write tile and CGB attributes at the explicit map base; DMG receives only the tile write. No VRAM access waits are inserted.
void __settileatcgb_unsafe(u16 base, u8 x, u8 y, u8 tile, u8 attr);
// Write attributes in bank one at the LCDC window map on CGB, then leave VBK zero; skip on DMG. Use the access-checked write path.
void __settilewinattr(u8 x, u8 y, u8 attr);
// Write attributes in bank one at the LCDC window map on CGB, then leave VBK zero; skip on DMG. No VRAM access waits are inserted.
void __settilewinattr_unsafe(u8 x, u8 y, u8 attr);
// Write tile and CGB attributes at the LCDC window map; DMG receives only the tile write. Use the access-checked write path.
void __settilewincgb(u8 x, u8 y, u8 tile, u8 attr);
// Write tile and CGB attributes at the LCDC window map; DMG receives only the tile write. No VRAM access waits are inserted.
void __settilewincgb_unsafe(u8 x, u8 y, u8 tile, u8 attr);
// Write attributes in bank one at the LCDC background map on CGB, then leave VBK zero; skip on DMG. Use the access-checked write path.
void __settilebgattr(u8 x, u8 y, u8 attr);
// Write attributes in bank one at the LCDC background map on CGB, then leave VBK zero; skip on DMG. No VRAM access waits are inserted.
void __settilebgattr_unsafe(u8 x, u8 y, u8 attr);
// Write tile and CGB attributes at the LCDC background map; DMG receives only the tile write. Use the access-checked write path.
void __settilebgcgb(u8 x, u8 y, u8 tile, u8 attr);
// Write tile and CGB attributes at the LCDC background map; DMG receives only the tile write. No VRAM access waits are inserted.
void __settilebgcgb_unsafe(u8 x, u8 y, u8 tile, u8 attr);
// Copy count attributes to dest in bank one on CGB, then leave VBK zero; skip on DMG. Transfers use access checks.
void __settileattr_bulk(u16 dest, const u8* src, u8 count);
// Copy count attributes to dest in bank one on CGB, then leave VBK zero; skip on DMG. The caller supplies writable VRAM timing.
void __settileattr_bulk_fast(u16 dest, const u8* src, u8 count);
// Copy tile and attribute streams to dest; DMG receives only tiles. Keep both sources readable. Transfers use access checks.
void __settilecgb_bulk(u16 dest, const u8* tile_src, const u8* attr_src, u8 count);
// Copy tile and attribute streams to dest; DMG receives only tiles. Keep both sources readable. The caller supplies writable VRAM timing.
void __settilecgb_bulk_fast(u16 dest, const u8* tile_src, const u8* attr_src, u8 count);kitaqgb/lib/cgb_tile.h
chain.h — 位置歷史環狀緩衝區
#pragma once
typedef __packed struct {
s16 x;
s16 y;
} ChainPoint;
typedef __packed struct {
ChainPoint* points;
u8 capacity;
u8 count;
u8 head;
} Chain;
// Attach caller-owned ring storage and start with no recorded points.
// The storage must remain valid for the lifetime of the chain.
// Use a valid chain pointer and capacity entries of caller-owned storage.
// Capacity at most 128 keeps every head+age sum in the byte range used by the reader.
void chain_init(Chain* chain, ChainPoint* storage, u8 capacity);
// Forget the recorded points without clearing or freeing the backing storage.
void chain_clear(Chain* chain);
// Move the ring head backward and store the newest point. Once full, each push
// replaces the oldest point; zero capacity is a no-op.
void chain_push_head(Chain* chain, s16 x, s16 y);
// Read a point by age, with index zero denoting the newest point. Return zero
// for an invalid request and clear a non-null output first. Keep head + index
// within the 8-bit range: addition is narrowed before the capacity wrap.
u8 chain_get_segment(const Chain* chain, u8 index, ChainPoint* out);
// Return the number of stored points, or zero for a null chain.
u8 chain_get_count(const Chain* chain);
// Return target minus current along the shortest wrapped route.
// Supply size 1..256 and coordinates in 0..size-1; inputs are not normalized.
// Exactly half a field retains the direct displacement sign.
s16 chain_wrap_delta(u8 target, u8 current, u16 size);
// Articulated body: one current pose per joint, including the head at index 0.
// Caller-owned byte arrays keep the inner loop compact on both GB and FC.
// Heading sectors run clockwise: 0=right, 4=down, 8=left, 12=up.
// Coordinates are pixels; each wrapped dimension accepts 1..256 pixels.
typedef __packed struct {
u8* x;
u8* y;
u8* heading;
u8 capacity;
u8 count;
u16 width;
u16 height;
} ChainBody;
// Attach three non-overlapping capacity-byte arrays. Return 1 on success.
// Invalid storage, zero capacity or dimensions outside 1..256 disable the body.
u8 chain_body_init(ChainBody* body, u8* x, u8* y, u8* heading, u8 capacity, u16 width, u16 height);
// Seed count joints in a straight pose behind the head; count includes the head.
// Return 0 without changing the pose if count is zero or exceeds capacity.
// Coordinates wrap to the playfield and headings are masked to 0..15.
u8 chain_body_reset(ChainBody* body, u8 count, u8 head_x, u8 head_y, u8 heading);
// Install the caller's head pose, then pull joints from front to rear.
// Each joint aims four pixels behind its updated predecessor and receives that
// predecessor's OLD heading. Each axis moves 1 pixel, or 2 when error exceeds 4.
// Call once per simulation tick; this does not advance head physics or render.
void chain_body_step(ChainBody* body, u8 head_x, u8 head_y, u8 heading);
// Append a copy of the current tail; later steps separate the new joint.
// Return 1 on growth, or 0 for an empty, disabled or full body.
u8 chain_body_grow(ChainBody* body);
// Remove all joints while retaining caller-owned storage and playfield settings.
void chain_body_clear(ChainBody* body);kitaqgb/lib/chain.h
danmaku.h — 彈池、扇形發射、命中與擦彈
#pragma once
// Fixed-capacity, allocation-free bullet field for a 160 x 128 play area.
// Positions/velocities are signed Q12.4 / Q4.4; +Y points down.
// Tile ids 0..15 encode the four 4x4 quadrants of an 8x8 tile.
// Reserve those tiles in VRAM, with a 3x3 bullet centered at (2,2)
// in every set quadrant. Other tile ids in the map are decoration.
#define DANMAKU_MAX 96
#define DANMAKU_MAP_BYTES 576
typedef __packed struct {
s16 x;
s16 y;
s8 vx;
s8 vy;
u8 active;
u8 grazed;
} DanmakuBullet;
extern DanmakuBullet dm_bullets[DANMAKU_MAX];
extern __wram __aligned(16) u8 dm_map[DANMAKU_MAP_BYTES];
extern u8 dm_count;
extern u8 dm_peak;
// Per-step hit is a Boolean latch; graze counts newly grazed bullets this step. Spawn/rejection counters wrap at 65536.
extern u8 dm_hit;
extern u8 dm_graze;
extern u8 dm_player_x;
extern u8 dm_player_y;
extern u8 dm_invulnerable;
extern u16 dm_spawned;
extern u16 dm_rejected;
// Reset pool, peak and lifetime counters; player fields and map contents remain caller-owned state.
void danmaku_reset();
// Deactivate the pool while retaining peak/spawn/rejection counters and the RAM map.
void danmaku_clear();
// Use pixel origins inside 160x128 and signed sixteenth-pixel velocities; return one if a slot was allocated.
u8 danmaku_spawn(u8 x, u8 y, s8 vx, s8 vy);
// Attempt a fan using wrapping 32-step angles; count is capped at 96 and speed at 64.
void danmaku_fan(u8 x, u8 y, u8 direction, u8 step, u8 count, u8 speed);
// 32 directions, 0=right, 8=down, 16=left, 24=up. speed in 1/16 px.
// Clear the 32x18 RAM map before drawing the next frame; no transfer is performed.
void danmaku_clear_map();
// Caller fills decoration after clear_map, then calls step to overlay bullets.
// hit and graze are events for this step. Collision uses rendered centers.
void danmaku_step();
// Requires CGB and LCD off or the beginning of VBlank. VBK restored to 0.
// Transfers 18 rows (32-byte stride) to BG map 9800 with 36-block GDMA.
void danmaku_present_now();kitaqgb/lib/danmaku.h
debug.h — RAM 紀錄與斷言
#pragma once
// Use a capacity from 1 through 255; the length counter is a byte.
// Compile every unit with the same override so the array declaration and storage agree.
#ifndef DEBUG_TRACE_MAX
#define DEBUG_TRACE_MAX 32
#endif
// Each packed entry retains a name pointer and two 16-bit values; name text is not copied.
typedef __packed struct {
const u8* name;
u16 value;
u16 frame;
} DebugTraceEntry;
extern DebugTraceEntry kq_debug_trace_log[DEBUG_TRACE_MAX];
extern u8 kq_debug_trace_count;
extern u16 kq_debug_frame;
extern u16 kq_debug_last_assert;
// Reset log length, frame tag and last assertion code; existing entry bytes are not erased.
void debug_init();
// Set the frame tag copied into subsequently recorded entries.
void debug_set_frame(u16 frame);
// Append a named frame marker using 0xFFFF as its value.
void debug_mark_frame(const u8* label);
// Append an unsigned byte value, widened to the log's 16-bit value field.
void debug_trace_u8(const u8* name, u8 value);
// Append a 16-bit value with the current frame tag.
void debug_trace_u16(const u8* name, u16 value);
// Record the assertion code and attempt to append an ASSERT entry. This helper
// does not halt execution, and the code is retained even if the log is full.
void debug_assert_fail(u16 code);
// Return the number of valid entries in the fixed trace buffer.
u8 debug_get_trace_count();
// Expose the internal trace array for inspection; use the count to bound reads.
const DebugTraceEntry* debug_get_trace_log();
// Read the last recorded assertion code, or the zero value installed by initialization.
u16 debug_get_last_assert();
#define KITAQGB_TRACE_U8(name, value) debug_trace_u8((const u8*)(name), (u8)(value))
#define KITAQGB_TRACE_U16(name, value) debug_trace_u16((const u8*)(name), (u16)(value))
#define KITAQGB_TRACE(name, value) debug_trace_u16((const u8*)(name), (u16)(value))
#define KITAQGB_MARK_FRAME(label) debug_mark_frame((const u8*)(label))
#define KITAQGB_ASSERT(cond) do { if (!(cond)) debug_assert_fail((u16)1); } while (0)
#define KITAQGB_ASSERT_CODE(cond, code) do { if (!(cond)) debug_assert_fail((u16)(code)); } while (0)kitaqgb/lib/debug.h
dmg3d.h — DMG 的 128×120 單色線框
// Compatibility names for the shared wire3d_dmg renderer.
// Select the same profile in every translation unit; compile one renderer entry.
#pragma once
#ifndef WIRE3D_DMG_HEIGHT
#define WIRE3D_DMG_HEIGHT 120
#endif
#if WIRE3D_DMG_HEIGHT != 120
#error Incompatible wire3d_dmg profile
#endif
#include "wire3d_dmg.h"
// The aliases below add no calls or storage. Their contracts are documented at the corresponding wire3d_dmg.h declarations.
#define DMG3D_ANGLE_STEPS WIRE3D_DMG_ANGLE_STEPS
#define DMG3D_AUX_COL_BYTES WIRE3D_DMG_AUX_COL_BYTES
#define DMG3D_AUX_ROWS WIRE3D_DMG_AUX_ROWS
#define DMG3D_BG_QUEUE_LIMIT WIRE3D_DMG_BG_QUEUE_LIMIT
#define DMG3D_BeginFrame Wire3DDMG_BeginFrame
#define DMG3D_CENTER_X WIRE3D_DMG_CENTER_X
#define DMG3D_CENTER_Y WIRE3D_DMG_CENTER_Y
#define DMG3D_DrawIndexedEdges Wire3DDMG_DrawIndexedEdges
#define DMG3D_DrawLine2D Wire3DDMG_DrawLine2D
#define DMG3D_DrawLine3D Wire3DDMG_DrawLine3D
#define DMG3D_DrawModel Wire3DDMG_DrawModel
#define DMG3D_DrawModelScaled Wire3DDMG_DrawModelScaled
#define DMG3D_DrawScene Wire3DDMG_DrawScene
#define DMG3D_Edge Wire3DDMG_Edge
#define DMG3D_EdgeFaces Wire3DDMG_EdgeFaces
#define DMG3D_EndFrame Wire3DDMG_EndFrame
#define DMG3D_EraseModelFaces Wire3DDMG_EraseModelFaces
#define DMG3D_EraseSpan2D Wire3DDMG_EraseSpan2D
#define DMG3D_EraseTriangle2D Wire3DDMG_EraseTriangle2D
#define DMG3D_FACE_NONE WIRE3D_DMG_FACE_NONE
#define DMG3D_FAR_Z WIRE3D_DMG_FAR_Z
#define DMG3D_Face Wire3DDMG_Face
#define DMG3D_Init Wire3DDMG_Init
#define DMG3D_MODEL_FACE_LIMIT WIRE3D_DMG_MODEL_FACE_LIMIT
#define DMG3D_MODEL_HIDDEN_LINES WIRE3D_DMG_MODEL_HIDDEN_LINES
#define DMG3D_MODEL_VERTEX_LIMIT WIRE3D_DMG_MODEL_VERTEX_LIMIT
#define DMG3D_Model Wire3DDMG_Model
#define DMG3D_NEAR_Z WIRE3D_DMG_NEAR_Z
#define DMG3D_Object Wire3DDMG_Object
#define DMG3D_PROJECT_LIMIT WIRE3D_DMG_PROJECT_LIMIT
#define DMG3D_ProjectPoint Wire3DDMG_ProjectPoint
#define DMG3D_PutBgTile Wire3DDMG_PutBgTile
#define DMG3D_ROW_BYTES WIRE3D_DMG_ROW_BYTES
#define DMG3D_RotatePoint Wire3DDMG_RotatePoint
#define DMG3D_SCENE_OBJECT_LIMIT WIRE3D_DMG_SCENE_OBJECT_LIMIT
#define DMG3D_SCREEN_H WIRE3D_DMG_SCREEN_H
#define DMG3D_SCREEN_W WIRE3D_DMG_SCREEN_W
#define DMG3D_SetAuxTransfer Wire3DDMG_SetAuxTransfer
#define DMG3D_SetCamera Wire3DDMG_SetCamera
#define DMG3D_SetDirtyTransfer Wire3DDMG_SetDirtyTransfer
#define DMG3D_SetPalette Wire3DDMG_SetPalette
#define DMG3D_TILE_H WIRE3D_DMG_TILE_H
#define DMG3D_TILE_W WIRE3D_DMG_TILE_W
#define DMG3D_TRANSFORM_LIMIT WIRE3D_DMG_TRANSFORM_LIMIT
#define DMG3D_TransferAuxNow Wire3DDMG_TransferAuxNow
#define DMG3D_TransferMainNow Wire3DDMG_TransferMainNow
#define DMG3D_Vec3 Wire3DDMG_Vec3
// The remaining aliases retain internal identifiers for source compatibility; they do not define an independent renderer.
#define DMG3D_abs_i16 w3ddmg_abs_i16
#define DMG3D_angle_index w3ddmg_angle_index
#define DMG3D_aux_transfer_enabled w3ddmg_aux_transfer_enabled
#define DMG3D_bg_map_9800 w3ddmg_bg_map_9800
#define DMG3D_bgq_addr_hi w3ddmg_bgq_addr_hi
#define DMG3D_bgq_addr_lo w3ddmg_bgq_addr_lo
#define DMG3D_bgq_count w3ddmg_bgq_count
#define DMG3D_bgq_tile w3ddmg_bgq_tile
#define DMG3D_bgq_value w3ddmg_bgq_value
#define DMG3D_bgq_x w3ddmg_bgq_x
#define DMG3D_bgq_y w3ddmg_bgq_y
#define DMG3D_bit_mask w3ddmg_bit_mask
#define DMG3D_build_face_visibility w3ddmg_build_face_visibility
#define DMG3D_cam_pitch w3ddmg_cam_pitch
#define DMG3D_cam_roll w3ddmg_cam_roll
#define DMG3D_cam_x w3ddmg_cam_x
#define DMG3D_cam_y w3ddmg_cam_y
#define DMG3D_cam_yaw w3ddmg_cam_yaw
#define DMG3D_cam_z w3ddmg_cam_z
#define DMG3D_clamp_i16 w3ddmg_clamp_i16
#define DMG3D_clamp_screen w3ddmg_clamp_screen
#define DMG3D_clear_dirty_tables w3ddmg_clear_dirty_tables
#define DMG3D_clear_occlusion_mask w3ddmg_clear_occlusion_mask
#define DMG3D_clear_occlusion_mask_asm w3ddmg_clear_occlusion_mask_asm
#define DMG3D_clear_stage_asm w3ddmg_clear_stage_asm
#define DMG3D_clear_stage_aux_asm w3ddmg_clear_stage_aux_asm
#define DMG3D_clear_triangle w3ddmg_clear_triangle
#define DMG3D_clear_vram_asm w3ddmg_clear_vram_asm
#define DMG3D_cos_q6 w3ddmg_cos_q6
#define DMG3D_dirty_dst_hi w3ddmg_dirty_dst_hi
#define DMG3D_dirty_dst_lo w3ddmg_dirty_dst_lo
#define DMG3D_dirty_src_hi w3ddmg_dirty_src_hi
#define DMG3D_dirty_src_lo w3ddmg_dirty_src_lo
#define DMG3D_dirty_tiles w3ddmg_dirty_tiles
#define DMG3D_dirty_transfer_enabled w3ddmg_dirty_transfer_enabled
#define DMG3D_edge_area w3ddmg_edge_area
#define DMG3D_face_visible w3ddmg_face_visible
#define DMG3D_fill_bg_map_asm w3ddmg_fill_bg_map_asm
#define DMG3D_flush_bg_queue w3ddmg_flush_bg_queue
#define DMG3D_i16 w3ddmg_i16
#define DMG3D_i8 w3ddmg_i8
#define DMG3D_inv_depth w3ddmg_inv_depth
#define DMG3D_is_edge_visible w3ddmg_is_edge_visible
#define DMG3D_line_dx w3ddmg_line_dx
#define DMG3D_line_dy w3ddmg_line_dy
#define DMG3D_line_err w3ddmg_line_err
#define DMG3D_line_stage_asm w3ddmg_line_stage_asm
#define DMG3D_line_stage_masked_c w3ddmg_line_stage_masked_c
#define DMG3D_line_sx w3ddmg_line_sx
#define DMG3D_line_sy w3ddmg_line_sy
#define DMG3D_line_x w3ddmg_line_x
#define DMG3D_line_x0 w3ddmg_line_x0
#define DMG3D_line_x1 w3ddmg_line_x1
#define DMG3D_line_y w3ddmg_line_y
#define DMG3D_line_y0 w3ddmg_line_y0
#define DMG3D_line_y1 w3ddmg_line_y1
#define DMG3D_mark_line_dirty w3ddmg_mark_line_dirty
#define DMG3D_mark_model_occluder w3ddmg_mark_model_occluder
#define DMG3D_mark_rect_dirty w3ddmg_mark_rect_dirty
#define DMG3D_mark_tile_dirty w3ddmg_mark_tile_dirty
#define DMG3D_mark_triangle w3ddmg_mark_triangle
#define DMG3D_mask_get w3ddmg_mask_get
#define DMG3D_mask_offset w3ddmg_mask_offset
#define DMG3D_mask_set w3ddmg_mask_set
#define DMG3D_mask_set_span w3ddmg_mask_set_span
#define DMG3D_neg_angle w3ddmg_neg_angle
#define DMG3D_occlusion_active w3ddmg_occlusion_active
#define DMG3D_occlusion_mask w3ddmg_occlusion_mask
#define DMG3D_plot_stage_asm w3ddmg_plot_stage_asm
#define DMG3D_plot_tx w3ddmg_plot_tx
#define DMG3D_plot_x w3ddmg_plot_x
#define DMG3D_plot_y w3ddmg_plot_y
#define DMG3D_prev_dirty_tiles w3ddmg_prev_dirty_tiles
#define DMG3D_project_camera_space w3ddmg_project_camera_space
#define DMG3D_project_world w3ddmg_project_world
#define DMG3D_put_bg_tile_safe_asm w3ddmg_put_bg_tile_safe_asm
#define DMG3D_reg_bgp w3ddmg_reg_bgp
#define DMG3D_reg_lcdc w3ddmg_reg_lcdc
#define DMG3D_reg_ly w3ddmg_reg_ly
#define DMG3D_reg_scx w3ddmg_reg_scx
#define DMG3D_reg_scy w3ddmg_reg_scy
#define DMG3D_rotate_x w3ddmg_rotate_x
#define DMG3D_rotate_y w3ddmg_rotate_y
#define DMG3D_rotate_z w3ddmg_rotate_z
#define DMG3D_scene_depth w3ddmg_scene_depth
#define DMG3D_scene_object_depth w3ddmg_scene_object_depth
#define DMG3D_scene_order w3ddmg_scene_order
#define DMG3D_screen_delta w3ddmg_screen_delta
#define DMG3D_screen_visible w3ddmg_screen_visible
#define DMG3D_screen_x w3ddmg_screen_x
#define DMG3D_screen_y w3ddmg_screen_y
#define DMG3D_sin_q6 w3ddmg_sin_q6
#define DMG3D_stage w3ddmg_stage
#define DMG3D_stage_clear_pixel w3ddmg_stage_clear_pixel
#define DMG3D_stage_clear_span w3ddmg_stage_clear_span
#define DMG3D_transfer_dirty_stage w3ddmg_transfer_dirty_stage
#define DMG3D_transfer_dirty_tile_asm w3ddmg_transfer_dirty_tile_asm
#define DMG3D_transfer_stage_asm w3ddmg_transfer_stage_asm
#define DMG3D_transfer_stage_aux_asm w3ddmg_transfer_stage_aux_asm
#define DMG3D_u16 w3ddmg_u16
#define DMG3D_u8 w3ddmg_u8
#define DMG3D_vram_tiles w3ddmg_vram_tiles
#define DMG3D_wait_vblank_start w3ddmg_wait_vblank_start
#define dmg3d w3ddmg
#define dmg3d_pair_aux_block w3ddmg_pair_aux_block
#define dmg3d_pair_aux_done w3ddmg_pair_aux_done
#define dmg3d_pair_aux_wait_0 w3ddmg_pair_aux_wait_0
#define dmg3d_pair_aux_wait_1 w3ddmg_pair_aux_wait_1
#define dmg3d_pair_aux_wait_10 w3ddmg_pair_aux_wait_10
#define dmg3d_pair_aux_wait_11 w3ddmg_pair_aux_wait_11
#define dmg3d_pair_aux_wait_12 w3ddmg_pair_aux_wait_12
#define dmg3d_pair_aux_wait_13 w3ddmg_pair_aux_wait_13
#define dmg3d_pair_aux_wait_14 w3ddmg_pair_aux_wait_14
#define dmg3d_pair_aux_wait_15 w3ddmg_pair_aux_wait_15
#define dmg3d_pair_aux_wait_16 w3ddmg_pair_aux_wait_16
#define dmg3d_pair_aux_wait_17 w3ddmg_pair_aux_wait_17
#define dmg3d_pair_aux_wait_18 w3ddmg_pair_aux_wait_18
#define dmg3d_pair_aux_wait_19 w3ddmg_pair_aux_wait_19
#define dmg3d_pair_aux_wait_2 w3ddmg_pair_aux_wait_2
#define dmg3d_pair_aux_wait_20 w3ddmg_pair_aux_wait_20
#define dmg3d_pair_aux_wait_21 w3ddmg_pair_aux_wait_21
#define dmg3d_pair_aux_wait_22 w3ddmg_pair_aux_wait_22
#define dmg3d_pair_aux_wait_23 w3ddmg_pair_aux_wait_23
#define dmg3d_pair_aux_wait_24 w3ddmg_pair_aux_wait_24
#define dmg3d_pair_aux_wait_25 w3ddmg_pair_aux_wait_25
#define dmg3d_pair_aux_wait_26 w3ddmg_pair_aux_wait_26
#define dmg3d_pair_aux_wait_27 w3ddmg_pair_aux_wait_27
#define dmg3d_pair_aux_wait_3 w3ddmg_pair_aux_wait_3
#define dmg3d_pair_aux_wait_4 w3ddmg_pair_aux_wait_4
#define dmg3d_pair_aux_wait_5 w3ddmg_pair_aux_wait_5
#define dmg3d_pair_aux_wait_6 w3ddmg_pair_aux_wait_6
#define dmg3d_pair_aux_wait_7 w3ddmg_pair_aux_wait_7
#define dmg3d_pair_aux_wait_8 w3ddmg_pair_aux_wait_8
#define dmg3d_pair_aux_wait_9 w3ddmg_pair_aux_wait_9
#define dmg3d_pair_main_block w3ddmg_pair_main_block
#define dmg3d_pair_main_wait_0 w3ddmg_pair_main_wait_0
#define dmg3d_pair_main_wait_1 w3ddmg_pair_main_wait_1
#define dmg3d_pair_main_wait_10 w3ddmg_pair_main_wait_10
#define dmg3d_pair_main_wait_11 w3ddmg_pair_main_wait_11
#define dmg3d_pair_main_wait_12 w3ddmg_pair_main_wait_12
#define dmg3d_pair_main_wait_13 w3ddmg_pair_main_wait_13
#define dmg3d_pair_main_wait_14 w3ddmg_pair_main_wait_14
#define dmg3d_pair_main_wait_2 w3ddmg_pair_main_wait_2
#define dmg3d_pair_main_wait_3 w3ddmg_pair_main_wait_3
#define dmg3d_pair_main_wait_4 w3ddmg_pair_main_wait_4
#define dmg3d_pair_main_wait_5 w3ddmg_pair_main_wait_5
#define dmg3d_pair_main_wait_6 w3ddmg_pair_main_wait_6
#define dmg3d_pair_main_wait_7 w3ddmg_pair_main_wait_7
#define dmg3d_pair_main_wait_8 w3ddmg_pair_main_wait_8
#define dmg3d_pair_main_wait_9 w3ddmg_pair_main_wait_9
#define dmg3dac_col w3ddmgac_col
#define dmg3dac_enter w3ddmgac_enter
#define dmg3dac_row w3ddmgac_row
#define dmg3dbg_enter w3ddmgbg_enter
#define dmg3dco_enter w3ddmgco_enter
#define dmg3dco_loop w3ddmgco_loop
#define dmg3dco_page w3ddmgco_page
#define dmg3dcs_enter w3ddmgcs_enter
#define dmg3dcs_inner w3ddmgcs_inner
#define dmg3dcs_outer w3ddmgcs_outer
#define dmg3dcv_enter w3ddmgcv_enter
#define dmg3dcv_loop w3ddmgcv_loop
#define dmg3dcv_page w3ddmgcv_page
#define dmg3ddt_enter w3ddmgdt_enter
#define dmg3ddt_loop w3ddmgdt_loop
#define dmg3dfb_enter w3ddmgfb_enter
#define dmg3dfb_loop w3ddmgfb_loop
#define dmg3dfb_page w3ddmgfb_page
#define dmg3dls_branch w3ddmgls_branch
#define dmg3dls_done w3ddmgls_done
#define dmg3dls_enter w3ddmgls_enter
#define dmg3dls_shallow w3ddmgls_shallow
#define dmg3dls_shallow_loop w3ddmgls_shallow_loop
#define dmg3dls_shallow_skip_bridge w3ddmgls_shallow_skip_bridge
#define dmg3dls_steep w3ddmgls_steep
#define dmg3dls_steep_loop w3ddmgls_steep_loop
#define dmg3dls_steep_skip_bridge w3ddmgls_steep_skip_bridge
#define dmg3dls_x_reverse w3ddmgls_x_reverse
#define dmg3dls_y_reverse w3ddmgls_y_reverse
#define dmg3dls_y_start w3ddmgls_y_start
#define dmg3dps_enter w3ddmgps_enter
#define dmg3dps_ret w3ddmgps_retkitaqgb/lib/dmg3d.h
entity.h — 固定陣列物件池
#pragma once
// Keep capacity in 1..255: IDs and scan counters are bytes and FF is reserved for failure.
// Use the same definition in every compilation unit.
#ifndef ENTITY_MAX
#define ENTITY_MAX ((u8)16)
#endif
// Position, velocity, state and timer units are game-defined; the pool does not advance them.
// The sprite field is only bookkeeping and does not allocate or release OAM entries.
typedef __packed struct {
u8 active;
u8 type;
s16 x;
s16 y;
s16 vx;
s16 vy;
u8 state;
u8 timer;
u8 sprite;
} Entity;
// An entity callback receives a slot ID, not a persistent object handle.
typedef void (*EntityFn)(u8 id);
// Reset every slot before the game starts using the pool.
void entity_init();
// Returns a reusable slot ID, or 0xFF if no slot is free.
u8 entity_create(u8 type, s16 x, s16 y);
// Release a valid slot without clearing its payload. Reallocation resets the payload;
// a saved pointer or ID must not be treated as a persistent entity identity.
void entity_destroy(u8 id);
// Returns null for an invalid or inactive ID; the returned pointer aliases reusable pool storage.
Entity* entity_get(u8 id);
// Call fn for each slot that is active when the scan reaches it; null is a no-op.
// Callbacks may change the pool, so newly activated later slots can run in this pass.
void entity_update_all(EntityFn fn);
// Use the same active-slot traversal for drawing; the callback supplies all rendering.
void entity_draw_all(EntityFn fn);
// Count occupied slots without changing entity state.
u8 entity_count_active();
// Release every entity and restore deterministic defaults, including the no-sprite sentinel.
void entity_clear_all();kitaqgb/lib/entity.h
fixed.h — Q8.8 定點運算與矩形
#pragma once
// Signed Q8.8 uses 256 units per pixel/value: the range is -128 to 127 + 255/256.
typedef s16 fix8;
#define FIX_ONE ((fix8)256)
#define FIX_HALF ((fix8)128)
typedef __packed struct {
fix8 x;
fix8 y;
} Vec2;
typedef __packed struct {
s16 x;
s16 y;
s16 w;
s16 h;
} KQRect;
// Convert an integer to signed 8.8 fixed point by moving it into the high byte.
// The caller must keep the result within the representable 16-bit range.
fix8 fix_from_int(s16 n);
// Discard the eight fractional bits using a signed right shift.
s16 fix_to_int(fix8 x);
// Approximate 8.8 multiplication by discarding four low bits from each operand
// before multiplying. This trades precision for a smaller intermediate product.
fix8 fix_mul(fix8 a, fix8 b);
// Scale the reduced-precision quotient back to 8.8 and return zero for b == 0.
// Callers must also ensure (b >> 4) is nonzero; the explicit check only tests b.
// The intermediate product must fit the compiler's integer arithmetic.
fix8 fix_div(fix8 a, fix8 b);
// Interpolate toward b using a quantized Q0.8 weight. Both shifts discard low
// bits, so small changes may vanish and a weight of 255 need not reach b.
fix8 fix_lerp(fix8 a, fix8 b, u8 t_q8);
// Return the magnitude in s16. The most-negative s16 has no positive s16
// representation and must be excluded by callers needing a nonnegative result.
s16 kq_abs_s16(s16 v);
// Select the smaller signed value.
s16 kq_min_s16(s16 a, s16 b);
// Select the larger signed value.
s16 kq_max_s16(s16 a, s16 b);
// Clamp to an inclusive interval; callers must provide lo <= hi.
s16 kq_clamp_s16(s16 v, s16 lo, s16 hi);
// Test overlap using exclusive right/bottom edges; touching edges do not collide.
// Require positive dimensions and edge sums that fit s16; zero-sized rectangles
// are not explicitly rejected and may be reported as overlapping.
u8 kq_rect_intersect(KQRect a, KQRect b);
// Test a half-open rectangle: left/top edges are included, right/bottom excluded.
// The coordinate-plus-size sums must remain representable as s16.
u8 kq_point_in_rect(s16 x, s16 y, KQRect r);kitaqgb/lib/fixed.h
input.h — 按鈕狀態、按下、放開及重複
#pragma once
#define BTN_RIGHT ((u8)0x01)
#define BTN_LEFT ((u8)0x02)
#define BTN_UP ((u8)0x04)
#define BTN_DOWN ((u8)0x08)
#define BTN_A ((u8)0x10)
#define BTN_B ((u8)0x20)
#define BTN_SELECT ((u8)0x40)
#define BTN_START ((u8)0x80)
// A fresh press pulses immediately. The next pulse occurs DELAY + 1 updates later.
#ifndef INPUT_REPEAT_DELAY
#define INPUT_REPEAT_DELAY ((u8)18)
#endif
// Subsequent pulses are RATE + 1 updates apart; zero repeats on every held update.
#ifndef INPUT_REPEAT_RATE
#define INPUT_REPEAT_RATE ((u8)5)
#endif
extern u8 kq_input_prev_keys;
extern u8 kq_input_keys;
extern u8 kq_input_press_keys;
extern u8 kq_input_release_keys;
extern u8 kq_input_repeat_keys;
u16 __readpadex(u8 prev_keys);
// Clear sampled/edge state and initialize an independent repeat timer for each button.
void input_init();
// Sample input once per game tick and derive press, release and repeat masks.
// Repeat delays are measured in calls to this function, not elapsed wall-clock time.
void input_update();
// Return whether any masked button is currently held.
u8 input_down(u8 mask);
// Return whether any masked button became pressed in the latest sample.
u8 input_pressed(u8 mask);
// Return whether any masked button became released in the latest sample.
u8 input_released(u8 mask);
// Return whether any masked button produced a fresh press or scheduled repeat pulse.
u8 input_repeat(u8 mask);
// Return the complete held-button mask from the latest update.
u8 input_current();
// Return the held-button mask that preceded the latest update.
u8 input_previous();
#define btn_down input_down
#define btn_pressed input_pressed
#define btn_released input_released
#define btn_repeat input_repeatkitaqgb/lib/input.h
link.h — 序列通訊與邏輯封包
#pragma once
// Shared Game Boy serial link library for KITAQGB projects.
//
// Integration notes:
// - Compile a hardware-register file before link.c / link_packet.c so SB, SC,
// IF_REG, and IE_REG are already declared.
// - Call Link_InitMaster() on the clock-source side and Link_InitSlave() on the
// other side.
// - Call Link_Poll() or Link_PollPacket() regularly from the main loop.
// - If you enable serial IRQ mode, call Link_OnSerialIRQ() from your own
// serial interrupt handler at vector 0x0058.
// - The packet layer is intentionally small and one-deep. It works best as a
// master-driven command/response layer. The low-level byte API remains the
// escape hatch for custom protocols.
#define LINK_MODE_SLAVE ((u8)0)
#define LINK_MODE_MASTER ((u8)1)
#define LINK_CLOCK_NORMAL ((u8)0)
#define LINK_CLOCK_FAST ((u8)1)
#define LINK_ERR_NONE ((u8)0)
#define LINK_ERR_BUSY ((u8)1)
#define LINK_ERR_TIMEOUT ((u8)2)
#define LINK_ERR_OVERFLOW ((u8)3)
#define LINK_ERR_PROTOCOL ((u8)4)
#define LINK_ERR_DISCONNECT ((u8)5)
#define LINK_PKT_MAX_PAYLOAD ((u8)24)
#define LINK_RX_QUEUE_SIZE ((u8)8)
#define LINK_TX_QUEUE_SIZE ((u8)8)
#define LINK4_MODE_NONE ((u8)0)
#define LINK4_MODE_HOST ((u8)1)
#define LINK4_MODE_PEER ((u8)2)
#define LINK4_MAX_PLAYERS ((u8)4)
#define LINK4_HOST_SLOT ((u8)0)
#define LINK4_INVALID_SLOT ((u8)0xFF)
// Reset byte queues, packet mailboxes, cooperative-peer state and errors, then
// disable serial transfers and serial IRQ delivery. Existing data is discarded.
void Link_InitCommon();
// Reset link state and select the internal-clock role for subsequent transfers.
void Link_InitMaster();
// Reset link state and select the external-clock role for subsequent transfers.
void Link_InitSlave();
// Enable or disable serial IRQ delivery and clear its pending flag. Enabling
// does not install the handler. Leaving its outer critical section enables CPU interrupts.
void __stackcall Link_SetUseInterrupt(u8 on);
// Select the fast-clock bit for future master transfers; this does not restart
// an active transfer or verify that the hardware supports CGB fast mode.
void __stackcall Link_SetFastClock(u8 on);
// Poll once before returning busy state, so this query may collect a completed byte.
u8 Link_IsBusy();
// Read the ordinary receive-ready flag without polling hardware.
u8 Link_HasByte();
// Return the latest latched error without clearing it.
u8 Link_LastError();
// Clear the error latch without resetting queues or an active transfer.
void Link_ClearError();
// Start one full-duplex byte exchange, or return BUSY without replacing an
// active transfer. Slave mode arms reception and waits for external clocks.
u8 __stackcall Link_BeginTransfer(u8 out);
// Collect a pending transfer only after hardware clears the SC start bit.
void Link_Poll();
// Stop the hardware transfer under interrupt protection. Queued receive bytes
// and packet-layer state remain available; this is not a full protocol reset.
void Link_Cancel();
// Acknowledge serial IRQ and finish a software-busy transfer. Call this from
// the actual serial interrupt handler, not an unrelated interrupt.
void Link_OnSerialIRQ();
// Pop the ordinary receive queue without waiting or polling hardware; null discards a byte.
u8 __stackcall Link_TryReadByte(u8 *out);
// Pop one byte, returning zero when empty. Use Link_TryReadByte when a received
// zero byte must be distinguished from an empty queue.
u8 Link_ReadByte();
// Require an output pointer, poll immediately, then wait at most timeout_frames
// VBlanks for a byte. Zero timeout still performs the initial poll and read.
u8 __stackcall Link_WaitByte(u16 timeout_frames, u8 *out);
// Validate payload size and idle packet state, copy payload bytes into owned
// storage and schedule transmission. Return success means queued, not acknowledged;
// keep polling to progress the exchange and inspect the error latch.
u8 __stackcall Link_SendPacket(const u8 *data, u8 len, u8 cmd);
// Drain received bytes, advance one outgoing exchange and update the retry
// timer. Timeout ticks count calls without progress, not hardware frames; call
// with a controlled cadence and avoid mixing raw reads with packet consumption.
void Link_PollPacket();
// Inspect the shared completed-packet flag without advancing the protocol.
u8 Link_HasPacket();
// Consume the shared packet mailbox and its matching peer flag. Any output
// may be null; a nonnull destination needs room for the received payload because
// there is no destination-capacity argument.
u8 __stackcall Link_ReadPacket(u8 *cmd, u8 *len, u8 *dst);
// Cooperative 4-player adapter helpers.
//
// This layer models the common host-selected adapter pattern:
// - Slot 0 is always the host.
// - The host selects one active peer slot at a time.
// - Packet mailboxes stay one-deep per peer.
// - The original Link_* API remains available for normal 2-player projects.
// Reset as master, validate slot count and select logical peer one. Invalid configuration still discards old link state.
u8 __stackcall Link4_InitHost(u8 slot_count);
// Reset as slave and validate the local nonzero slot and total slot count.
// An invalid configuration still discards the previous link state.
u8 __stackcall Link4_InitPeer(u8 local_slot, u8 slot_count);
// Return the configured cooperative role; this is not a hardware connection probe.
u8 Link4_GetMode();
// Return the configured zero-based local slot.
u8 Link4_GetLocalSlot();
// Return the configured number of logical slots, not a live connection count.
u8 Link4_GetSlotCount();
// Return the current logical destination, or the invalid-slot sentinel when unset.
u8 Link4_GetSelectedPeer();
// Return the peer attributed to the last completed byte transfer.
u8 Link4_GetLastRxPeer();
// Return the peer attributed when the last byte transfer was started.
u8 Link4_GetLastTxPeer();
// Poll completion, then change the logical destination only while byte and
// packet state are idle. A peer can select only the host. No adapter-routing
// command is sent here; the transport must provide the matching physical route.
u8 __stackcall Link4_SelectPeer(u8 peer_slot);
// Select the logical peer and start a byte exchange, returning the first error.
u8 __stackcall Link4_BeginTransferTo(u8 peer_slot, u8 out);
// Inspect a valid peer ring without polling the hardware.
u8 __stackcall Link4_HasByteFrom(u8 peer_slot);
// Pop one byte from the selected peer ring; null output discards it.
u8 __stackcall Link4_TryReadByteFrom(u8 peer_slot, u8 *out);
// Scan remote rings in increasing slot order and return the first available
// byte. Null output pointers are allowed; lower slots have polling priority.
u8 __stackcall Link4_TryReadByteAny(u8 *peer_slot, u8 *out);
// Select a logical peer, then copy and schedule a packet; return the first error.
u8 __stackcall Link4_SendPacketTo(u8 peer_slot, const u8 *data, u8 len, u8 cmd);
// Advance the shared packet engine; this does not poll every logical peer in turn.
void Link4_PollPacket();
// Inspect the one-packet mailbox for a valid remote slot without consuming it.
u8 __stackcall Link4_HasPacketFrom(u8 peer_slot);
// Consume a peer mailbox, copying to optional outputs. A nonnull destination
// needs room for the entire payload. Clear the shared mailbox only when it
// refers to this same peer.
u8 __stackcall Link4_ReadPacketFrom(u8 peer_slot, u8 *cmd, u8 *len, u8 *dst);kitaqgb/lib/link.h
link_dmg07.h — DMG-07 外部時脈通訊
#pragma once
// Polling driver for the physical Nintendo DMG-07 Four Player Adapter.
//
// The adapter supplies every serial clock. LinkDmg07_Poll() must therefore be
// called frequently enough to re-arm the serial port between adapter bytes;
// calling it only once per video frame is not sufficient. Call
// LinkDmg07_TickFrame() exactly once per frame for timeout accounting.
//
// Transmission uses SIZE=1: every adapter packet contains four bytes, one for
// each physical player slot. A console sends its local byte during byte 0 and
// sends zero during bytes 1..3, except while emitting an aligned FF restart
// packet. The adapter broadcasts those four submitted bytes in the following
// packet. The initial broadcast contains undefined adapter data and is
// discarded by this driver.
#define LINK_DMG07_PHASE_PING ((u8)0)
#define LINK_DMG07_PHASE_REQUEST_AA ((u8)1)
#define LINK_DMG07_PHASE_WAIT_CC ((u8)2)
#define LINK_DMG07_PHASE_TRANSFER ((u8)3)
#define LINK_DMG07_MAX_PLAYERS ((u8)4)
#define LINK_DMG07_PACKET_BYTES ((u8)4)
#define LINK_DMG07_SIZE ((u8)1)
// Physical slots here are one-based; do not substitute the zero-based Link4 cooperative slot identifiers.
#define LINK_DMG07_NO_SLOT ((u8)0)
// RATE $10 gives the shortest documented packet period for SIZE=1 while
// retaining the adapter's normal inter-byte pacing. RATE $00 is not used.
#define LINK_DMG07_DEFAULT_RATE ((u8)0x10)
#ifndef LINK_DMG07_TIMEOUT_FRAMES
#define LINK_DMG07_TIMEOUT_FRAMES ((u8)12)
#endif
#define LINK_DMG07_ERR_NONE ((u8)0)
#define LINK_DMG07_ERR_STATE ((u8)1)
#define LINK_DMG07_ERR_NOT_PLAYER1 ((u8)2)
#define LINK_DMG07_ERR_NOT_READY ((u8)3)
#define LINK_DMG07_ERR_TIMEOUT ((u8)4)
#define LINK_DMG07_ERR_PROTOCOL ((u8)5)
#define LINK_DMG07_ERR_OVERFLOW ((u8)6)
#define LINK_DMG07_RESTART_NONE ((u8)0)
#define LINK_DMG07_RESTART_PENDING ((u8)1)
#define LINK_DMG07_RESTART_SENDING ((u8)2)
// Initializes polling-only external-clock operation. A zero RATE is replaced
// with LINK_DMG07_DEFAULT_RATE. This driver disables only the serial IRQ bit.
void __stackcall LinkDmg07_Init(u8 rate);
// Services at most one completed serial byte and immediately re-arms SC=$80.
// Call continuously from the main loop, including between VBlanks.
void LinkDmg07_Poll();
// Advances saturating frame-based silence and handshake timeout counters.
void LinkDmg07_TickFrame();
// Return the discovery, start-handshake or transfer phase without polling.
u8 LinkDmg07_GetPhase();
// Return the one-based player slot, or LINK_DMG07_NO_SLOT before discovery.
u8 LinkDmg07_GetLocalSlot();
// Normalized mask: bit 0 is player 1, ..., bit 3 is player 4.
u8 LinkDmg07_GetConnectedMask();
// Return the last validated raw adapter status byte.
u8 LinkDmg07_GetLastStatus();
// Read the completed-discovery status flag without clearing it.
u8 LinkDmg07_HasPingStatus();
// Clear and report the completed-discovery flag; return zero if no new status exists.
u8 LinkDmg07_ConsumePingStatus();
// Only physical player 1 may request AA AA AA AA. The bytes are aligned to
// the next FE/status/status/status ping packet. All consoles enter transfer
// mode only after receiving four consecutive CC bytes.
u8 LinkDmg07_RequestTransmission();
// Any physical slot may schedule FF FF FF FF at the next four-byte packet
// boundary while remaining in TRANSFER phase. The driver keeps sending aligned
// FF bytes until it sees the adapter's complete all-FF indicator packet, then
// returns to PING. A transfer-phase silence timeout schedules the same recovery
// automatically and preserves the current byte position for clocks that resume.
u8 LinkDmg07_RequestRestart();
// Return whether aligned recovery is absent, pending or sending control traffic.
u8 LinkDmg07_GetRestartState();
// Sets the byte sampled when byte 0 of the next adapter packet is armed.
// Set it before the current packet completes (and before requesting start for
// the first submission). During normal transfer, bytes 1..3 are sent as zero.
void __stackcall LinkDmg07_SetLocalByte(u8 value);
// The first incoming adapter data packet is discarded. Thereafter ReadPacket
// copies four bytes in physical slot order (players 1..4).
u8 LinkDmg07_IsPipelinePrimed();
// Inspect the one-packet receive mailbox without consuming it.
u8 LinkDmg07_HasPacket();
// Consume the latest four-byte packet. A nonnull destination must hold four
// bytes; null discards the packet. Packet storage remains after the flag clears.
u8 __stackcall LinkDmg07_ReadPacket(u8 *dst);
// Read one cached player byte using a one-based slot. Invalid slots return
// zero; the function neither requires readiness nor consumes the packet.
u8 __stackcall LinkDmg07_GetPacketSlot(u8 player_slot);
// SentSequence increments when this console's packet byte is clocked out.
// PacketSequence labels the returned four-byte packet. For a valid packet it
// is one less than SentSequence, making the DMG-07 one-packet delay explicit.
u8 LinkDmg07_GetSentSequence();
// Return the modulo-256 sequence associated with the most recently published packet.
u8 LinkDmg07_GetPacketSequence();
// SilenceFrames is reset by every completed serial byte. TimeoutCount counts
// distinct serial-silence or AA/CC/restart handshake timeouts. DisconnectCount counts
// adapter-silence outages and ping-status membership drops. All saturate.
u8 LinkDmg07_GetSilenceFrames();
// Return the saturating lifetime timeout count, preserved across protocol restarts.
u8 LinkDmg07_GetTimeoutCount();
// Return the saturating count of removed-player and previously-seen-adapter timeout events.
u8 LinkDmg07_GetDisconnectCount();
// Return the saturating protocol/overflow error count. Timeout and request
// validation paths use separate counters or latches and do not increment this value.
u8 LinkDmg07_GetErrorCount();
// Return the latest error latch without clearing counters or restarting the protocol.
u8 LinkDmg07_LastError();
// Clear only the latest error code, preserving counters and protocol state.
void LinkDmg07_ClearError();kitaqgb/lib/link_dmg07.h
physics2d.h — 2D 運動與碰撞
#pragma once
// Position and velocity use caller-selected integer units with one integration
// step per call; no hidden pixel or time conversion occurs. Keep intermediate
// signed arithmetic in range. World/body storage is owned by the caller.
#include "fixed.h"
// Multiply a signed word by a signed byte; divide by 256, truncating toward zero.
s16 __smul16x8(s16 a, s8 b);
// Lightweight deterministic 2D physics for KITAQGB.
// Integer pixels per step are one possible unit convention; inv_mass is Q8.
typedef struct {
s16 x;
s16 y;
s16 vx;
s16 vy;
s16 half_x;
s16 half_y;
s16 inv_mass_q8; // 0 means static body.
s16 restitution_q8; // 0..255 (reserved for future tuning).
u8 active;
} KQBody2D;
typedef struct {
KQBody2D* bodies;
u8 body_count;
s16 gravity_x;
s16 gravity_y;
u8 solver_iterations;
s16 max_speed;
} KQWorld2D;
// Retain the caller-owned body array without initializing its elements.
// Set gravity to (0,32), four contact iterations and a per-axis speed limit of 512.
// A null world is ignored; the array must outlive subsequent world operations.
void kq2d_world_init(KQWorld2D* world, KQBody2D* bodies, u8 body_count);
// Advance active dynamic bodies, then visit each active unordered pair for
// the configured contact passes (zero means one). Static bodies still participate
// as obstacles. The world borrows its array and shares non-reentrant ASM scratch.
// This is discrete integration; fast bodies can pass through thin obstacles.
void kq2d_step(KQWorld2D* world);
// For one active dynamic body, add gravity, clamp each velocity axis and then
// add velocity to position. Null inputs are ignored; no contacts are solved.
// Use a nonnegative speed limit and keep additions in signed 16-bit range.
void kq2d_integrate_body(KQWorld2D* world, KQBody2D* body);
// Test strict overlap of two centered boxes; touching edges return false.
// Both pointers must be valid. Active/mass flags are ignored, and coordinate
// differences and extent sums must fit the signed 16-bit calculations.
u8 kq2d_overlap_aabb(const KQBody2D* a, const KQBody2D* b);
// Initialize an active unit-inverse-mass body at the supplied center and half
// extents, with zero velocity and reserved restitution set to zero. Null is ignored.
void kq2d_body_init(KQBody2D* body, s16 x, s16 y, s16 half_x, s16 half_y);
// Replace the center without altering velocity, extents or activity. Null is ignored.
void kq2d_body_set_pos(KQBody2D* body, s16 x, s16 y);
// Replace velocity without clamping or checking activity/mass. Null is ignored.
void kq2d_body_set_velocity(KQBody2D* body, s16 vx, s16 vy);
// Add gravity and clamp each velocity axis separately for an active dynamic
// body. Null, inactive and static bodies are ignored. Supply a nonnegative limit
// and avoid overflow in the additions before clamping; position is unchanged.
void kq2d_body_apply_gravity(KQBody2D* body, s16 gravity_x, s16 gravity_y, s16 max_speed);
// Scale both velocities through the signed 8-bit coefficient intrinsic.
// Despite the unsigned parameter, values 128..255 become negative coefficients;
// this is not a full-range unsigned Q8 damping helper. Null is ignored.
void kq2d_body_apply_friction(KQBody2D* body, u8 friction_q8);
// Delegate strict rectangle overlap to the fixed-point utility; edge-only
// contact is false. Coordinate-plus-size sums must remain representable as s16.
u8 kq2d_rect_intersect(KQRect a, KQRect b);
// Delegate the half-open point test: include left/top and exclude right/bottom.
// Coordinate-plus-size sums must remain representable as s16.
u8 kq2d_point_in_rect(s16 x, s16 y, KQRect r);
// Opt-in surface solver. Velocities/threshold/kick share the caller's units.
// Normal must be unit length in Q8; coefficients are 0..255.
typedef struct {
s16 nx_q8;
s16 ny_q8;
s16 vx;
s16 vy;
s16 bounce_threshold;
s16 kick;
u8 restitution_q8;
u8 friction_q8;
} KQSurface2D;
// Truncates toward zero, including negative values; coefficient is -256..256.
s16 kq2d_scale_q8(s16 value, s16 coefficient);
// Conservative circular bound, with a shared Q8 scale for both components.
// Quantizes toward zero; very small limits relative to input may yield zero.
// Components and positive max_speed must be <= 16383 in magnitude.
void kq2d_body_limit_speed(KQBody2D* body, s16 max_speed);
// Kinematic surface response; returns incoming normal speed, or zero if separating.
// Caller resolves penetration separately. Relative components must fit +/-8191.
s16 kq2d_body_resolve_surface(KQBody2D* body, const KQSurface2D* surface);
// Linear crossing time in Q8 (0..256); positive separation is outside.
// Returns 0 for initial overlap, 256 for no crossing. Gaps must fit +/-8191.
u16 kq2d_surface_toi_q8(s16 start_gap, s16 end_gap);kitaqgb/lib/physics2d.h
physics2d_circle.h — 圓形物體物理
#pragma once
// Deterministic 2D circle physics for KITAQGB.
// Intended for top-down ball games such as billiards, air hockey, and marbles.
// Use consistent caller-selected units for centers, radii and per-step velocity.
// The implementation uses 16-bit arithmetic: reduced squared-distance sums and
// weight products must fit their types. Reduction to byte-sized components alone
// is insufficient to guarantee this. Body storage remains caller-owned.
typedef struct {
s16 x;
s16 y;
s16 vx;
s16 vy;
s16 radius;
s16 inv_mass_q8; // 0 means static body.
u8 restitution_q8; // 0..255, higher means bouncier.
u8 friction_q8; // 0..255, higher removes more tangential motion.
u8 active;
} KQCircleBody2D;
typedef struct {
KQCircleBody2D* bodies;
u8 body_count;
s16 gravity_x;
s16 gravity_y;
u8 solver_iterations;
s16 max_speed;
u8 linear_damping_q8; // 255 is almost no damping, lower values damp faster.
u8 use_bounds;
s16 min_x;
s16 min_y;
s16 max_x;
s16 max_y;
u8 wall_restitution_q8;
u8 wall_friction_q8;
} KQCircleWorld2D;
// Retain a caller-owned array without initializing bodies. Set zero gravity,
// four contact passes, per-axis limit 768 and damping 252/256; bounds start disabled.
// A null world is ignored. Keep the array alive for subsequent steps.
void kq2dc_world_init(KQCircleWorld2D* world, KQCircleBody2D* bodies, u8 body_count);
// Store and enable bounds without validating their order or fitting bodies
// immediately. Supply extents large enough for body diameters. Null is ignored.
void kq2dc_set_bounds(KQCircleWorld2D* world, s16 min_x, s16 min_y, s16 max_x, s16 max_y);
// Integrate active dynamic bodies, apply bounds, solve contacts, then damp
// velocity and snap components in -1..1 to zero. Zero solver iterations means one.
// Pairs with both velocities zero are skipped, so resting overlaps can remain.
// Bounds can reposition static bodies; null world/array inputs are ignored.
void kq2dc_step(KQCircleWorld2D* world);
// Compare a reduced integer center distance with the reduced radius sum.
// Valid pointers and positive radii are required; activity and mass are ignored.
// This approximate test requires representable differences, radius sums and
// squared-distance sum. Touching at the computed distance returns false.
u8 kq2dc_overlap_circle(const KQCircleBody2D* a, const KQCircleBody2D* b);kitaqgb/lib/physics2d_circle.h
physics3d.h — 3D AABB 物理
#pragma once
// Lightweight deterministic 3D physics for KITAQGB.
// AABB contacts, acceleration, mass-weighted bounce, and impact state flags.
// The game owns break decisions: the solver records impact speeds but never
// sets this flag or deactivates a body based on break_speed. Positions, extents,
// velocities and acceleration use consistent caller-selected per-step units.
#define KQ3D_BODY_BROKEN ((u8)0x01)
typedef struct {
s16 x;
s16 y;
s16 z;
s16 vx;
s16 vy;
s16 vz;
s16 ax;
s16 ay;
s16 az;
s16 half_x;
s16 half_y;
s16 half_z;
s16 mass_q8; // 256 means mass 1.0.
s16 inv_mass_q8; // 0 means static body.
s16 restitution_q8; // 256 means perfectly elastic.
s16 break_speed; // Reserved for game-side impact thresholds.
s16 last_impact_speed;
u8 active;
u8 flags;
} KQBody3D;
typedef struct {
KQBody3D* bodies;
u8 body_count;
s16 gravity_x;
s16 gravity_y;
s16 gravity_z;
u8 solver_iterations;
s16 max_speed;
} KQWorld3D;
// Borrow the body array without initializing it. Set gravity (0,24,0), four
// contact passes and a per-axis speed limit of 512. Null world is ignored;
// the caller retains ownership and must keep the array alive.
void kq3d_world_init(KQWorld3D* world, KQBody3D* bodies, u8 body_count);
// Initialize an active centered box with zero velocity/acceleration,
// restitution 224, cleared impact/flags and mass set through the weight helper.
// The caller supplies valid half extents. Null body is ignored.
void kq3d_body_init(KQBody3D* body, s16 x, s16 y, s16 z, s16 half_x, s16 half_y, s16 half_z, s16 mass_q8);
// Store the requested mass; nonpositive mass makes the body static.
// For positive mass compute inverse weight as max(1,32767/max(mass,64)).
// The stored mass retains the original input; this is a relative solver weight,
// not an exact Q8 reciprocal. Null body is ignored.
void kq3d_body_set_mass(KQBody3D* body, s16 mass_q8);
// Integrate active dynamic bodies and reset their impact values, then solve
// each active unordered pair for the configured passes (zero means one).
// Static bodies retain previous impact maxima until the game clears them.
// Acceleration persists; flags and break thresholds remain game-owned.
// This discrete solver shares non-reentrant ASM scratch and can miss fast crossings.
void kq3d_step(KQWorld3D* world);
// Reset impact for one active dynamic body, add gravity and persistent body
// acceleration, clamp velocity per axis and advance position. Static/inactive
// bodies retain impact state. Null inputs are ignored; no contacts are solved.
// Use a nonnegative speed limit and avoid overflow before clamping.
void kq3d_integrate_body(KQWorld3D* world, KQBody3D* body);
// Test strict overlap on all three axes; face-only contact returns false.
// Valid pointers are required and flags are ignored. Center differences and
// extent sums must fit the signed 16-bit magnitude calculations.
u8 kq3d_overlap_aabb(const KQBody3D* a, const KQBody3D* b);
// Sum three signed products, shifting each by eight bits before addition.
// Coefficients are signed bytes scaled by 1/256; the 16-bit sum is not saturated.
s16 kq3d_dot_q8_8(s16 x, s16 y, s16 z, s8 ax, s8 ay, s8 az);kitaqgb/lib/physics3d.h
raster.h — 分段及逐掃描線捲動表
#pragma once
#include "scroll.h"
// Keep wrapper capacity consistent with the compiler split-table capacity; wrapper checks do not enlarge it.
#define KQ_RASTER_MAX_BANDS 8
#define KQ_RASTER_OK 0
#define KQ_RASTER_FULL 1
#define KQ_RASTER_BAD_LY 2
#define KQ_RASTER_UNSORTED 3
#define KQ_RASTER_BAD_RANGE 4
#define KQ_RASTER_BG KQ_SCROLL_SPLIT_USE_BG
#define KQ_RASTER_WIN KQ_SCROLL_SPLIT_USE_WIN
#define KQ_RASTER_WIN_SHOW KQ_SCROLL_SPLIT_WIN_SHOW
#define KQ_RASTER_WIN_HIDE KQ_SCROLL_SPLIT_WIN_HIDE
#define KQ_RASTER_BG_COLOR0 KQ_SCROLL_SPLIT_BG_COLOR0
#define KQ_RASTER_FLAG_MASK 0x1F
#define KQ_RASTER_LINE_FLAT 0
#define KQ_RASTER_LINE_X_TITLE 1
#define KQ_RASTER_LINE_TRAVEL_GATE 2
// Caller-owned wave state. Initialize it before use and keep it non-null for every LineX operation.
// frame_counter measures RunFrame calls, not an independent hardware clock.
typedef struct RasterLineX {
u8 profile;
u8 base_x;
u8 phase;
u8 phase_step;
u8 frame_divider;
u8 frame_counter;
} RasterLineX;
// Stop split scheduling, empty the shared table and clear error/count state.
void Raster_Init();
// Stop splits immediately and clear bookkeeping. Build and commit a new table to restart.
void Raster_Clear();
// Commit an empty split table so no raster bands remain active.
void Raster_Disable();
// Read the number of bands currently recorded by this wrapper.
u8 Raster_GetCount();
// Read the last stored status without clearing it.
u8 Raster_GetLastError();
// Append a validated background-scroll band and advance the monotonic-LY
// bookkeeping. A successful append clears the previous error.
u8 Raster_Push(u8 ly, u8 scx, u8 scy);
// Append a validated extended band after masking flags to supported operations.
u8 Raster_PushEx(u8 ly, u8 scx, u8 scy, u8 wx, u8 wy, u8 flags);
// Enable window updates and pass hardware WX/WY values without coordinate conversion.
u8 Raster_PushWindowRaw(u8 ly, u8 wx, u8 wy, u8 flags);
// Convert screen X to hardware WX by adding seven, then queue a window band.
// The byte addition wraps if callers supply an excessive X coordinate.
u8 Raster_PushWindowScreen(u8 ly, u8 screen_x, u8 screen_y, u8 flags);
// Queue both background and window updates, converting window screen X to WX.
u8 Raster_PushBgWindowScreen(u8 ly, u8 scx, u8 scy, u8 screen_x, u8 screen_y, u8 flags);
// Pack a 15-bit color into the extended band's two scroll-byte fields and select
// the color-zero operation, which interprets those fields as color data.
u8 Raster_PushBgColor0(u8 ly, u16 rgb15);
// Publish pending splits and return the stored status. This commits even if an
// earlier append failed; callers should inspect errors while building the table.
u8 Raster_Commit();
// Validate the HUD height, then replace pending splits with a fixed top band
// and scrolling playfield. The new table still requires an explicit commit.
u8 Raster_BuildHudTop(u8 hud_height, u8 camera_x, u8 camera_y);
// Build a scrolling upper playfield and fixed bottom HUD after validating the split.
u8 Raster_BuildHudBottom(u8 hud_y, u8 camera_x, u8 camera_y);
// Build two horizontal-scroll bands sharing one vertical scroll value.
u8 Raster_BuildParallax2(u8 split_y, u8 far_scx, u8 near_scx, u8 scy);
// Build three horizontal-scroll bands at ordered visible split lines. Invalid
// parameters leave the previous pending table intact and set the error status.
u8 Raster_BuildParallax3(u8 y1, u8 y2, u8 scx0, u8 scx1, u8 scx2, u8 scy);
// Initialize a scanline-wave state with phase zero and one phase step per frame.
void Raster_LineXInit(RasterLineX* effect, u8 profile, u8 base_x);
// Change the wave profile and restart its phase/divider counter.
void Raster_LineXSetProfile(RasterLineX* effect, u8 profile);
// Configure the phase increment and frame interval; clamp a zero interval to one.
void Raster_LineXSetSpeed(RasterLineX* effect, u8 phase_step, u8 frame_divider);
// Set the byte phase directly without resetting the frame-divider counter.
void Raster_LineXSetPhase(RasterLineX* effect, u8 phase);
// Look up the selected periodic profile at LY + phase and add base X modulo
// 256. An unknown profile returns the unmodified base X.
u8 Raster_LineXGetOffset(const RasterLineX* effect, u8 ly);
// Render all 144 visible lines with one SCX write per line, then advance phase.
// This foreground renderer masks interrupts during the visible frame. Do game
// and audio work between calls; do not combine it with a STAT raster driver.
// Returns without changing the effect when the LCD is off.
void Raster_LineXRunFrame(RasterLineX* effect);kitaqgb/lib/raster.h
rpg.h — 亂數、文字、地圖、儲存及 RPG/ADV/SLG 功能
#pragma once
// The application supplies frame/cursor/font tiles at these indices; these constants do not load graphics.
#ifndef TEXT_TILE_FILL
#define TEXT_TILE_FILL ((u8)0)
#endif
#ifndef TEXT_TILE_FRAME_TL
#define TEXT_TILE_FRAME_TL ((u8)1)
#endif
#ifndef TEXT_TILE_FRAME_TR
#define TEXT_TILE_FRAME_TR ((u8)2)
#endif
#ifndef TEXT_TILE_FRAME_BL
#define TEXT_TILE_FRAME_BL ((u8)3)
#endif
#ifndef TEXT_TILE_FRAME_BR
#define TEXT_TILE_FRAME_BR ((u8)4)
#endif
#ifndef TEXT_TILE_FRAME_H
#define TEXT_TILE_FRAME_H ((u8)5)
#endif
#ifndef TEXT_TILE_FRAME_V
#define TEXT_TILE_FRAME_V ((u8)6)
#endif
#ifndef TEXT_TILE_CURSOR
#define TEXT_TILE_CURSOR ((u8)7)
#endif
#ifndef TEXT_TILE_PAGE_WAIT
#define TEXT_TILE_PAGE_WAIT ((u8)8)
#endif
#ifndef TEXT_DIGIT_BASE
#define TEXT_DIGIT_BASE ((u8)'0')
#endif
#define TEXT_CTRL_END ((u8)0x00)
#define TEXT_CTRL_NEWLINE ((u8)0x0A)
#define TEXT_CTRL_WAIT ((u8)0x01)
#define TEXT_CTRL_PAGE_WAIT ((u8)0x02)
#define PAD_KEY_RIGHT ((u8)0x01)
#define PAD_KEY_LEFT ((u8)0x02)
#define PAD_KEY_UP ((u8)0x04)
#define PAD_KEY_DOWN ((u8)0x08)
#define PAD_KEY_A ((u8)0x10)
#define PAD_KEY_B ((u8)0x20)
#define PAD_KEY_SELECT ((u8)0x40)
#define PAD_KEY_START ((u8)0x80)
// Default layout: four 512-byte slots, each with a six-byte header and at most 506 payload bytes.
#define SAVE_SLOT_COUNT ((u8)4)
#define SAVE_SLOT_SIZE ((u16)512)
#define SAVE_MAGIC0 ((u8)0x4B)
#define SAVE_MAGIC1 ((u8)0x51)
#define SAVE_VERSION ((u8)1)
#define SAVE_OK ((u8)1)
#define SAVE_ERR ((u8)0)
// A bank byte plus a CPU-visible address forms this data reference; it does not switch banks by itself.
typedef __packed struct {
u8 bank;
const u8* ptr;
} far_ptr_t;
typedef __packed struct {
u8 x;
u8 y;
u8 w;
u8 h;
const u8* const* items;
u8 count;
u8 cursor;
} menu_t;
typedef __packed struct {
u8 id;
u8 qty;
const u8* name;
} item_t;
// Packed nine-byte ordinary-map descriptor. Tile IDs use bank_tiles; collision bits and event bytes
// use the descriptor bank. Width/height are tile cells, with row-major data.
typedef __packed struct {
u8 width;
u8 height;
u8 bank_tiles;
const u8* tiles;
const u8* collision_bits;
const void* events;
} map_t;
// One 2x2 metatile: four tile IDs plus collision, palette metadata and event ID.
// The map drawing routine uses tile IDs only; it does not apply palette attributes.
typedef __packed struct {
u8 tile_tl;
u8 tile_tr;
u8 tile_bl;
u8 tile_br;
u8 collision;
u8 palette;
u8 event;
} metatile_t;
// Metatile dimensions count 2x2 cells. bank_tiles=0 means use the descriptor bank;
// nonzero bank_tiles supplies both ID-array and definition-table reads.
typedef __packed struct {
u8 width;
u8 height;
u8 bank_tiles;
const u8* metatile_ids;
const metatile_t* metatiles;
} metatile_map_t;
typedef __packed struct {
u8 x;
u8 y;
u8 w;
u8 h;
const u8* const* items;
u8 count;
u8 cursor;
u8 prev_keys;
u8 selected;
u8 cancelled;
} menu_state_t;
typedef __packed struct {
u8 x;
u8 y;
u8 hp;
u8 move;
u8 atk_min;
u8 atk_max;
u8 team;
u8 acted;
} unit_t;
void __wait_vblank();
u16 __readpadex(u8 prev_keys);
u16 __getbgmapbase();
void __memset(void* dst, u8 value, u16 count);
void __memcpy(void* dst, const void* src, u16 count);
void __settile(u8 x, u8 y, u8 tile);
void __settilebg(u8 x, u8 y, u8 tile);
void __settileat(u16 base, u8 x, u8 y, u8 tile);
void __vram_memcpy(u16 dst, const void* src, u16 len);
void __vram_memset(u16 dst, u8 value, u16 len);
void __far_memcpy(void* dst, u8 bank, const void* src, u16 len);
u8 __rng8();
void __rng_seed(u16 seed);
void __scroll_bg_set(u8 scx, u8 scy);
void __settile_xy(u8 x, u8 y, u8 tile);
void __settile_rect(u8 x, u8 y, u8 w, u8 h, u8 tile);
void __settile_row(u8 x, u8 y, const u8* src, u8 len);
void __settile_col(u8 x, u8 y, const u8* src, u8 len);
void __fill_tilemap(u16 base, u8 tile, u16 count);
void __settilemap_rect(u16 base, u8 x, u8 y, u8 w, u8 h, const u8* src);
void __vram_copy(u16 dst, const void* src, u16 len);
void __vram_fill(u16 dst, u8 value, u16 len);
void __vram_copy_hblank(u16 dst, const void* src, u16 len);
void __vram_copy_dma(u16 dst, const void* src, u16 len);
u8 __farpeek8(u8 bank, const void* addr);
u16 __farpeek16(u8 bank, const void* addr);
void __farmemcpy(void* dst, u8 bank, const void* src, u16 len);
// The current GB backend evaluates/discards these arguments but emits no indirect call.
void __farcall_ptr(u8 bank, const void* func);
#define far_read8(p) __farpeek8((p).bank, (p).ptr)
#define far_read16(p) __farpeek16((p).bank, (p).ptr)
#define far_read_block(dst, p, len) __farmemcpy((dst), (p).bank, (p).ptr, (len))
void __memcpy_small(void* dst, const void* src, u8 len);
void __memset_small(void* dst, u8 value, u8 len);
void __copy16(void* dst, const void* src);
void __copy32(void* dst, const void* src);
u16 __tile_addr(u16 base, u8 x, u8 y);
u16 __map_index(u8 x, u8 y, u8 width);
u8 __xy_in_rect(u8 x, u8 y, u8 rx, u8 ry, u8 rw, u8 rh);
u8 __manhattan(u8 x1, u8 y1, u8 x2, u8 y2);
u8 __bit_test(const u8* p, u16 bit_index);
void __bit_set(u8* p, u16 bit_index);
void __bit_clear(u8* p, u16 bit_index);
void __bit_toggle(u8* p, u16 bit_index);
// Compiler intrinsic, separate from the RAM rle_decode helpers below; it is not a bounded-stream API.
u16 __rle_decode_vram(u16 dst, u8 bank, const void* src);
// Advance the compiler-provided pseudorandom generator and return one byte.
u8 rng8();
// Consume two generator bytes in high-byte/low-byte order to form a 16-bit value.
u16 rng16();
// Reduce a random byte modulo max; zero returns zero without consuming randomness.
// Modulo reduction is biased unless max divides the generator range.
u8 rand_range(u8 max);
// Select an index from cumulative byte weights using a 16-bit random draw.
// A zero total, including an empty list, returns zero; callers must distinguish
// that case from a valid index. Modulo reduction can introduce a small bias.
u8 weighted_choice(const u8* weights, u8 count);
// Replace the generator seed so subsequent calls can reproduce a sequence.
void rng_seed(u16 seed);
// Alias the byte generator; this consumes one generator step.
u8 rng_next8();
// Alias the two-step 16-bit generator.
u16 rng_next16();
// Alias rand_range and return a value in [0,max), or zero when max is zero.
u8 rng_range(u8 max);
// Return false for zero and true for values at least 100. Intermediate values
// use the modulo-based range generator, so percentages are approximate.
u8 rng_chance(u8 percent);
// Set the tile-space window, reset its cursor and redraw it immediately.
// Opening does not reset the existing character speed or load font tiles.
void text_open(u8 x, u8 y, u8 w, u8 h);
// Erase the open window with the fill tile and disable windowed character output.
void text_close();
// Decode an END-terminated stream of tile bytes and newline/wait/page controls.
// WAIT consumes a following frame-count byte. The source must remain readable
// through blocking waits; the routine does not validate stream length.
void text_print(const u8* str);
// Decode the same text controls while fetching each byte from the specified
// ROM bank. The pointer advances within that bank; it does not roll into the next bank.
void text_print_far(u8 bank, const u8* str);
// Redraw choices and block for edge-triggered navigation: UP/DOWN wrap, A
// accepts, and B returns 0xFF. Zero choices also returns 0xFF. Choice strings
// use raw tile bytes, and the caller must fit them inside the available rows.
u8 text_choice(const u8* const* choices, u8 count);
// Set VBlank waits per windowed character; zero prints without character delays.
void text_set_speed(u8 speed);
// Open and redraw a window using the same tile-space arguments as text_open.
void text_window(u8 x, u8 y, u8 w, u8 h);
// Fill the supplied tile rectangle without changing the active text window or cursor.
void text_clear_rect(u8 x, u8 y, u8 w, u8 h);
// Draw a zero-terminated tile string at absolute tile coordinates, without
// window clipping, control codes or the windowed printing delay.
void text_print_xy(u8 x, u8 y, const u8* str);
// Print an unsigned byte in decimal using only the required number of cells.
void text_print_u8(u8 x, u8 y, u8 value);
// Print an unsigned word in decimal using only the required number of cells.
void text_print_u16(u8 x, u8 y, u16 value);
// Print a minus tile for negative values, followed by the unsigned magnitude.
// Positive values use the unsigned decimal path; no plus sign is emitted.
void text_print_s16(u8 x, u8 y, s16 value);
// Replace the active script and clear wait, choice and saved-return state.
void script_run(u8 bank, const u8* script);
// Execute commands until an output/choice yields (0), a wait yields (1), or
// execution ends (2). Control/flag commands continue within the same call, so
// a script loop without a yielding command can block the game loop indefinitely.
u8 script_step();
// Set the number of subsequent script_step calls to spend waiting. Frame-based
// timing requires the application to call script_step once per frame.
void script_wait_frames(u8 n);
// Run a blocking menu loop with wraparound up/down selection, A to accept
// and B to cancel. Return 0xFF for an empty menu or cancellation. Item strings
// and menu dimensions must fit the visible tile area.
u8 menu_run(const menu_t* menu);
// Open a two-choice dialog and return the text-choice result (YES first, NO second).
u8 menu_yesno();
// Run a blocking item menu, drawing names and two-digit quantities. Return
// the selected index or 0xFF on empty input/B; this does not consume an item.
u8 menu_inventory(const item_t* items, u8 count);
// Initialize a nonblocking menu state that borrows the item pointer table.
// Selection starts unset (0xFF), and the cancellation flag starts clear.
void menu_init_state(menu_state_t* state, u8 x, u8 y, u8 w, u8 h, const u8* const* items, u8 count);
// Draw the current menu and cursor without waiting or sampling input. The
// caller schedules suitable display timing and keeps item text within bounds.
void menu_draw(menu_state_t* state);
// Sample new button presses and update cursor/selection state without drawing.
// Selected and cancelled results remain latched; a B press in the same update
// as A clears selection and leaves cancellation set.
void menu_update(menu_state_t* state);
// Read the latched selection without clearing it; null state returns 0xFF.
u8 menu_get_selected(menu_state_t* state);
// Read the latched cancellation flag; null state returns false.
u8 menu_was_cancelled(menu_state_t* state);
// Load the nine-byte ordinary-map descriptor and draw up to 20 by 18 tiles
// from its top-left corner. Drawing does not upload tile graphics or clear
// background cells beyond smaller map dimensions.
void map_load(u8 bank, const map_t* map);
// Use metatile collision when that mode is active; otherwise read one packed
// collision bit. Missing maps/out-of-range cells block movement, but a valid
// ordinary map without a collision array is entirely passable.
u8 map_is_blocked(u8 x, u8 y);
// Report whether an event exists at the cell. Ordinary maps expose a Boolean
// byte-presence test; metatile maps reduce their event ID to a Boolean here.
u8 map_trigger_at(u8 x, u8 y);
// Center an ordinary-map tile coordinate within a 20-by-18 viewport and clamp
// the scroll origin to its edges. This adjusts scroll registers only; it does
// not stream newly exposed map rows into VRAM.
void camera_center(u8 x, u8 y);
// Select metatile mode, copy its descriptor and draw the initial viewport
// with the camera at cell (0,0).
void map_load_metatile(u8 bank, const metatile_map_t* map);
// Draw a 10-by-9 metatile viewport as 20-by-18 individual background tiles.
// Out-of-range cells use definition zero; palette attributes are not written.
// Remember the camera and clear the dirty flag after the full redraw.
void map_draw_visible(u8 camera_tx, u8 camera_ty);
// Read a row-major metatile ID, returning ID zero for inactive or out-of-range
// lookups. Callers must provide a usable definition for metatile zero.
u8 map_get_metatile(u8 tx, u8 ty);
// Return the selected definition's palette byte. An out-of-range coordinate
// uses the metatile-zero fallback; this function does not write CGB attributes.
u8 map_get_attr(u8 tx, u8 ty);
// Treat out-of-range metatile cells as solid; otherwise inspect the definition
// collision flag. In ordinary-map mode, delegate to its packed collision bits.
u8 map_is_solid(u8 tx, u8 ty);
// Return a metatile event ID, or the ordinary-map Boolean trigger result.
// Missing/out-of-range metatile cells have no event.
u8 map_get_event(u8 tx, u8 ty);
// Mark the viewport for a full redraw when a valid metatile cell changes.
// The coordinate is validated but no per-cell dirty list is retained.
void map_mark_dirty(u8 tx, u8 ty);
// Redraw the remembered metatile viewport only when the shared dirty flag is set.
void map_flush_dirty();
// Validate slot and payload length, write payload bytes, then write the header
// and checksum. Return one after completing the writes; interruption can leave
// a partially replaced slot, so this is not transactional save storage.
u8 save_write(u8 slot, const void* data, u16 len);
// Require matching magic/version, exact requested length and a valid checksum
// before copying data into the destination. Validation failure leaves the
// destination unchanged. An invalid slot returns before touching RAM control;
// validation failures after enabling RAM disable it before returning zero.
u8 save_read(u8 slot, void* data, u16 len);
// Validate a slot's header, payload bounds and checksum without copying the
// payload out. A nonzero result means the stored record passes these checks.
u8 save_exists(u8 slot);
// Initialize the expected RAM access state and leave cartridge RAM disabled.
// Existing slot contents are preserved.
void save_init();
// Alias the checked save_read operation.
u8 save_load(u8 slot, void* data, u16 len);
// Alias save_exists, including its header and checksum validation.
u8 save_check(u8 slot);
// Zero the complete selected slot, including header and payload; invalid slot
// IDs are ignored. Cartridge RAM is disabled when clearing finishes.
void save_clear(u8 slot);
// Build movement costs, then convert reachable cells to one and unreachable
// 0xFF cells to zero. The caller provides one output byte per current-map cell
// and a valid unit origin; path-search workspace limits also apply.
u8 unit_move_range(unit_t* u, u8* out_mask);
// Mark cells whose Manhattan distance falls within the inclusive attack range.
// This geometric mask does not test obstacles, line of sight or other units.
u8 unit_attack_range(unit_t* u, u8* out_mask);
// A unit can act only while HP is nonzero and its acted flag is clear.
// The unit pointer must refer to a valid record.
u8 unit_can_act(const unit_t* u);
// Find a shortest cardinal path with BFS and write direction codes 0=up,
// 1=right, 2=down, 3=left. Return its byte length, or zero for failure or an
// already-reached goal. The caller supplies max_len output bytes and respects
// the shared workspace/distance limits; excessive paths are not truncated.
u8 path_find_bfs(u8 sx, u8 sy, u8 gx, u8 gy, u8* out_path, u8 max_len);
// Flood cardinal neighbors at unit cost, stopping expansion at the movement
// limit and rejecting blocked destinations. Initialize output to 0xFF only
// after validating the map and origin; invalid input leaves output unchanged.
void range_fill_move(u8 sx, u8 sy, u8 move, u8* out_costmap);
// Read a bit from the flag array. Callers must keep id below 2048.
u8 flag_get(u16 id);
// Set a flag bit without disturbing adjacent flags; id must be below 2048.
void flag_set(u16 id);
// Clear a flag bit; id must be below 2048.
void flag_clear(u16 id);
// Read a quest-state byte; quest_id must be below 64.
u8 quest_state(u8 quest_id);
// Replace a quest-state byte without validating its game-specific meaning.
// The caller must keep quest_id below 64.
void quest_set_state(u8 quest_id, u8 state);
// Expand count/value byte pairs until a zero count terminates the stream.
// The caller must provide a valid terminator and sufficient destination storage;
// there are no source or destination bounds parameters. Return the 16-bit byte count.
u16 rle_decode(void* dst, const void* src);
// Decode the same count/value format using bank-qualified reads for every source
// byte. Keep the encoded stream within the supplied bank/address mapping and
// provide enough destination space; a zero count ends the stream.
u16 rle_decode_far(void* dst, u8 bank, const void* src);
// Return the active map width in its own cell units, or zero when no map is loaded.
u8 map_current_width();
// Return the active map height in its own cell units, or zero when no map is loaded.
u8 map_current_height();kitaqgb/lib/rpg.h
scene.h — 場景註冊、切換與更新
#pragma once
typedef void (*SceneFunc)();
// Callbacks may be null. Keep the table and non-null targets readable for its lifetime.
// These plain function pointers do not carry a ROM bank number.
typedef __packed struct {
SceneFunc enter;
SceneFunc update;
SceneFunc draw;
SceneFunc exit;
} SceneDef;
// Attach the caller-owned scene table and clear current-scene state without invoking callbacks.
void scene_init(const SceneDef* scenes, u8 count);
// Replace the table by resetting scene state; this does not call the old scene's exit handler.
void scene_set_table(const SceneDef* scenes, u8 count);
// Ignore invalid IDs; otherwise exit the current scene and enter the requested one.
// Selecting the current ID still performs exit/enter. Callbacks run synchronously.
void scene_change(u8 scene_id);
// Clear the change flag before calling the active scene's update handler, so a
// transition made during that handler is visible afterward.
void scene_update();
// Call the active scene's draw handler if one exists; no current scene is a no-op.
void scene_draw();
// Return the stored scene ID; zero is also returned before the first transition.
u8 scene_get_current();
// Read the transition flag, which is cleared at the start of an active scene update.
u8 scene_was_changed();kitaqgb/lib/scene.h
scroll.h — 背景、視窗與分割捲動
#pragma once
// Flags select operations in a raster split; raw window X includes the hardware +7 offset.
#define KQ_SCROLL_SPLIT_USE_BG 0x01
#define KQ_SCROLL_SPLIT_USE_WIN 0x02
#define KQ_SCROLL_SPLIT_WIN_SHOW 0x04
#define KQ_SCROLL_SPLIT_WIN_HIDE 0x08
#define KQ_SCROLL_SPLIT_BG_COLOR0 0x10
void __scroll_bg_set(u8 scx, u8 scy);
void __scroll_bg_x_set(u8 scx);
void __scroll_bg_y_set(u8 scy);
u8 __scroll_bg_x_get();
u8 __scroll_bg_y_get();
void __scroll_win_set(u8 wx, u8 wy);
void __scroll_win_x_set(u8 wx);
void __scroll_win_y_set(u8 wy);
u8 __scroll_win_x_get();
u8 __scroll_win_y_get();
void __scroll_bg_set_buffered(u8 scx, u8 scy);
void __scroll_bg_x_set_buffered(u8 scx);
void __scroll_bg_y_set_buffered(u8 scy);
void __scroll_win_set_buffered(u8 wx, u8 wy);
void __scroll_win_x_set_buffered(u8 wx);
void __scroll_win_y_set_buffered(u8 wy);
void __scroll_flush();
void __scroll_split_reset();
void __scroll_split_push(u8 ly, u8 scx, u8 scy);
void __scroll_split_push_ex(u8 ly, u8 scx, u8 scy, u8 wx, u8 wy, u8 flags);
void __scroll_split_commit();
void __scroll_win_show();
void __scroll_win_hide();
void __scroll_bg_add(s8 dx, s8 dy);
void __scroll_win_add(s8 dx, s8 dy);
// Reset background scroll to zero and place the window at screen origin
// using hardware WX=7 and WY=0.
void Scroll_Init();
// Write both hardware background-scroll bytes immediately.
void Scroll_SetBg(u8 scx, u8 scy);
// Write horizontal background scroll while leaving vertical scroll unchanged.
void Scroll_SetBgX(u8 scx);
// Write vertical background scroll while leaving horizontal scroll unchanged.
void Scroll_SetBgY(u8 scy);
// Read the tracked current background X; this is not a direct SCX register read.
u8 Scroll_GetBgX();
// Read the tracked current background Y; pending and raster-only values are excluded.
u8 Scroll_GetBgY();
// Write raw hardware WX/WY values; callers add seven to a screen-space window X.
void Scroll_SetWindow(u8 wx, u8 wy);
// Write raw hardware WX without converting a screen-space X coordinate.
void Scroll_SetWindowX(u8 wx);
// Write the window Y coordinate through the intrinsic.
void Scroll_SetWindowY(u8 wy);
// Read tracked current WX, including its seven-pixel offset; not a live hardware read.
u8 Scroll_GetWindowX();
// Read tracked current WY; pending and raster-only values are excluded.
u8 Scroll_GetWindowY();
// Stage background-scroll values in the intrinsic buffer for a later flush.
void Scroll_SetBgBuffered(u8 scx, u8 scy);
// Stage raw window-coordinate values for a later flush.
void Scroll_SetWindowBuffered(u8 wx, u8 wy);
// Apply the buffered scroll/window state through the compiler runtime.
void Scroll_Flush();
// Apply signed deltas to the byte-sized background-scroll coordinates.
void Scroll_BgAdd(s8 dx, s8 dy);
// Apply signed deltas to the byte-sized hardware window coordinates.
void Scroll_WindowAdd(s8 dx, s8 dy);
// Request window visibility through the compiler intrinsic.
void Scroll_WindowShow();
// Request that the window be hidden through the compiler intrinsic.
void Scroll_WindowHide();
// Clear the pending split table before building a new raster configuration.
void Scroll_SplitReset();
// Append a background-scroll split directly. Use Raster_Push when caller-side
// scanline ordering and capacity validation are desired.
void Scroll_SplitPush(u8 ly, u8 scx, u8 scy);
// Append an extended split with raw background/window fields and operation flags.
void Scroll_SplitPushEx(u8 ly, u8 scx, u8 scy, u8 wx, u8 wy, u8 flags);
// Reuse the two background-scroll fields to carry the low/high RGB15 bytes
// for a split whose operation flag selects background color zero.
void Scroll_SplitPushBgColor0(u8 ly, u16 rgb15);
// Publish the pending split configuration through the compiler runtime.
void Scroll_SplitCommit();kitaqgb/lib/scroll.h
slg.h — 棋盤、行動清單與復原
#pragma once
// A row-major byte board. Storage is borrowed; cell values and coordinates have game-defined meaning.
typedef __packed struct {
u8 width;
u8 height;
u8* cells;
} SLGBoard;
typedef __packed struct {
u8 x;
u8 y;
u8 value;
} SLGMove;
typedef __packed struct {
SLGMove* items;
u8 count;
u8 capacity;
} SLGMoveList;
// Undo records are retained cell values only; popping one does not apply it to a board.
typedef __packed struct {
SLGMove* items;
u8 count;
u8 capacity;
} SLGUndoStack;
// Attach width * height bytes of caller-owned cell storage without clearing it.
void slg_board_init(SLGBoard* board, u8 width, u8 height, u8* cells);
// Fill every cell with value; a null board is ignored. A valid board must own
// enough accessible cell storage for its declared dimensions.
void slg_board_clear(SLGBoard* board, u8 value);
// Return zero for a null board or out-of-range coordinate; otherwise read the
// cell. Zero therefore cannot distinguish an invalid lookup from an empty cell.
u8 slg_board_get(const SLGBoard* board, u8 x, u8 y);
// Write a cell only when the board and coordinate are valid.
void slg_board_set(SLGBoard* board, u8 x, u8 y, u8 value);
// Attach caller-owned move storage and reset the list length.
void slg_move_list_init(SLGMoveList* list, SLGMove* items, u8 capacity);
// Forget the moves without erasing their storage; a null list is ignored.
void slg_move_list_clear(SLGMoveList* list);
// Append coordinates and a value to the bounded move list. Return zero on a
// null/full list without replacing any existing move.
u8 slg_move_list_push(SLGMoveList* list, u8 x, u8 y, u8 value);
// Attach caller-owned undo records and initialize an empty stack.
void slg_undo_init(SLGUndoStack* stack, SLGMove* items, u8 capacity);
// Record a cell's previous value for later undo. Return zero if the stack is
// null or full; this function does not change the board itself.
u8 slg_undo_push(SLGUndoStack* stack, u8 x, u8 y, u8 old_value);
// Remove the newest undo record and optionally copy it out. A null output
// still discards the record; a null or empty stack returns zero.
u8 slg_undo_pop(SLGUndoStack* stack, SLGMove* out_move);kitaqgb/lib/slg.h
sprite.h — OBJ 配置、定位、組合精靈與動畫
#pragma once
// Keep the default 40 for the standard DMA path. Hardware always transfers 160 bytes,
// even if this array is shortened; a custom layout must provide valid bytes for that full transfer.
#ifndef SPRITE_MAX
#define SPRITE_MAX 40
#endif
#define SPRITE_FLAG_PAL1 ((u8)0x10)
#define SPRITE_FLAG_XFLIP ((u8)0x20)
#define SPRITE_FLAG_YFLIP ((u8)0x40)
#define SPRITE_FLAG_PRIORITY ((u8)0x80)
// Packed hardware order is Y, X, tile, flags; screen coordinates need the GB OAM offsets.
typedef __packed struct {
u8 y;
u8 x;
u8 tile;
u8 flags;
} SpriteOamEntry;
extern __wram __aligned(256) SpriteOamEntry kq_sprite_oam[SPRITE_MAX];
extern u8 kq_sprite_active[SPRITE_MAX];
extern u8 kq_sprite_used;
extern u8 kq_sprite_height;
// Signed pixel displacements from a common origin; final byte coordinates wrap rather than clip.
typedef __packed struct {
s8 dx;
s8 dy;
u8 tile;
u8 flags;
} MetaSpritePart;
// Initialize frame/ticks within their configured ranges. This animation selects consecutive tile IDs;
// it does not change sprite size or automatically step by two tiles in 8x16 mode.
typedef __packed struct {
u8 first_tile;
u8 frame_count;
u8 frame;
u8 ticks;
u8 ticks_per_frame;
} SpriteAnim;
void __wait_vblank();
void __oam_dma(u16 src_ptr);
// Clear allocation and shadow OAM state and reset the DMA-stub installation flag.
// The default height is eight pixels; the hardware display mode is configured elsewhere.
void sprite_init();
// Claim the first free slot, hide it, and return its ID; return 0xFF when full.
// Previously stored tile/flag bytes are retained until the caller replaces them.
u8 sprite_alloc();
// Release an allocated valid slot and hide it. Repeated frees do not decrement the count.
void sprite_free(u8 id);
// Convert screen coordinates to OAM coordinates by adding X=8 and Y=16.
// The byte additions wrap; this updates shadow storage even for an unallocated slot.
void sprite_set_pos(u8 id, u8 x, u8 y);
// Set a valid shadow slot's tile byte; allocation and hardware transfer are separate.
void sprite_set_tile(u8 id, u8 tile);
// Replace a valid shadow slot's complete hardware attribute byte.
void sprite_set_flags(u8 id, u8 flags);
// Move a valid shadow slot off screen without freeing it.
void sprite_hide(u8 id);
// Install the HRAM stub lazily and execute OAM DMA with interrupts disabled.
// This routine does not wait for VBlank and always enables interrupts afterward;
// it does not restore the caller's previous interrupt-enable state.
void sprite_flush_oam_now();
// Wait for VBlank, then transfer shadow OAM using the immediate DMA routine.
void sprite_flush_oam();
// Return the number of active slots, including slots activated by metasprite_draw.
// Hidden allocated slots remain active until sprite_free releases them.
u8 sprite_count_used();
// Report whether the software overlap estimate exceeds ten sprites on a scanline.
u8 sprite_warn_scanline_overflow();
// Estimate the largest overlap of active, non-hidden shadow sprites across
// visible scanlines using the configured sprite height. This is a software
// overlap count, not a rendered-pixel or hardware-priority simulation.
u8 sprite_max_scanline_count();
// Place consecutive parts, counting each newly activated slot once. Existing
// active slots are overwritten without increasing the allocation count. Return
// the number written; an invalid first slot or zero count writes nothing.
u8 metasprite_draw(u8 first_id, u8 x, u8 y, const MetaSpritePart* parts, u8 count);
// Advance animation ticks/frame with wrapping frame selection and return the
// resulting tile. Zero ticks-per-frame freezes animation; null state returns zero.
u8 anim_update(SpriteAnim* anim);kitaqgb/lib/sprite.h
sprite_order.h — 依優先順序與輪替選取精靈
#pragma once
// Copyright (c) 2026 DAISUKE OBA. MIT License.
// Hardware-compatible layout without requiring the sprite allocator or its
// global storage. Cast a sprite.h shadow buffer to this type when combining
// the libraries; both layouts contain exactly Y, X, tile and flags bytes.
typedef __packed struct {
u8 y;
u8 x;
u8 tile;
u8 flags;
} SpriteOrderOamEntry;
#define SPRITE_ORDER_LEVELS 4
#define SPRITE_ORDER_OAM_COUNT 40
// One submitted, visible sprite. Attributes retain their hardware meaning;
// priority 0..3 controls OAM selection order, not the BG-over-OBJ flag.
typedef __packed struct {
SpriteOrderOamEntry oam;
u8 priority;
} SpriteOrderItem;
// Caller-owned foreground state. Capacity is 1..255 items; count includes only
// accepted submissions. Rebuild the same logical submission list each frame so
// phase rotation distributes selection among equal-priority sprites.
typedef struct {
SpriteOrderItem* items;
u8 capacity;
u8 count;
u8 height;
u8 phase;
} SpriteOrder;
// Bind writable item storage and select the hardware sprite height (8 or 16).
// Return 1 on success. Invalid storage, zero capacity or another height returns
// 0 and leaves a non-null state disabled. A null state returns 0 without writes.
u8 sprite_order_init(SpriteOrder* order, SpriteOrderItem* items, u8 capacity, u8 height);
// Discard this frame's submissions while preserving storage, height and phase.
// A null state is ignored. Call once before submitting the next frame's sprites.
void sprite_order_begin(SpriteOrder* order);
// Submit one sprite at signed, top-left SCREEN pixel coordinates. Preserve the
// tile and attribute bytes; use priority 0 (first) through 3 (last). Fully
// off-screen sprites, invalid priorities, disabled state and full storage return
// 0 without consuming a slot. Partly visible sprites are accepted. Return 1 on
// acceptance. Hardware 8x16 mode still ignores the tile index's low bit.
u8 sprite_order_push(SpriteOrder* order, s16 x, s16 y, u8 tile, u8 flags, u8 priority);
// Write a complete 160-byte shadow OAM: ascending priority, then cyclic order
// within each priority. Clamp limit to 40, return the number emitted and zero
// all unused entries (including Y) so they cannot consume scanline slots.
// Advance phase once for a nonempty valid queue, even when limit is zero.
// Empty queues reset phase to zero. Null/disabled/corrupt state or null output
// returns 0 without modifying output or phase.
// Output must provide 40 entries and must not overlap item/state storage.
// This only writes RAM. Build in foreground, then transfer during VBlank.
// DMG overlap priority also depends on X: this cannot override that hardware
// rule. OAM order chooses the first ten sprites per scanline on both DMG/CGB.
// It neither updates sprite_alloc's bookkeeping nor performs OAM DMA.
u8 sprite_order_build(SpriteOrder* order, SpriteOrderOamEntry* output, u8 limit);kitaqgb/lib/sprite_order.h
system.h — 啟動、影格計數、等待與中斷
#pragma once
// This callback runs in the caller of system_wait_vblank, not as an installed ISR.
// Its plain pointer has no ROM bank component; keep the target callable in that mapping.
typedef void (*SystemCallback)();
extern u16 kq_system_frame;
void __wait_vblank();
// Reset the software frame counter and remove any registered callback.
void system_init();
// Wait for VBlank, count this wrapper call, then invoke the callback synchronously.
// The counter wraps at 16 bits and is not an independent hardware frame clock.
void system_wait_vblank();
// Replace the callback used by system_wait_vblank; null disables the callback.
void system_set_vblank_callback(SystemCallback callback);
// Read the software count of completed system_wait_vblank calls.
u16 system_get_frame();
// Return the low byte of the software frame counter for wrapping 8-bit timing.
u8 system_get_frame8();
// Enable CPU interrupts and return using the inline-assembly function body.
void system_enable_interrupts();
// Disable CPU interrupts and return; callers must explicitly re-enable them later.
void system_disable_interrupts();
#define gb_init system_init
#define gb_wait_vblank system_wait_vblank
#define gb_set_vblank_callback system_set_vblank_callback
#define gb_frame_count system_get_frame
#define gb_enable_interrupts system_enable_interrupts
#define gb_disable_interrupts system_disable_interruptskitaqgb/lib/system.h
vram.h — VRAM 佇列更新與傳輸
#pragma once
// Keep this capacity in 1..255 in all units; counts and capacity/free return values are bytes.
#ifndef VRAM_QUEUE_MAX
#define VRAM_QUEUE_MAX 32
#endif
#define VRAM_CMD_BG_TILE ((u8)1)
#define VRAM_CMD_BG_RECT ((u8)2)
#define VRAM_CMD_BG_BLOCK ((u8)3)
#define VRAM_CMD_MEMCPY ((u8)4)
#define VRAM_CMD_MEMSET ((u8)5)
// A command owns metadata only. src is a retained near pointer with no bank number or copied payload.
typedef __packed struct {
u8 kind;
u8 x;
u8 y;
u8 w;
u8 h;
u8 value;
u16 dst;
const u8* src;
u16 len;
} VramCommand;
extern VramCommand kq_vram_queue[VRAM_QUEUE_MAX];
extern u8 kq_vram_queue_used;
extern u8 kq_vram_queue_overflowed;
void __wait_vblank();
void __settile_xy(u8 x, u8 y, u8 tile);
void __settile_rect(u8 x, u8 y, u8 w, u8 h, u8 tile);
void __settilemap_rect(u16 base, u8 x, u8 y, u8 w, u8 h, const u8* src);
void __vram_copy(u16 dst, const void* src, u16 len);
void __vram_fill(u16 dst, u8 value, u16 len);
// Start with an empty command queue and a clear overflow flag.
void vram_init();
// Discard pending commands and clear the latched overflow flag without writing VRAM.
void vram_clear_queue();
// Queue a single background tile write; return zero if no command slot is available.
u8 vram_queue_bg_tile(u8 x, u8 y, u8 tile);
// Provide the short alias for a queued background tile write.
u8 vram_queue_tile(u8 x, u8 y, u8 tile);
// Queue a rectangle filled with one tile value; coordinates and dimensions are in tiles.
u8 vram_queue_bg_rect(u8 x, u8 y, u8 w, u8 h, u8 tile);
// Queue a tile-map rectangle while retaining src rather than copying its bytes.
// Keep the source data and its ROM bank accessible until the queue is flushed.
u8 vram_queue_bg_block(u16 base, u8 x, u8 y, u8 w, u8 h, const u8* src);
// Queue a byte transfer and retain the source pointer. The source must remain
// valid and visible until flush; len is measured in bytes, not tiles.
u8 vram_queue_memcpy(u16 dst, const void* src, u16 len);
// Alias the queued byte-copy operation; this does not convert a tile count to bytes.
u8 vram_queue_tiles(u16 dst, const void* src, u16 len);
// Queue a byte fill and return zero if the command queue is full.
u8 vram_queue_memset(u16 dst, u8 value, u16 len);
// Execute pending commands in insertion order without waiting for VBlank here.
// The caller must arrange suitable VRAM access timing and a sufficient transfer budget.
// Only the used count is cleared; overflow stays latched until an explicit reset.
void vram_flush_now();
// Wait for VBlank before executing the queue. Waiting once does not itself limit
// the queued workload to the available VBlank duration.
void vram_flush();
// Return the number of queued commands, not the number of transfer bytes.
u8 vram_get_queue_used();
// Return the total number of command slots, independent of queue usage.
// This is command-buffer capacity, not free space in hardware VRAM.
u8 vram_get_queue_capacity();
// Return the remaining command-slot capacity.
u8 vram_get_queue_free();
// Read the overflow latch without clearing it.
u8 vram_get_overflowed();kitaqgb/lib/vram.h
wire3d.h — DMG 線框
// Compatibility names for the shared wire3d_dmg renderer.
// Select the same profile in every translation unit; compile one renderer entry.
#pragma once
#ifndef WIRE3D_DMG_HEIGHT
#define WIRE3D_DMG_HEIGHT 96
#endif
#if WIRE3D_DMG_HEIGHT != 96
#error Incompatible wire3d_dmg profile
#endif
#include "wire3d_dmg.h"
#define W3D_BG_QUEUE_LIMIT WIRE3D_DMG_BG_QUEUE_LIMIT
#define W3D_CENTER_X WIRE3D_DMG_CENTER_X
#define W3D_CENTER_Y WIRE3D_DMG_CENTER_Y
#define W3D_FAR_Z WIRE3D_DMG_FAR_Z
#define W3D_HUD_TILE_BASE WIRE3D_DMG_HUD_TILE_BASE
#define W3D_HUD_TILE_BLANK WIRE3D_DMG_HUD_TILE_BLANK
#define W3D_HUD_TILE_COUNT WIRE3D_DMG_HUD_TILE_COUNT
#define W3D_NEAR_Z WIRE3D_DMG_NEAR_Z
#define W3D_PROJECT_LIMIT WIRE3D_DMG_PROJECT_LIMIT
#define W3D_ROW_BYTES WIRE3D_DMG_ROW_BYTES
#define W3D_TILE_H WIRE3D_DMG_TILE_H
#define W3D_TILE_W WIRE3D_DMG_TILE_W
#define W3D_TRANSFORM_LIMIT WIRE3D_DMG_TRANSFORM_LIMIT
#define WIRE3D_EDGE_MASK_BINS_16 WIRE3D_DMG_EDGE_MASK_BINS_16
#define WIRE3D_FACE_NONE WIRE3D_DMG_FACE_NONE
#define WIRE3D_MODEL_EDGE_LIMIT WIRE3D_DMG_MODEL_EDGE_LIMIT
#define WIRE3D_MODEL_FACE_LIMIT WIRE3D_DMG_MODEL_FACE_LIMIT
#define WIRE3D_MODEL_HIDDEN_LINES WIRE3D_DMG_MODEL_HIDDEN_LINES
#define WIRE3D_MODEL_VERTEX_LIMIT WIRE3D_DMG_MODEL_VERTEX_LIMIT
#define WIRE3D_SCENE_OBJECT_LIMIT WIRE3D_DMG_SCENE_OBJECT_LIMIT
#define WIRE3D_SCREEN_H WIRE3D_DMG_SCREEN_H
#define WIRE3D_SCREEN_W WIRE3D_DMG_SCREEN_W
#define Wire3D_BeginFrame Wire3DDMG_BeginFrame
#define Wire3D_DrawLine2D Wire3DDMG_DrawLine2D
#define Wire3D_DrawLine3D Wire3DDMG_DrawLine3D
#define Wire3D_DrawModel Wire3DDMG_DrawModel
#define Wire3D_DrawModelScaled Wire3DDMG_DrawModelScaled
#define Wire3D_DrawScene Wire3DDMG_DrawScene
#define Wire3D_Edge Wire3DDMG_Edge
#define Wire3D_EdgeFaces Wire3DDMG_EdgeFaces
#define Wire3D_EndFrame Wire3DDMG_EndFrame
#define Wire3D_EraseModelFaces Wire3DDMG_EraseModelFaces
#define Wire3D_EraseSpan2D Wire3DDMG_EraseSpan2D
#define Wire3D_EraseTriangle2D Wire3DDMG_EraseTriangle2D
#define Wire3D_Face Wire3DDMG_Face
#define Wire3D_Init Wire3DDMG_Init
#define Wire3D_Model Wire3DDMG_Model
#define Wire3D_Object Wire3DDMG_Object
#define Wire3D_ProjectPoint Wire3DDMG_ProjectPoint
#define Wire3D_PutBgTile Wire3DDMG_PutBgTile
#define Wire3D_SelectEdgeMask Wire3DDMG_SelectEdgeMask
#define Wire3D_SetCamera Wire3DDMG_SetCamera
#define Wire3D_SetPalette Wire3DDMG_SetPalette
#define Wire3D_Vec3 Wire3DDMG_Vec3
#define w3d_abs_i16 w3ddmg_abs_i16
#define w3d_bg_map_9800 w3ddmg_bg_map_9800
#define w3d_bgq_addr_hi w3ddmg_bgq_addr_hi
#define w3d_bgq_addr_lo w3ddmg_bgq_addr_lo
#define w3d_bgq_count w3ddmg_bgq_count
#define w3d_bgq_tile w3ddmg_bgq_tile
#define w3d_bgq_value w3ddmg_bgq_value
#define w3d_bgq_x w3ddmg_bgq_x
#define w3d_bgq_y w3ddmg_bgq_y
#define w3d_bit_mask w3ddmg_bit_mask
#define w3d_build_edge_flags w3ddmg_build_edge_flags
#define w3d_build_face_visibility w3ddmg_build_face_visibility
#define w3d_cam_pitch w3ddmg_cam_pitch
#define w3d_cam_roll w3ddmg_cam_roll
#define w3d_cam_x w3ddmg_cam_x
#define w3d_cam_y w3ddmg_cam_y
#define w3d_cam_yaw w3ddmg_cam_yaw
#define w3d_cam_z w3ddmg_cam_z
#define w3d_clamp_i16 w3ddmg_clamp_i16
#define w3d_clamp_screen w3ddmg_clamp_screen
#define w3d_clear_occlusion_mask w3ddmg_clear_occlusion_mask
#define w3d_clear_occlusion_mask_asm w3ddmg_clear_occlusion_mask_asm
#define w3d_clear_stage_asm w3ddmg_clear_stage_asm
#define w3d_clear_triangle w3ddmg_clear_triangle
#define w3d_clear_vram_asm w3ddmg_clear_vram_asm
#define w3d_cos_q6 w3ddmg_cos_q6
#define w3d_edge_area w3ddmg_edge_area
#define w3d_edge_flags w3ddmg_edge_flags
#define w3d_face_visible w3ddmg_face_visible
#define w3d_fill_bg_map_asm w3ddmg_fill_bg_map_asm
#define w3d_flush_bg_queue w3ddmg_flush_bg_queue
#define w3d_hud_tiles w3ddmg_hud_tiles
#define w3d_i16 w3ddmg_i16
#define w3d_i8 w3ddmg_i8
#define w3d_inv_depth w3ddmg_inv_depth
#define w3d_is_edge_visible w3ddmg_is_edge_visible
#define w3d_line_dx w3ddmg_line_dx
#define w3d_line_dy w3ddmg_line_dy
#define w3d_line_err w3ddmg_line_err
#define w3d_line_stage_asm w3ddmg_line_stage_asm
#define w3d_line_stage_masked_c w3ddmg_line_stage_masked_c
#define w3d_line_sx w3ddmg_line_sx
#define w3d_line_sy w3ddmg_line_sy
#define w3d_line_x w3ddmg_line_x
#define w3d_line_x0 w3ddmg_line_x0
#define w3d_line_x1 w3ddmg_line_x1
#define w3d_line_y w3ddmg_line_y
#define w3d_line_y0 w3ddmg_line_y0
#define w3d_line_y1 w3ddmg_line_y1
#define w3d_load_hud_tiles w3ddmg_load_hud_tiles
#define w3d_mark_model_occluder w3ddmg_mark_model_occluder
#define w3d_mark_triangle w3ddmg_mark_triangle
#define w3d_mask_get w3ddmg_mask_get
#define w3d_mask_offset w3ddmg_mask_offset
#define w3d_mask_set w3ddmg_mask_set
#define w3d_mask_set_span w3ddmg_mask_set_span
#define w3d_neg_angle w3ddmg_neg_angle
#define w3d_occlusion_active w3ddmg_occlusion_active
#define w3d_occlusion_mask w3ddmg_occlusion_mask
#define w3d_pair_block w3ddmg_pair_block
#define w3d_pair_wait_0 w3ddmg_pair_wait_0
#define w3d_pair_wait_1 w3ddmg_pair_wait_1
#define w3d_pair_wait_10 w3ddmg_pair_wait_10
#define w3d_pair_wait_11 w3ddmg_pair_wait_11
#define w3d_pair_wait_12 w3ddmg_pair_wait_12
#define w3d_pair_wait_13 w3ddmg_pair_wait_13
#define w3d_pair_wait_14 w3ddmg_pair_wait_14
#define w3d_pair_wait_15 w3ddmg_pair_wait_15
#define w3d_pair_wait_2 w3ddmg_pair_wait_2
#define w3d_pair_wait_3 w3ddmg_pair_wait_3
#define w3d_pair_wait_4 w3ddmg_pair_wait_4
#define w3d_pair_wait_5 w3ddmg_pair_wait_5
#define w3d_pair_wait_6 w3ddmg_pair_wait_6
#define w3d_pair_wait_7 w3ddmg_pair_wait_7
#define w3d_pair_wait_8 w3ddmg_pair_wait_8
#define w3d_pair_wait_9 w3ddmg_pair_wait_9
#define w3d_plot_stage_asm w3ddmg_plot_stage_asm
#define w3d_plot_tx w3ddmg_plot_tx
#define w3d_plot_x w3ddmg_plot_x
#define w3d_plot_y w3ddmg_plot_y
#define w3d_project_camera_space w3ddmg_project_camera_space
#define w3d_project_world w3ddmg_project_world
#define w3d_put_bg_tile_safe_asm w3ddmg_put_bg_tile_safe_asm
#define w3d_reg_bgp w3ddmg_reg_bgp
#define w3d_reg_lcdc w3ddmg_reg_lcdc
#define w3d_reg_ly w3ddmg_reg_ly
#define w3d_reg_scx w3ddmg_reg_scx
#define w3d_reg_scy w3ddmg_reg_scy
#define w3d_rotate_x w3ddmg_rotate_x
#define w3d_rotate_y w3ddmg_rotate_y
#define w3d_rotate_z w3ddmg_rotate_z
#define w3d_scene_depth w3ddmg_scene_depth
#define w3d_scene_object_depth w3ddmg_scene_object_depth
#define w3d_scene_order w3ddmg_scene_order
#define w3d_screen_delta w3ddmg_screen_delta
#define w3d_screen_visible w3ddmg_screen_visible
#define w3d_screen_x w3ddmg_screen_x
#define w3d_screen_y w3ddmg_screen_y
#define w3d_sin_q6 w3ddmg_sin_q6
#define w3d_stage w3ddmg_stage
#define w3d_stage_clear_pixel w3ddmg_stage_clear_pixel
#define w3d_stage_clear_span w3ddmg_stage_clear_span
#define w3d_transfer_stage_asm w3ddmg_transfer_stage_asm
#define w3d_u16 w3ddmg_u16
#define w3d_u8 w3ddmg_u8
#define w3d_vram_tiles w3ddmg_vram_tiles
#define w3d_wait_vblank_start w3ddmg_wait_vblank_start
#define w3dbg_enter w3ddmgbg_enter
#define w3dco_enter w3ddmgco_enter
#define w3dco_loop w3ddmgco_loop
#define w3dco_page w3ddmgco_page
#define w3dcs_enter w3ddmgcs_enter
#define w3dcs_inner w3ddmgcs_inner
#define w3dcs_outer w3ddmgcs_outer
#define w3dcv_enter w3ddmgcv_enter
#define w3dcv_loop w3ddmgcv_loop
#define w3dcv_page w3ddmgcv_page
#define w3dfb_enter w3ddmgfb_enter
#define w3dfb_loop w3ddmgfb_loop
#define w3dfb_page w3ddmgfb_page
#define w3dls_branch w3ddmgls_branch
#define w3dls_done w3ddmgls_done
#define w3dls_enter w3ddmgls_enter
#define w3dls_shallow w3ddmgls_shallow
#define w3dls_shallow_loop w3ddmgls_shallow_loop
#define w3dls_shallow_skip_bridge w3ddmgls_shallow_skip_bridge
#define w3dls_steep w3ddmgls_steep
#define w3dls_steep_loop w3ddmgls_steep_loop
#define w3dls_steep_skip_bridge w3ddmgls_steep_skip_bridge
#define w3dls_x_reverse w3ddmgls_x_reverse
#define w3dls_y_reverse w3ddmgls_y_reverse
#define w3dls_y_start w3ddmgls_y_start
#define w3dps_enter w3ddmgps_enter
#define w3dps_ret w3ddmgps_retkitaqgb/lib/wire3d.h
wire3d_cgb.h — CGB 彩色線框
#pragma once
#ifndef KITAQGB_WIRE3D_CGB_H
#define KITAQGB_WIRE3D_CGB_H
#define WIRE3DCGB_SCREEN_W 128
#ifndef WIRE3DCGB_HEIGHT
#define WIRE3DCGB_HEIGHT 96
#endif
#if WIRE3DCGB_HEIGHT != 88 && WIRE3DCGB_HEIGHT != 96
#error WIRE3DCGB_HEIGHT must be 88 or 96
#endif
#define WIRE3DCGB_SCREEN_H WIRE3DCGB_HEIGHT
#if WIRE3DCGB_HEIGHT == 88
#define WIRE3DCGB_TILE_ROWS 11
#define WIRE3DCGB_TILE_COUNT 176
#define WIRE3DCGB_COLUMN_BYTES 176
#define WIRE3DCGB_NEG_COLUMN_BYTES 0xFF50
#define WIRE3DCGB_STAGE_RIGHT 0xDD50
#define WIRE3DCGB_STAGE_BOTTOM 0xD3AE
#define WIRE3DCGB_SECOND_DMA 0xAF
#else
#define WIRE3DCGB_TILE_ROWS 12
#define WIRE3DCGB_TILE_COUNT 192
#define WIRE3DCGB_COLUMN_BYTES 192
#define WIRE3DCGB_NEG_COLUMN_BYTES 0xFF40
#define WIRE3DCGB_STAGE_RIGHT 0xDE40
#define WIRE3DCGB_STAGE_BOTTOM 0xD3BE
#define WIRE3DCGB_SECOND_DMA 0xBF
#endif
// Reserve 3072 bytes in either profile for full-screen compatibility.
#define WIRE3DCGB_UPLOAD_BYTES (WIRE3DCGB_TILE_COUNT * 16)
#define WIRE3DCGB_FULL_SCREEN_W 160
#define WIRE3DCGB_FULL_SCREEN_H 144
#define WIRE3DCGB_FULL_TILE_LIMIT 127
#define WIRE3DCGB_STAGE_BASE 0xD300
#define WIRE3DCGB_STAGE_WRAM_BANK 2
#define WIRE3DCGB_STAGE_BYTES 3072
#define WIRE3DCGB_MODEL_VERTEX_LIMIT 24
#define WIRE3DCGB_MODEL_FACE_LIMIT 16
#define WIRE3DCGB_MODEL_EDGE_LIMIT 64
#define WIRE3DCGB_SCENE_OBJECT_LIMIT 8
#define WIRE3DCGB_FACE_NONE 255
#define WIRE3DCGB_MODEL_HIDDEN_LINES 1
#define WIRE3DCGB_COLOR_LOW 1
#define WIRE3DCGB_COLOR_MAIN 2
#define WIRE3DCGB_COLOR_HIGH 3
#define WIRE3DCGB_COLOR_DEFAULT WIRE3DCGB_COLOR_MAIN
#define WIRE3DCGB_RGB15(r5, g5, b5) ((w3dcgb_u16)((w3dcgb_u16)((r5) & 31) | ((w3dcgb_u16)((g5) & 31) << 5) | ((w3dcgb_u16)((b5) & 31) << 10)))
typedef s8 w3dcgb_i8;
typedef s16 w3dcgb_i16;
typedef u8 w3dcgb_u8;
typedef u16 w3dcgb_u16;
typedef struct {
w3dcgb_i16 x;
w3dcgb_i16 y;
w3dcgb_i16 z;
} Wire3DCGB_Vec3;
typedef struct {
w3dcgb_u8 a;
w3dcgb_u8 b;
} Wire3DCGB_Edge;
typedef struct {
w3dcgb_u8 a;
w3dcgb_u8 b;
w3dcgb_u8 c;
} Wire3DCGB_Face;
typedef struct {
w3dcgb_u8 f0;
w3dcgb_u8 f1;
} Wire3DCGB_EdgeFaces;
typedef struct {
const Wire3DCGB_Vec3* vertices;
const Wire3DCGB_Edge* edges;
const Wire3DCGB_Face* faces;
const Wire3DCGB_EdgeFaces* edge_faces;
w3dcgb_u8 vertex_count;
w3dcgb_u8 edge_count;
w3dcgb_u8 face_count;
w3dcgb_u8 flags;
} Wire3DCGB_Model;
typedef struct {
const Wire3DCGB_Model* model;
w3dcgb_i16 x;
w3dcgb_i16 y;
w3dcgb_i16 z;
w3dcgb_i8 rx;
w3dcgb_i8 ry;
w3dcgb_i8 rz;
w3dcgb_i16 scale_q8;
w3dcgb_u8 visible;
w3dcgb_u8 color;
} Wire3DCGB_Object;
typedef struct {
w3dcgb_i16 x;
w3dcgb_i16 y;
w3dcgb_i16 z;
w3dcgb_i8 rx;
w3dcgb_i8 ry;
w3dcgb_i8 rz;
w3dcgb_u8 color;
} Wire3DCGB_FastCube;
void Wire3DCGB_Init();
void Wire3DCGB_InitFullScreen();
void Wire3DCGB_InitFastMapLite();
void Wire3DCGB_EnableDoubleSpeed();
void Wire3DCGB_SetScreenOffset(w3dcgb_u8 scx, w3dcgb_u8 scy);
void Wire3DCGB_SetPaletteRGB15(w3dcgb_u16 color0, w3dcgb_u16 color1, w3dcgb_u16 color2, w3dcgb_u16 color3);
void Wire3DCGB_SetLineColor(w3dcgb_u8 color);
w3dcgb_u8 Wire3DCGB_GetLineColor();
void Wire3DCGB_ClearFrameTiles();
void Wire3DCGB_BeginFrame();
void Wire3DCGB_BeginFrameFast();
void Wire3DCGB_BeginFrameSparse();
void Wire3DCGB_ClearSparseStageFast();
void Wire3DCGB_MarkDirtyRect2D(w3dcgb_u8 min_x, w3dcgb_u8 min_y, w3dcgb_u8 max_x, w3dcgb_u8 max_y);
void Wire3DCGB_SetCamera(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 pitch, w3dcgb_i8 yaw, w3dcgb_i8 roll);
void Wire3DCGB_DrawModel(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz);
void Wire3DCGB_DrawModelScaled(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz, w3dcgb_i16 scale_q8);
void Wire3DCGB_DrawModelColor(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz, w3dcgb_u8 color);
void Wire3DCGB_DrawModelScaledColor(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz, w3dcgb_i16 scale_q8, w3dcgb_u8 color);
void Wire3DCGB_EraseModelFaces(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz, w3dcgb_i16 scale_q8);
void Wire3DCGB_EraseTriangle2D(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by, w3dcgb_u8 cx, w3dcgb_u8 cy);
void Wire3DCGB_EraseSpan2D(w3dcgb_u8 y, w3dcgb_u8 x0, w3dcgb_u8 x1);
/* Signed endpoints, clipped before conversion to the rasterizer's u8 ABI. */
void Wire3DCGB_DrawLineClipped2D(w3dcgb_i16 x0, w3dcgb_i16 y0,
w3dcgb_i16 x1, w3dcgb_i16 y1, w3dcgb_u8 color);
void Wire3DCGB_DrawEdgeListClipped2D(const Wire3DCGB_Edge* edges, w3dcgb_u8 edge_count,
const w3dcgb_i16* vx, const w3dcgb_i16* vy, w3dcgb_u8 vertex_count,
w3dcgb_i16 cx, w3dcgb_i16 cy, w3dcgb_u8 color);
w3dcgb_i16 Wire3DCGB_ProjectAxis48(w3dcgb_i16 value, w3dcgb_i16 z);
void Wire3DCGB_InvalidateFrameHistory();
/* Startup-only: reserves both BG maps; queued HUD tiles are mirrored. */
void Wire3DCGB_EnableAtomicMaps();
void Wire3DCGB_EraseRect2D(w3dcgb_u8 x0, w3dcgb_u8 y0, w3dcgb_u8 x1, w3dcgb_u8 y1);
void Wire3DCGB_EraseLeftGuard24Fast();
void Wire3DCGB_DrawWhiteBorderFast();
void Wire3DCGB_ClearOcclusionMask();
void Wire3DCGB_SetOcclusionActive(w3dcgb_u8 active);
void Wire3DCGB_MarkTriangle2D(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by, w3dcgb_u8 cx, w3dcgb_u8 cy);
void Wire3DCGB_MarkPackedSilhouette2D(const w3dcgb_u8* profile, w3dcgb_u8 count,
w3dcgb_i8 y0, w3dcgb_u8 x, w3dcgb_u8 y);
void Wire3DCGB_ErasePackedSilhouette2D(const w3dcgb_u8* profile, w3dcgb_u8 count,
w3dcgb_i8 y0, w3dcgb_u8 x, w3dcgb_u8 y);
void Wire3DCGB_DrawScene(Wire3DCGB_Object* objects, w3dcgb_u8 count);
void Wire3DCGB_DrawFastCubes(Wire3DCGB_FastCube* cubes, w3dcgb_u8 count, w3dcgb_u8 hidden_enabled, w3dcgb_u8 selected);
void Wire3DCGB_DrawFastStatus(w3dcgb_u8 hidden_enabled, w3dcgb_u8 selected);
void Wire3DCGB_DrawFastCubeFrame(Wire3DCGB_FastCube* cubes, w3dcgb_u8 count, w3dcgb_u8 hidden_enabled, w3dcgb_u8 selected);
void Wire3DCGB_DrawFastProjectile(w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_i16 z, w3dcgb_u8 phase, w3dcgb_u8 color);
void Wire3DCGB_FastMapBegin();
void Wire3DCGB_FastMapBeginTilesOnly();
void Wire3DCGB_FastMapCell(w3dcgb_u8 tx, w3dcgb_u8 ty, w3dcgb_u8 color, w3dcgb_u8 mask);
void Wire3DCGB_FastMapRect(w3dcgb_u8 tx0, w3dcgb_u8 ty0, w3dcgb_u8 tx1, w3dcgb_u8 ty1, w3dcgb_u8 color, w3dcgb_u8 sides);
void Wire3DCGB_FastMapFlush();
void Wire3DCGB_FastMapFlushTilesOnly();
// Project camera-space coordinates without subtracting/rotating the camera.
// Depth 8..255; outputs unchanged on rejection. Shared scratch: no ISR calls.
w3dcgb_u8 Wire3DCGB_ProjectCameraPoint(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_u8* sx, w3dcgb_u8* sy);
w3dcgb_u8 Wire3DCGB_ProjectPoint(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_u8* sx, w3dcgb_u8* sy);
/* Fast path for games whose camera pitch, yaw, and roll stay at zero. */
w3dcgb_u8 Wire3DCGB_ProjectPointNoRotation(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_u8* sx, w3dcgb_u8* sy);
void Wire3DCGB_DrawLine3D(w3dcgb_i16 ax, w3dcgb_i16 ay, w3dcgb_i16 az, w3dcgb_i16 bx, w3dcgb_i16 by, w3dcgb_i16 bz);
void Wire3DCGB_DrawLine3DColor(w3dcgb_i16 ax, w3dcgb_i16 ay, w3dcgb_i16 az, w3dcgb_i16 bx, w3dcgb_i16 by, w3dcgb_i16 bz, w3dcgb_u8 color);
void Wire3DCGB_DrawPoint2D(w3dcgb_u8 x, w3dcgb_u8 y);
void Wire3DCGB_DrawTinyModel2D(w3dcgb_u8 x, w3dcgb_u8 y,
w3dcgb_u8 turn, w3dcgb_u8 color);
void Wire3DCGB_DrawLine2D(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by);
void Wire3DCGB_DrawLine2DColor(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by, w3dcgb_u8 color);
void Wire3DCGB_DrawMaskedModel2D(const Wire3DCGB_Model* model,
const w3dcgb_i8* vertex_x, const w3dcgb_i8* vertex_y,
const w3dcgb_u8* edge_mask,
w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_u8 color);
void Wire3DCGB_DrawEdgeList2D(const Wire3DCGB_Edge* edges, w3dcgb_u8 edge_count,
const w3dcgb_i8* vertex_x, const w3dcgb_i8* vertex_y,
w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_u8 color);
void Wire3DCGB_DrawLineList2DColor(const w3dcgb_u8* line_xy,
w3dcgb_u8 line_count, w3dcgb_u8 color);
void Wire3DCGB_PutBgTile(w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_u8 tile);
void Wire3DCGB_EndFrame();
void Wire3DCGB_EndFrameFast();
void Wire3DCGB_EndFrameSparse();
void Wire3DCGB_EndFrameSparseNow();
w3dcgb_u8 Wire3DCGB_GetFullScreenTileCount();
w3dcgb_u8 Wire3DCGB_GetFullScreenOverflow();
#endifkitaqgb/lib/wire3d_cgb.h
wire3d_dmg.h — DMG 線框
#pragma once
// Select the viewport at build time before including this header or source.
// Default: 128x120 with consuming uploads and optional dirty/auxiliary transfer.
// Heights 88 and 96 retain the HUD and yaw-mask profile with BeginFrame clearing.
#ifndef WIRE3D_DMG_HEIGHT
#define WIRE3D_DMG_HEIGHT 120
#endif
#if WIRE3D_DMG_HEIGHT != 88 && WIRE3D_DMG_HEIGHT != 96 && WIRE3D_DMG_HEIGHT != 120
#error WIRE3D_DMG_HEIGHT must be 88, 96 or 120
#endif
#ifndef KITAQGB_WIRE3D_DMG_H
#define KITAQGB_WIRE3D_DMG_H
#if WIRE3D_DMG_HEIGHT != 120
// Monochrome 128x88/96 wireframe renderer with global, non-reentrant state.
// It takes over LCD tile data/map and reserves WRAM 0xD000..0xDFFF for staging.
// Angles wrap every 16 steps; scale 256 is unity. Scene occlusion is a coarse
// face-bounding-box/five-line-sample heuristic, not per-pixel depth testing.
#else
// Monochrome 128x120 staged renderer with global non-reentrant state.
// Reserve WRAM 0xD000..0xDFFF and the renderer's tile/map VRAM regions.
// BeginFrame does not clear pixels: uploads consume the stage. Auxiliary source
// strips alias the main stage, and dirty transfer relies on current/previous flags.
#endif
#define WIRE3D_DMG_SCREEN_W 128
#if WIRE3D_DMG_HEIGHT != 120
#define WIRE3D_DMG_SCREEN_H WIRE3D_DMG_HEIGHT
#else
#define WIRE3D_DMG_SCREEN_H 120
#endif
#define WIRE3D_DMG_MODEL_VERTEX_LIMIT 24
#if WIRE3D_DMG_HEIGHT != 120
#define WIRE3D_DMG_MODEL_EDGE_LIMIT 16
#endif
#define WIRE3D_DMG_MODEL_FACE_LIMIT 16
#define WIRE3D_DMG_SCENE_OBJECT_LIMIT 8
#define WIRE3D_DMG_FACE_NONE 255
#define WIRE3D_DMG_MODEL_HIDDEN_LINES 1
#if WIRE3D_DMG_HEIGHT != 120
#define WIRE3D_DMG_EDGE_MASK_BINS_16 16
#else
#define WIRE3D_DMG_ANGLE_STEPS 16
#endif
typedef s8 w3ddmg_i8;
typedef s16 w3ddmg_i16;
typedef u8 w3ddmg_u8;
typedef u16 w3ddmg_u16;
typedef struct {
w3ddmg_i16 x;
w3ddmg_i16 y;
w3ddmg_i16 z;
} Wire3DDMG_Vec3;
typedef struct {
w3ddmg_u8 a;
w3ddmg_u8 b;
} Wire3DDMG_Edge;
typedef struct {
w3ddmg_u8 a;
w3ddmg_u8 b;
w3ddmg_u8 c;
} Wire3DDMG_Face;
typedef struct {
w3ddmg_u8 f0;
w3ddmg_u8 f1;
} Wire3DDMG_EdgeFaces;
#if WIRE3D_DMG_HEIGHT != 120
// Model tables are borrowed for drawing, never copied or bank-switched.
// Counts are capped at 24 vertices, 16 edges and 16 faces; each supplied table
// must contain the referenced entries. Triangle winding with positive projected
// area is front-facing. FACE_NONE denotes a missing adjacent face.
#else
// Model tables are borrowed and must remain readable in the active bank.
// At most 24 vertices and 16 faces are processed; the model edge count is not
// limited to 16. Supply all declared edge and adjacency entries. Positive
// projected triangle area is front-facing; FACE_NONE means missing adjacency.
#endif
typedef struct {
const Wire3DDMG_Vec3* vertices;
const Wire3DDMG_Edge* edges;
const Wire3DDMG_Face* faces;
const Wire3DDMG_EdgeFaces* edge_faces;
#if WIRE3D_DMG_HEIGHT != 120
/* Keep edge mask tables in RAM for pointer-indirect access on current KITAQGB. */
const w3ddmg_u16* edge_masks;
#endif
w3ddmg_u8 vertex_count;
w3ddmg_u8 edge_count;
w3ddmg_u8 face_count;
#if WIRE3D_DMG_HEIGHT != 120
w3ddmg_u8 edge_mask_count;
#endif
w3ddmg_u8 flags;
} Wire3DDMG_Model;
typedef struct {
const Wire3DDMG_Model* model;
w3ddmg_i16 x;
w3ddmg_i16 y;
w3ddmg_i16 z;
#if WIRE3D_DMG_HEIGHT != 120
w3ddmg_i8 rx;
w3ddmg_i8 ry;
w3ddmg_i8 rz;
#else
w3ddmg_u8 rx;
w3ddmg_u8 ry;
w3ddmg_u8 rz;
#endif
w3ddmg_i16 scale_q8;
w3ddmg_u8 visible;
} Wire3DDMG_Object;
#if WIRE3D_DMG_HEIGHT != 120
// Take over the LCD: wait for VBlank, switch it off, clear 6144 tile bytes and
// the BG map, install HUD tiles and the 128x96 signed-tile viewport, then enable
// BG display with scroll zero and BGP=0xB4. Reset camera, BG queue and stage.
// Reserve 0xD000..0xDFFF for staging and retain its WRAM bank mapping.
// Call BeginFrame before drawing to initialize the occlusion state as well.
#else
// Take over LCD state, clear tile VRAM and the BG map, and install a 16x15
// viewport beginning at map tile (3,1). Set scroll (8,0), BGP=0xB4 and BG display.
// Reset camera, queues, transfer modes, both dirty tables and stage. Reserve
// 0xD000..0xDFFF and retain its WRAM mapping; auxiliary storage aliases it.
// Call BeginFrame before drawing to establish occlusion state.
#endif
void Wire3DDMG_Init();
#if WIRE3D_DMG_HEIGHT != 120
// Clear staged pixels and occlusion mask and disable occlusion filtering.
// This leaves the displayed VRAM frame and pending BG tile queue unchanged.
#else
// Disable occlusion filtering only. Stage clearing normally happens during
// transfer, and Init supplies the first clean stage. This does not discard an
// unsubmitted frame, clear the mask, or reset pending BG writes/dirty flags.
#endif
void Wire3DDMG_BeginFrame();
/* Validate depth and project coordinates already in camera space. */
w3ddmg_u8 Wire3DDMG_ProjectCameraPoint(w3ddmg_i16 x,w3ddmg_i16 y,w3ddmg_i16 z,w3ddmg_u8* sx,w3ddmg_u8* sy);
// Store camera position and angles for later draws; a full turn is 16 angle
// steps. No existing drawing is reprojected and no input range validation occurs.
#if WIRE3D_DMG_HEIGHT != 120
void Wire3DDMG_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 pitch, w3ddmg_i8 yaw, w3ddmg_i8 roll);
#else
void Wire3DDMG_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 pitch, w3ddmg_u8 yaw, w3ddmg_u8 roll);
#endif
// Draw an unscaled model by delegating to DrawModelScaled with scale 256.
#if WIRE3D_DMG_HEIGHT != 120
void Wire3DDMG_DrawModel(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz);
// Scale, rotate in Y/X/Z order, translate and project at most 24 vertices;
// then draw up to 16 edges filtered by yaw masks and optional front-facing faces.
// Nonpositive scale becomes unity (256). Null model/vertex/edge pointers are
// ignored; referenced tables must remain readable. Keep scale products and
// translations in signed 16-bit range. Depth-crossing edges are dropped, not clipped.
void Wire3DDMG_DrawModelScaled(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz, w3ddmg_i16 scale_q8);
#else
void Wire3DDMG_DrawModel(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz);
// Scale up to 24 vertices, rotate Y/X/Z, translate and project, then traverse
// all edge_count entries (a byte count) with optional adjacent-face filtering.
// Face scratch is capped at 16; edge tables must contain all declared entries.
// Nonpositive scale means 256. Null model/vertex/edge pointers are ignored.
// Keep products/translations in signed 16-bit range; depth-crossing edges are dropped.
void Wire3DDMG_DrawModelScaled(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz, w3ddmg_i16 scale_q8);
#endif
// Project up to 24 vertices and erase front-facing triangle interiors from
// the stage for a model with hidden-line flags and face data. Nonpositive scale
// means 256 (unity). Up to 16 faces are considered; depth-crossing faces are
// skipped. This also replaces shared projection caches, but does not update VRAM.
#if WIRE3D_DMG_HEIGHT != 120
void Wire3DDMG_EraseModelFaces(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz, w3ddmg_i16 scale_q8);
#else
void Wire3DDMG_EraseModelFaces(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz, w3ddmg_i16 scale_q8);
#endif
// Erase a triangle from staged pixels using integer scanline intersections.
// Supply viewport coordinates. Degenerate triangles are ignored; the occlusion
// mask and VRAM are unchanged.
void Wire3DDMG_EraseTriangle2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by, w3ddmg_u8 cx, w3ddmg_u8 cy);
// Order the X endpoints and erase the inclusive staged span. Both endpoints
// must be in 0..127; invalid Y is ignored. The routine does not clip X for you.
void Wire3DDMG_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1);
#if WIRE3D_DMG_HEIGHT != 120
// Process at most the first eight objects, sorted near to far by transformed
// origin depth. Draw visible valid models, then mark their front-face bounding
// rectangles to reject fully sampled later lines. This approximates inter-object
// occlusion, not a depth buffer. It clears its mask but retains existing staged
// pixels. Null arrays are ignored; objects and their data must remain readable.
#else
// Sort at most eight object origins by camera depth, near to far. Draw visible
// valid models and mark front-face bounding rectangles for later objects. The
// first sorted slot bypasses mask tests and the last needs no new occluder.
// This is coarse line rejection, not a depth buffer. Null/empty input is ignored;
// caller data and the current projection cache must remain valid during traversal.
#endif
void Wire3DDMG_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count);
#if WIRE3D_DMG_HEIGHT != 120
// Select a precomputed mask from the low four bits of object yaw; pitch,
// roll and camera orientation are ignored. Use 16, 8, 4 or 2 bins; other positive
// counts select entry zero (counts >=16 use the first 16). Missing data returns
// 0xFFFF. Keep the mask table readable through the current data-pointer mapping.
w3ddmg_u16 Wire3DDMG_SelectEdgeMask(const Wire3DDMG_Model* model, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz);
// Project a world point with the current camera. Return zero for rejected
// depth, leaving outputs unchanged; success writes clamped coordinates for the selected height.
// Output pointers must be valid. Screen clamping is not geometric clipping.
#else
// Project a world point with the current camera. Return zero for invalid
// depth without changing outputs; success writes clamped 128x120 coordinates.
// Both output pointers must be valid. Coordinate differences must fit s16.
#endif
w3ddmg_u8 Wire3DDMG_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy);
#if WIRE3D_DMG_HEIGHT == 120
// Rotate in place in Y/X/Z order using 16 steps per full turn. A null
// component pointer makes the whole call a no-op; use distinct pointers.
// Each axis rotation clamps its inputs to +/-220.
void Wire3DDMG_RotatePoint(w3ddmg_i16* x, w3ddmg_i16* y, w3ddmg_i16* z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz);
#endif
// Project both world endpoints and draw only when both pass the depth range.
// Do not intersect a crossing segment with near/far planes; projected endpoints
// are independently clamped to the screen edges.
void Wire3DDMG_DrawLine3D(w3ddmg_i16 ax, w3ddmg_i16 ay, w3ddmg_i16 az, w3ddmg_i16 bx, w3ddmg_i16 by, w3ddmg_i16 bz);
#if WIRE3D_DMG_HEIGHT != 120
// Draw a connected line into the 128x96 stage, including endpoints. During
// DrawScene, use the coarse five-sample occlusion rejection; otherwise draw directly.
// Supply viewport coordinates. VRAM is updated only by EndFrame.
#else
// Mark the bounding tile rectangle when dirty transfer is enabled, then draw
// a connected staged line. Scene drawing may reject it using five mask samples.
// Supply 128x120 viewport endpoints; low-level pixel bounds checks do not clip
// the segment geometrically.
#endif
void Wire3DDMG_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by);
#if WIRE3D_DMG_HEIGHT == 120
// Draw a wireframe rectangle directly into the staged bitplane. Endpoints are
// inclusive screen pixels in 0..127 x 0..119; both horizontal and vertical
// edges are written with byte masks and only touched tiles are uploaded.
void Wire3DDMG_DrawRect2D(w3ddmg_u8 x0, w3ddmg_u8 y0, w3ddmg_u8 x1, w3ddmg_u8 y1);
#endif
// Draw the canonical 12 edges of an 8-vertex projected box in one call.
// Vertex order is near-face corners 0..3, then far-face corners 4..7.
void Wire3DDMG_DrawBoxEdges2D(const w3ddmg_u8* sx, const w3ddmg_u8* sy);
#if WIRE3D_DMG_HEIGHT == 120
// Draw byte-pair edge indices after integer scaling and translation; scale
// zero means one, and there is no object rotation or face filtering. Project at
// most 24 vertices. Supply at most 128 edge pairs because byte offsets wrap
// after 255. Invalid vertex IDs/depth-rejected endpoints are skipped; null arrays
// are ignored. Keep coordinate products/sums representable as s16.
void Wire3DDMG_DrawIndexedEdges(const Wire3DDMG_Vec3* vertices, w3ddmg_u8 vertex_count, const w3ddmg_u8* edges, w3ddmg_u8 edge_count, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 scale);
#endif
// Queue a tile write to the 32x32 map at 0x9800 for EndFrame. Invalid map
// coordinates and submissions beyond 48 pending writes are silently ignored.
// This queue is separate from the general vram library queue.
void Wire3DDMG_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile);
// Write the raw DMG BGP palette encoding immediately; no frame synchronization occurs.
void Wire3DDMG_SetPalette(w3ddmg_u8 bgp);
#if WIRE3D_DMG_HEIGHT != 120
// Wait for the next VBlank, flush pending BG map writes, then copy the stage
// to VRAM while polling access windows. Copying consumes the staged pixels.
// The transfer may extend beyond VBlank; this is not an atomic frame swap.
#else
// Store the EndFrame auxiliary-transfer gate; any nonzero value enables it.
// No data is copied or cleared here. Auxiliary source bytes alias the main stage.
void Wire3DDMG_SetAuxTransfer(w3ddmg_u8 flag);
// Store the dirty-transfer gate and clear both dirty histories and the main
// stage, even if the value is unchanged. VRAM is retained; enabling this over an
// old image can leave unmarked old tiles, so arrange a clean displayed baseline.
void Wire3DDMG_SetDirtyTransfer(w3ddmg_u8 flag);
// Upload and consume the full main stage immediately, polling STAT but not
// waiting for the next VBlank. Ignore transfer gates and leave dirty histories
// and BG tile queue unchanged; the caller coordinates the frame lifecycle.
void Wire3DDMG_TransferMainNow();
// Upload and consume auxiliary source strips immediately, independent of the
// auxiliary gate. No VBlank-start wait or dirty-history/BG-queue update occurs.
// The source overlaps the main stage and must be coordinated with its upload.
void Wire3DDMG_TransferAuxNow();
// Wait for the next VBlank and flush BG writes, then optionally consume the
// auxiliary strips before uploading either dirty tiles or the entire main stage.
// Auxiliary/main source overlap makes that ordering significant. STAT polling
// continues across access windows; the update need not fit one VBlank.
#endif
void Wire3DDMG_EndFrame();
// Same queue/gate/history lifecycle, without the initial fresh-VBlank wait.
// Synchronous STAT-safe upload; not an atomic swap. LCD must remain enabled.
void Wire3DDMG_EndFrameNow();
#endif
#if WIRE3D_DMG_HEIGHT == 120
#endifkitaqgb/lib/wire3d_dmg.h
zx0.h —
#pragma once
// Copyright (c) 2026 DAISUKE OBA. MIT License.
// ZX0-compatible forward v2 streams; format designed by Einar Saukas.
#define ZX0_OK 0
#define ZX0_BAD_ARGUMENT 1
#define ZX0_TRUNCATED 2
#define ZX0_BAD_STREAM 3
#define ZX0_OUTPUT_FULL 4
#define ZX0_DISPLAY_ACTIVE 5
// Shared last-call status. These foreground routines are not reentrant.
extern u8 zx0_error;
// Return decoded bytes, or zero on error (possibly after partial writes).
// Source and output must not overlap or cross their current CPU bank windows.
// Capacity and packed_size are byte counts. No prefix/backward/v1 streams.
u16 zx0_decompress(void* dst, u16 capacity, const void* src, u16 packed_size);
// Decode a KQA1 raw/RLE/ZX0 asset produced with --format=auto.
// Empty raw assets return zero with zx0_error==ZX0_OK.
u16 asset_decompress(void* dst, u16 capacity, const void* src, u16 packed_size);
// Decode directly into the selected GB VRAM bank ($8000..$9FFF), with LCD off.
// Preserve LCDC, VBK and interrupt state. Output must fit before $A000.
u16 zx0_decompress_vram(u16 vram_addr, const void* src, u16 packed_size);kitaqgb/lib/zx0.h







