KITAQ SERIES • REFERENZAUSGABE
KITAQGB-BIBLIOTHEK
Werkzeuge zur Spieleentwicklung
Quellenstand: 14. September 2026 · Englische Referenzausgabe: 14. September 2026
Bibliotheken mit dem nativen Compiler verwenden
lib/ enthält C-Header und C-Quellen, die in das Konsolen-ROM übersetzt werden. PC-Compiler und Hilfswerkzeuge sind in Rust geschrieben; Spielquellen, Zielbibliotheken und ihre APIs bleiben C. Die mitgelieferten SOURCE_MANIFEST.json und LIBRARY_MERGE.json dokumentieren die Auswahl der Bibliotheksquellen.
kitaqgb · Nativer Rust-Compiler und Hilfswerkzeuge · GitHub Actions
Native Builds und Ausführungsprüfungen waren unter Windows, Linux, macOS ARM und macOS Intel erfolgreich. KITAQGB bestand pro Umgebung 48 Tests und 395 Werkzeugprüfungen, KITAQFC 55 und 401. Rust 1.85 wurde ebenfalls getestet. PUBLIC_DISTRIBUTION.json enthält die Hashwerte der installierten Programme und die Herkunft der Prüfergebnisse. Die öffentlichen GitHub-Actions-Workflows bauen und testen diese Quellen unabhängig.
Gespeicherte Referenzausgaben prüfen ROM-Bytes, Diagnosen und Werkzeugformate. Frühere C#-Emulatorprüfungen bleiben historische Nachweise mit ihren ursprünglichen Quellfingerabdrücken. Sie belegen nicht automatisch sämtliche Rust-APIs, echte Hardware oder einen vollständigen Spielstart über das FDS-BIOS. Das nicht verfügbare ursprüngliche PNG-Skript wurde nach seiner Spezifikation neu implementiert; Bytegleichheit mit ihm kann nicht bestätigt werden.
Vollständige Beispielprogramme
Enthalten sind alle Programme, die gemeinsamen Header, die bereitgestellte ascii.c und die daraus konvertierten Ressourcen. Namen mit m_ am Anfang bezeichnen Hilfsfunktionen für diese Handbücher. Lesen Sie jeden Build-Befehl zusammen mit dem erwarteten Ergebnis und dem Prüfprotokoll. Führen Sie die Befehle im übergeordneten Ordner der nebeneinanderliegenden Repositories aus.
Skript zur Stapelkompilierung / Ergebnisse und Bildschirmaufnahmen
Den mitgelieferten Zeichensatz anzeigen gb_font.c
Zweck: Zeigt, welche Buchstaben, Ziffern und Satzzeichen die mitgelieferte eigens erstellte Schrift enthält und wie sie gezeichnet werden.
Funktionsweise: m_init bereitet Anzeige und Schrift vor. m_text zeichnet jede Zeile; m_put zeichnet das doppelte Anführungszeichen mit Zeichencode 34.
Bedienung und erwartetes Ergebnis: Prüfen Sie, ob 26 Großbuchstaben, 26 Kleinbuchstaben, 10 Ziffern und 30 Satzzeichen erscheinen und alle Zeichen gut lesbar sind. Es ist keine Eingabe erforderlich.

Quelltext herunterladen / Prüfstatus
.\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(); }
}Die erste Textausgabe gb_hello.c
Zweck: Zeigt den grundlegenden Ablauf zum Starten einer ROM und zum Zeichnen von Text und einer Zahl im Hintergrund.
Funktionsweise: Nach m_init zeichnet m_text die Begrüßung und m_number formatiert 42. Die abschließende Schleife wartet auf Frames und lässt das Bild sichtbar.
Bedienung und erwartetes Ergebnis: Der Bildschirm zeigt HELLO WORLD und 042. Die führende Null entsteht durch die Dezimaldarstellung mit drei Stellen.

Quelltext herunterladen / Prüfstatus
.\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(); }
}Mit breiterem Zwischentyp rechnen gb_arithmetic.c
Zweck: Zeigt, wie ein Zwischenergebnis gespeichert wird, das nicht in acht Bit passt.
Funktionsweise: (u16)200 + 100 ergibt 300. Das Programm teilt das Ergebnis durch 10 und wandelt es anschließend zur Anzeige in u8 um. Beachten Sie, dass die Typverbreiterung vor der Addition erfolgt.
Bedienung und erwartetes Ergebnis: 030 steht für das berechnete Ergebnis 30.

Quelltext herunterladen / Prüfstatus
.\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(); }
}Verzweigungen und Schleifen gb_control.c
Zweck: Erprobt for, continue, while, do/while und switch in einer kleinen Berechnung.
Funktionsweise: Die Summe von 0 bis 7 ohne 3 ergibt 25. Die while-Schleife erhöht auf 30, do/while auf 32, und switch wählt case 32, um 42 zuzuweisen.
Bedienung und erwartetes Ergebnis: 042 ist das Endergebnis dieser Schleifen und Verzweigungen.

Quelltext herunterladen / Prüfstatus
.\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(); }
}Funktionen, Arrays, Strukturen und Zeiger gb_aggregate.c
Zweck: Zeigt, wie Werte gruppiert und über Funktionen und Zeiger angesprochen werden.
Funktionsweise: Das Programm kopiert einen Point mit (10,20) und schreibt dann über einen Zeiger 1 bis 4 in ein Array. Es addiert das Funktionsergebnis 30, die Arraywerte 1, 2 und 4 sowie die Konstante 5.
Bedienung und erwartetes Ergebnis: Die Summe wird als 042 angezeigt. Verfolgen Sie die Strukturkopie, die Schreibzugriffe auf ptr[i] und den Rückgabewert der Funktion.
![Funktionen, Arrays, Strukturen und Zeiger: Die Summe wird als 042 angezeigt. Verfolgen Sie die Strukturkopie, die Schreibzugriffe auf ptr[i] und den Rückgabewert der Funktion.](../verification/gb_aggregate.png)
Quelltext herunterladen / Prüfstatus
.\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(); }
}Bitflags und Pufferkopie gb_bits_memory.c
Zweck: Packt Flags in ein Byte und kopiert einen Puffer in einen getrennten Speicherbereich.
Funktionsweise: __memset löscht vier Bytes. Das Programm setzt Bit 3, invertiert Bit 1 und kopiert anschließend alle vier Bytes mit __memcpy.
Bedienung und erwartetes Ergebnis: Das erste Zielbyte wird als 010 angezeigt; Bit 3 trägt 8 und Bit 1 trägt 2 bei.

Quelltext herunterladen / Prüfstatus
.\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(); }
}Neue Tastendrücke zählen gb_input.c
Zweck: Unterscheidet einen neuen Tastendruck von einer weiterhin gedrückten Taste.
Funktionsweise: In jedem Frame wird input_update aufgerufen. Der Zähler steigt nur, wenn input_pressed(BTN_A) wahr ist.
Bedienung und erwartetes Ergebnis: Der Anfangswert ist 000. Drücken Sie A, um 001 zu erhalten; Gedrückthalten erhöht den Zähler nicht weiter. Loslassen und erneut drücken ergibt 002. Der Bytezähler springt nach 255 auf 000 zurück.

Quelltext herunterladen / Prüfstatus
.\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-Festkommawerte multiplizieren gb_fixed.c
Zweck: Zeigt die Umwandlung von Ganzzahlen in Q8.8, die Multiplikation und die Rückwandlung in eine Ganzzahl.
Funktionsweise: fix_from_int wandelt 3 und 4 in Q8.8 um. fix_mul multipliziert sie, und fix_to_int wandelt das Produkt wieder in eine Ganzzahl um.
Bedienung und erwartetes Ergebnis: 012 bedeutet 3 × 4 = 12. Es ist die umgewandelte Ganzzahl, nicht der intern mit 256 skalierte Wert.

Quelltext herunterladen / Prüfstatus
.\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(); }
}Aus einem festen Objektpool zuweisen gb_entity.c
Zweck: Erzeugt ein Objekt aus einer festen Menge von Speicherplätzen, ohne dynamische Speicherzuweisung.
Funktionsweise: entity_init setzt den Pool zurück. entity_create erzeugt Typ 1 bei (20,30); das Programm prüft auf die Fehler-ID 0xFF, bevor es vx auf 2 setzt.
Bedienung und erwartetes Ergebnis: 001 ist die Anzahl aktiver Objekte, keine ID oder Koordinate. Das Beispiel aktualisiert und zeichnet das Objekt nicht; daher erscheint keine bewegte Figur.

Quelltext herunterladen / Prüfstatus
.\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(); }
}Einen Diagnosewert im RAM aufzeichnen gb_debug.c
Zweck: Speichert einen benannten Spielwert getrennt von der Bildschirmanzeige in einem Diagnosepuffer.
Funktionsweise: Das Programm initialisiert die Diagnose, setzt die Framekennung auf 1 und zeichnet den Wert 42 unter dem Namen HP auf.
Bedienung und erwartetes Ergebnis: 001 ist die Anzahl der Trace-Einträge. HP=42 liegt im Diagnosepuffer; der Bildschirm allein zeigt oder bestätigt diesen Inhalt nicht.

Quelltext herunterladen / Prüfstatus
.\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(); }
}Einen Positionsverlauf speichern gb_chain.c
Zweck: Zeigt, wie ein Positionsverlauf in einem Ringpuffer gespeichert wird.
Funktionsweise: chain_init bindet ein Array mit Platz für vier Punkte ein. Anschließend zeichnet chain_push_head (20,30) auf.
Bedienung und erwartetes Ergebnis: 042 ist eine feste Abschlussmarkierung, keine Koordinate oder Anzahl. Prüfen Sie trail und points für den gespeicherten Verlauf. Dieses Programm zeichnet keinen nachfolgenden Körper.

Quelltext herunterladen / Prüfstatus
.\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(); }
}Den Framezähler der Bibliothek lesen gb_system.c
Zweck: Zeigt, wie Wartezeiten in Frames den Framezähler der Bibliothek beeinflussen.
Funktionsweise: Nach system_init ruft das Programm system_wait_vblank zweimal auf und zeigt system_get_frame8 an.
Bedienung und erwartetes Ergebnis: Das Ergebnis ist 002. Die Warteschleife verwendet die Handbuch-Hilfsfunktion m_wait; der angezeigte Wert steigt daher nicht weiter.

Quelltext herunterladen / Prüfstatus
.\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(); }
}Die aktuelle Szenen-ID wählen gb_scene.c
Zweck: Zeigt, wie eine ID zur Unterscheidung von Szenen wie Titelbildschirm und Spiel gewählt wird.
Funktionsweise: Das Programm registriert zwei mit null initialisierte SceneDef-Einträge und wählt mit scene_change die ID 1.
Bedienung und erwartetes Ergebnis: 001 ist die aktuelle von scene_get_current gelieferte ID. In diesem Beispiel sind weder Szenen-Callbacks noch Übergangszeichnungen registriert.

Quelltext herunterladen / Prüfstatus
.\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(); }
}Weltkoordinaten in Bildschirmkoordinaten umwandeln gb_camera.c
Zweck: Zieht die Kameraposition ab, um die Bildschirmposition eines Weltpunkts zu bestimmen.
Funktionsweise: Camera_Set erhält den Q8.8-Wert 2560, also X=10 Pixel. Anschließend wandelt Camera_WorldToScreenX die Weltkoordinate X=52 um.
Bedienung und erwartetes Ergebnis: 052 minus 010 ergibt die angezeigte 042. Dies ist eine Koordinatenberechnung; der Hintergrund wird nicht gescrollt.

Quelltext herunterladen / Prüfstatus
.\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-Daten in den RAM entpacken gb_rle.c
Zweck: Erprobt eine kompakte Darstellung wiederholter Bytes als Anzahl und Wert.
Funktionsweise: Die gepackten Bytes {3,42,0} bedeuten drei Kopien von 42, gefolgt von einer Nullanzahl als Endmarke. rle_decode schreibt in einen drei Byte großen Zielpuffer.
Bedienung und erwartetes Ergebnis: Das letzte Byte, out[2], wird als 042 angezeigt. Alle drei entpackten Bytes sollen den Wert 42 enthalten.
![RLE-Daten in den RAM entpacken: Das letzte Byte, out[2], wird als 042 angezeigt. Alle drei entpackten Bytes sollen den Wert 42 enthalten.](../verification/gb_rle.png)
Quelltext herunterladen / Prüfstatus
.\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(); }
}Ein Brettfeld lesen und schreiben gb_board.c
Zweck: Zeigt, wie Rasterkoordinaten eines Brettspiels auf Speicherpositionen abgebildet werden.
Funktionsweise: Ein 16-Byte-Array speichert ein 4×4-Brett. Das Programm löscht es, schreibt 42 in Zelle (2,1) und liest dieselbe Zelle wieder.
Bedienung und erwartetes Ergebnis: 042 ist der zurückgelesene Wert. Das Programm zeichnet das 4×4-Brett selbst nicht.

Quelltext herunterladen / Prüfstatus
.\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(); }
}Eine Box um einen Physikschritt bewegen gb_physics.c
Zweck: Initialisiert eine Welt und einen rechteckigen Körper und aktualisiert dann die Position anhand der Geschwindigkeit.
Funktionsweise: Der Körper startet bei (40,40) mit Geschwindigkeit (2,0) und Schwerkraft null. Das Programm ruft kq2d_step einmal auf.
Bedienung und erwartetes Ergebnis: 042 ist die resultierende X-Koordinate, hier in ganzen Pixeln. Es werden weder eine Boxform noch eine fortlaufende Animation gezeichnet.

Quelltext herunterladen / Prüfstatus
.\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(); }
}Abschluss und Timeout einer seriellen Übertragung behandeln gb_link.c
Zweck: Unterscheidet eine abgeschlossene Übertragung von einer Übertragung, die nicht innerhalb der Wartegrenze endet.
Funktionsweise: Der Master sendet 42 und wartet mit Link_WaitByte. Bei Abschluss wird das empfangene Byte angezeigt; bei Timeout wird die Übertragung abgebrochen und null angezeigt.
Bedienung und erwartetes Ergebnis: Eine ohne Verbindung abgeschlossene Übertragung kann 255 liefern. Ein Timeout zeigt 000; bei verbundenem Partner erscheint das empfangene Byte. Das Ergebnis ist nicht immer 042.

Quelltext herunterladen / Prüfstatus
.\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-Daten mit einem Bankargument lesen gb_bank.c
Zweck: Erklärt die Argumente zum Kopieren von ROM-Daten in den RAM.
Funktionsweise: far_data_read kopiert die beiden Bytes 7 und 42 mit Bankargument 0 und Länge 2 nach copied.
Bedienung und erwartetes Ergebnis: Das zweite Zielbyte wird als 042 angezeigt. Dieses Beispiel liest aus fest eingeblendetem ROM; es zeigt keine Übertragung zwischen verschiedenen umschaltbaren Banken.

Quelltext herunterladen / Prüfstatus
.\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(); }
}Daten anhand der Asset-ID laden gb_asset.c
Zweck: Registriert Position und Länge eines Assets und ruft anschließend seine Bytes anhand der ID ab.
Funktionsweise: Asset 0 hat Typ RAW, Bank 0, einen Zeiger auf {7,42} und Länge 2. asset_load_raw kopiert es in einen Zwei-Byte-RAM-Puffer.
Bedienung und erwartetes Ergebnis: Das zweite Byte wird als 042 angezeigt. Das Beispiel demonstriert das Auffinden und Kopieren von Assets, keine Bilddarstellung.

Quelltext herunterladen / Prüfstatus
.\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(); }
}Ein Geschoss zuweisen gb_danmaku.c
Zweck: Initialisiert den Geschosspool und prüft seine Belegung nach dem Erzeugen eines Geschosses.
Funktionsweise: Nach danmaku_reset ruft das Programm danmaku_spawn(40,40,16,0) auf und zeigt dm_count an.
Bedienung und erwartetes Ergebnis: 001 ist die Anzahl zugewiesener Geschosse. Es gibt hier weder eine Geschoss-Aktualisierungsschleife noch eine Hintergrundkomposition; bewegte Geschosse werden nicht gezeichnet.

Quelltext herunterladen / Prüfstatus
.\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(); }
}Eine CGB-Hintergrundpalette einstellen gb_cgb_palette.c
Zweck: Wählt Hintergrund- und Textfarben anhand der RGB-Komponenten des Game Boy Color.
Funktionsweise: Das Programm schaltet das LCD im VBlank aus, setzt Farbe 0 der Palette 0 auf Weiß (31,31,31) und Farbe 3 auf Violett (12,0,22) und aktiviert dann die Anzeige.
Bedienung und erwartetes Ergebnis: Führen Sie das Programm im CGB-Modus aus, um violetten Text und 042 auf weißem Hintergrund zu sehen. Die monochrome DMG-Ausgabe kann diese Farben nicht darstellen.

Quelltext herunterladen / Prüfstatus
.\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(); }
}Den Hintergrund horizontal scrollen gb_scroll.c
Zweck: Verschiebt die Ansicht, ohne den Hintergrundinhalt neu zu zeichnen.
Funktionsweise: Jeder Frame erhöht phase und übergibt den Wert an Scroll_SetBg. Die Acht-Bit-Position springt nach 255 auf null zurück.
Bedienung und erwartetes Ergebnis: Das Wort SCROLL bewegt sich nach links. Beobachten Sie seine Position über die Zeit; eine einzelne Aufnahme kann die Bewegung nicht zeigen.

Quelltext herunterladen / Prüfstatus
.\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); }
}Eine Tile-Aktualisierung einreihen gb_vram_queue.c
Zweck: Trennt eine Zeichenanforderung von der VRAM-Übertragung, die sie umsetzt.
Funktionsweise: vram_queue_bg_tile reiht Tile 52 für Tile-Koordinate (3,8) ein, und vram_flush überträgt es. In der mitgelieferten Schrift ist Tile 52 die Ziffer 4.
Bedienung und erwartetes Ergebnis: Achten Sie auf eine einzelne 4 bei Hintergrund-Tile-Koordinate (3,8). Dies ist eine Tile-Aktualisierung, kein Zahlenzähler.

Quelltext herunterladen / Prüfstatus
.\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(); }
}Ein Sprite per OAM-DMA anzeigen gb_sprite.c
Zweck: Weist ein Sprite zu und zeigt es unabhängig vom Hintergrund an.
Funktionsweise: Der neu initialisierte Pool liefert Platz 0. Das Programm wählt Tile 65, setzt Position (70,80), aktiviert die OBJ-Anzeige und überträgt das Schatten-OAM in jedem Frame.
Bedienung und erwartetes Ergebnis: An der angegebenen Sprite-Position erscheint ein unbewegtes A. Prüfen Sie im Spiel vor Verwendung der zurückgegebenen ID, ob die Zuweisung fehlgeschlagen ist.

Quelltext herunterladen / Prüfstatus
.\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(); }
}Einen reproduzierbaren Zufallswert erzeugen gb_rng.c
Zweck: Verwendet einen Startwert, um eine Pseudozufallsfolge zu reproduzieren.
Funktionsweise: rng_seed(1234) initialisiert den Generator; danach wird rng_range(10) einmal aufgerufen. Die Obergrenze 10 ist ausgeschlossen.
Bedienung und erwartetes Ergebnis: Der Bildschirm zeigt einen Wert von 000 bis 009. Ein Neustart desselben Programms mit demselben Startwert erzeugt ihn erneut; er ändert sich nicht in jedem Frame.

Quelltext herunterladen / Prüfstatus
.\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(); }
}Ein Spielzustandsflag speichern gb_flags.c
Zweck: Stellt einen booleschen Zustand, etwa den Abschluss eines Ereignisses, durch eine Flagnummer dar.
Funktionsweise: Das Programm löscht Flag 12, setzt es und liest es mit flag_get zurück.
Bedienung und erwartetes Ergebnis: 001 bedeutet, dass Flag 12 wahr ist. Das Beispiel arbeitet mit RAM-Flags und erhält sie nicht über Aus- und Einschalten hinweg.

Quelltext herunterladen / Prüfstatus
.\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(); }
}Einen Kreis um einen Physikschritt bewegen gb_circle.c
Zweck: Richtet einen kreisförmigen Körper ein und aktualisiert seine Position anhand der Geschwindigkeit.
Funktionsweise: Der aktive Kreis hat Radius 4, Position (40,40) und Geschwindigkeit (2,0). Die Schwerkraft ist null und linear_damping_q8 ist 255; kq2dc_step wird einmal ausgeführt.
Bedienung und erwartetes Ergebnis: 042 ist die resultierende ganzzahlige X-Koordinate. Das Beispiel zeichnet weder einen Kreisumriss noch eine Kollisionsanimation.

Quelltext herunterladen / Prüfstatus
.\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(); }
}Einen Soundeffekt in jedem Frame verarbeiten gb_sound.c
Zweck: Startet einen Soundeffekt-Datenstrom und lässt ihn durch regelmäßige Frameaktualisierungen fortschreiten.
Funktionsweise: Nach Audio_Init startet Audio_PlaySFX tone auf Kanal-ID 1. Die Hauptschleife ruft Audio_Update einmal pro Frame auf.
Bedienung und erwartetes Ergebnis: Ein kurzer Pulseffekt erklingt, während 042 sichtbar bleibt. Die Zahl ist eine feste Markierung, weder Lautstärke noch Wiedergabeposition. Beurteilen Sie den Klang über die Audioausgabe oder eine Aufnahme.

Quelltext herunterladen / Prüfstatus
.\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-Referenz der Bibliothek
554 Einträge. Öffnen Sie einen Eintrag, um Syntax, Argumente, Quellhinweise und ein Anwendungsbeispiel zu sehen. Aufruffragmente benötigen zusätzliche Initialisierung und sind keine eigenständigen ROMs. Die Beispiele zeigen, wie vorbereitete Werte an die API übergeben werden; sie belegen keine Prüfung am Gerät.
zx0
Decodiert ZX0-kompatible Assets in RAM oder VRAM. Bereiten Sie Assets am PC mit kitaqgb-zx0.exe vor und decodieren Sie zur Laufzeit nur benötigte Daten. --format=auto vergleicht unkomprimierte, RLE- und ZX0-Nutzdaten und wählt die kleinsten; bei Gleichstand gilt die Reihenfolge unkomprimiert, RLE, ZX0. Der gesamte Container einschließlich Neun-Byte-Header darf 65535 Bytes nicht überschreiten. Teilen Sie Assets passend zu tatsächlichen CPU-Bänken und RAM auf.
Einar Saukas entwickelte das ZX0-Format und den ursprünglichen Kompressionsalgorithmus. Der hier bereitgestellte Kompressor und Dekompressor sind unabhängige KITAQ-Implementierungen, Copyright DAISUKE OBA, veröffentlicht unter der MIT-Lizenz.
Führen Sie diese Hostbefehle im Stammverzeichnis des Repositorys aus. Bauen Sie das Werkzeug 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
Decodiert einen ZX0-v2-Strom in einen begrenzten RAM-Bereich. Übereinstimmungen verweisen auf zuvor decodierte Bytes; das Ziel muss daher les- und beschreibbar sein. Geeignet für Tilemaps oder Leveltabellen, die die CPU vor ihrer Verwendung verarbeitet.
Syntax
u16 zx0_decompress(void* dst, u16 capacity, const void* src, u16 packed_size);Parameter
dstBeginn des beschreibbaren Ziel-RAM; darf nicht null sein. Geben Sie die Kapazität in Bytes an, nicht in Arrayelementen.
capacityAnzahl beschreibbarer Zielbytes. Ein gewöhnlicher ZX0-Strom benötigt mindestens ein Byte. Ein leeres unkomprimiertes KQA1-Asset kann mit Kapazität null erfolgreich sein.
srcBeginn der über die aktuelle Bankeinblendung lesbaren komprimierten Daten. Darf nicht null sein.
packed_sizeByteanzahl der vollständigen Eingabe. Ein ZX0-Strom enthält seine Endmarkierung und keine nachfolgenden Bytes. Ein KQA1-Container enthält seinen Neun-Byte-Header. Maximum: 65535 Bytes.
Rückgabewert
Liefert bei Erfolg die Anzahl decodierter Bytes, bei Fehler null. Prüfen Sie stets auch zx0_error.
Bedingungen und Grenzen
Binden Sie zx0.h ein und kompilieren Sie lib/zx0.c. Diese Routinen teilen sich Arbeitsspeicher und sind aus Interrupts nicht reentrant. Ein- und Ausgabe dürfen weder überlappen noch im CPU-Adressraum umbrechen oder aktuell eingeblendete Bankfenster überschreiten. Die Bibliothek schaltet keine Asset-Bänke um.
Jeder Aufruf aktualisiert zx0_error: 0 Erfolg, 1 ungültiges Argument, 2 abgeschnittene Eingabe, 3 fehlerhafter Datenstrom, 4 zu wenig Ausgabespeicher, 5 aktive Anzeige. Ein Fehler kann Teilausgabe hinterlassen; verwenden Sie diese nicht. Bei mehreren ungültigen Bedingungen bestimmt die zuerst erkannte den Code.
Akzeptiert vorwärtsgerichtete ZX0-v2-Ströme. ZX0 v1, Rückwärtsströme und externe Wörterbücher gehören nicht zu dieser Schnittstelle. Kennen Sie die decodierte Größe des am Host erzeugten Assets und stellen Sie ausreichend Speicher bereit.
Anwendungsbeispiel
count=zx0_decompress(decoded_map,16,packed_map,packed_map_SIZE);
if(count!=16||zx0_error!=ZX0_OK)failures++;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Die Zeile RAM MAP wiederholt Quadrat-, Rauten- und Schachbrett-Tiles. AUTO RLE MAP bildet aus sechzehn Quadraten einen waagerechten Balken. VRAM TILES wiederholt dieselben drei Tiles nach Decodierung ihrer Pixel ins VRAM. Auf CGB und FC ist das Quadrat weiß, die Raute rot und das Schachbrett blau; DMG verwendet Graustufen. CHECKS OK bestätigt die erwarteten decodierten Größen ohne Fehler bei allen drei Aufrufen.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Liest Codec und Größen aus einem mit --format=auto erzeugten KQA1-Header und kopiert dann rohe Bytes oder decodiert RLE/ZX0 ins RAM. Der Aufrufer benötigt keine separate Verzweigung je Codec.
Syntax
u16 asset_decompress(void* dst, u16 capacity, const void* src, u16 packed_size);Parameter
dstBeginn des beschreibbaren Ziel-RAM; darf nicht null sein. Geben Sie die Kapazität in Bytes an, nicht in Arrayelementen.
capacityAnzahl beschreibbarer Zielbytes. Ein gewöhnlicher ZX0-Strom benötigt mindestens ein Byte. Ein leeres unkomprimiertes KQA1-Asset kann mit Kapazität null erfolgreich sein.
srcBeginn der über die aktuelle Bankeinblendung lesbaren komprimierten Daten. Darf nicht null sein.
packed_sizeByteanzahl der vollständigen Eingabe. Ein ZX0-Strom enthält seine Endmarkierung und keine nachfolgenden Bytes. Ein KQA1-Container enthält seinen Neun-Byte-Header. Maximum: 65535 Bytes.
Rückgabewert
Liefert bei Erfolg die Anzahl decodierter Bytes, bei Fehler null. Prüfen Sie stets auch zx0_error.
Bedingungen und Grenzen
Binden Sie zx0.h ein und kompilieren Sie lib/zx0.c. Diese Routinen teilen sich Arbeitsspeicher und sind aus Interrupts nicht reentrant. Ein- und Ausgabe dürfen weder überlappen noch im CPU-Adressraum umbrechen oder aktuell eingeblendete Bankfenster überschreiten. Die Bibliothek schaltet keine Asset-Bänke um.
Jeder Aufruf aktualisiert zx0_error: 0 Erfolg, 1 ungültiges Argument, 2 abgeschnittene Eingabe, 3 fehlerhafter Datenstrom, 4 zu wenig Ausgabespeicher, 5 aktive Anzeige. Ein Fehler kann Teilausgabe hinterlassen; verwenden Sie diese nicht. Bei mehreren ungültigen Bedingungen bestimmt die zuerst erkannte den Code.
KQA1 ist der KITAQ-Asset-Container: Vier-Byte-Kennung, Ein-Byte-Codec (0 unkomprimiert, 1 RLE, 2 ZX0), decodierte Größe u16, Nutzdatengröße u16, danach Nutzdaten. Die u16-Felder sind Little-Endian. RLE wiederholt Anzahl/Wert-Paare mit Anzahlen 1..255 und einem Abschluss mit Anzahl null. Ein leeres unkomprimiertes Asset ist mit Rückgabewert null und Fehler null erfolgreich.
Anwendungsbeispiel
count=asset_decompress(decoded_auto,16,packed_auto,packed_auto_SIZE);
if(count!=16||zx0_error!=ZX0_OK)failures++;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Die Zeile RAM MAP wiederholt Quadrat-, Rauten- und Schachbrett-Tiles. AUTO RLE MAP bildet aus sechzehn Quadraten einen waagerechten Balken. VRAM TILES wiederholt dieselben drei Tiles nach Decodierung ihrer Pixel ins VRAM. Auf CGB und FC ist das Quadrat weiß, die Raute rot und das Schachbrett blau; DMG verwendet Graustufen. CHECKS OK bestätigt die erwarteten decodierten Größen ohne Fehler bei allen drei Aufrufen.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Decodiert bei angehaltenem LCD ZX0-Tilepixel oder Kartendaten direkt in die gewählte VRAM-Bank. VRAM selbst liefert den Verlauf für Rückverweise; ein RAM-Zwischenpuffer ist daher unnötig.
Syntax
u16 zx0_decompress_vram(u16 vram_addr, const void* src, u16 packed_size);Parameter
vram_addrVRAM-Startadresse, 0x8000..0x9FFF. Die Ausgabe wird durch das VRAM-Ende bei 0xA000 begrenzt. Wählen Sie auf CGB vor dem Aufruf VBK.
srcBeginn der über die aktuelle Bankeinblendung lesbaren komprimierten Daten. Darf nicht null sein.
packed_sizeByteanzahl der vollständigen Eingabe. Ein ZX0-Strom enthält seine Endmarkierung und keine nachfolgenden Bytes. Ein KQA1-Container enthält seinen Neun-Byte-Header. Maximum: 65535 Bytes.
Rückgabewert
Liefert bei Erfolg die Anzahl decodierter Bytes, bei Fehler null. Prüfen Sie stets auch zx0_error.
Bedingungen und Grenzen
Binden Sie zx0.h ein und kompilieren Sie lib/zx0.c. Diese Routinen teilen sich Arbeitsspeicher und sind aus Interrupts nicht reentrant. Ein- und Ausgabe dürfen weder überlappen noch im CPU-Adressraum umbrechen oder aktuell eingeblendete Bankfenster überschreiten. Die Bibliothek schaltet keine Asset-Bänke um.
Jeder Aufruf aktualisiert zx0_error: 0 Erfolg, 1 ungültiges Argument, 2 abgeschnittene Eingabe, 3 fehlerhafter Datenstrom, 4 zu wenig Ausgabespeicher, 5 aktive Anzeige. Ein Fehler kann Teilausgabe hinterlassen; verwenden Sie diese nicht. Bei mehreren ungültigen Bedingungen bestimmt die zuerst erkannte den Code.
Akzeptiert vorwärtsgerichtete ZX0-v2-Ströme. ZX0 v1, Rückwärtsströme und externe Wörterbücher gehören nicht zu dieser Schnittstelle. Kennen Sie die decodierte Größe des am Host erzeugten Assets und stellen Sie ausreichend Speicher bereit.
Liefert Fehler 5 bei aktiviertem LCD; VBlank allein genügt nicht. Anzeige-, VBK- und Interrupt-Einstellungen bleiben unverändert. Der Aufrufer stoppt und startet das LCD.
Anwendungsbeispiel
count=zx0_decompress_vram(0x8800,packed_tiles,packed_tiles_SIZE);
if(count!=48||zx0_error!=ZX0_OK)failures++;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Die Zeile RAM MAP wiederholt Quadrat-, Rauten- und Schachbrett-Tiles. AUTO RLE MAP bildet aus sechzehn Quadraten einen waagerechten Balken. VRAM TILES wiederholt dieselben drei Tiles nach Decodierung ihrer Pixel ins VRAM. Auf CGB und FC ist das Quadrat weiß, die Raute rot und das Schachbrett blau; DMG verwendet Graustufen. CHECKS OK bestätigt die erwarteten decodierten Größen ohne Fehler bei allen drei Aufrufen.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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 — Ressourcen-IDs und Datenbeschreibungen
Die Ressourcenbibliothek findet Daten in ROM-Bänken über eine 8-Bit-ID. Binden Sie asset.c ein; auf dem FC zusätzlich bank.c. Ein gepackter AssetDesc belegt 6 Byte: Typ, Banknummer der Nutzdaten, 16-Bit-Adresse und Länge in Byte. Deskriptortabelle und Nutzdaten dürfen in verschiedenen ROM-Bänken liegen.
Registrieren Sie die Tabelle vor der ersten Suche. Die Registrierung ist ein gemeinsamer globaler Zustand und darf nicht gleichzeitig mit einer Suche geändert werden. Geprüft werden IDs und der Ausgabezeiger von asset_get, nicht jedoch Tabelle, Nutzdatenadressen oder Cartridge-Inhalt.
Sucht eine RAW- oder TILES-Ressource und überträgt alle desc.len Byte mit __vram_copy. Wählen Sie zuvor die ROM-Bank der Nutzdaten aus: Die GB-Funktion verwendet desc.ptr direkt und schaltet für den Transfer nicht auf desc.bank um.
asset_get
Kopiert einen AssetDesc aus der ROM-Bank der registrierten Tabelle in den bereitgestellten Speicher. Damit werden die Metadaten der Ressource gelesen, nicht ihre Nutzdaten.
Syntax
u8 asset_get(u8 asset_id, AssetDesc* out_desc);Parameter
asset_idRessourcenindex ab null. In der registrierten Tabelle gilt für eine gültige ID
asset_id < count.out_descBeschreibbarer Speicher für einen 6-Byte-Deskriptor. Ein Nullzeiger wird vor dem Tabellenzugriff zurückgewiesen.
Rückgabewert
1 nach dem Kopieren des Deskriptors; 0 bei Nullzeiger oder ungültiger ID. Bei diesen Fehlern bleibt der Zielspeicher unverändert.
Bedingungen und Grenzen
Registrieren Sie die Tabelle vor der ersten Suche. Die Registrierung ist ein gemeinsamer globaler Zustand und darf nicht gleichzeitig mit einer Suche geändert werden. Geprüft werden IDs und der Ausgabezeiger von asset_get, nicht jedoch Tabelle, Nutzdatenadressen oder Cartridge-Inhalt.
Die Beispiele legen den aufrufenden Code in die feste Bank 0, damit ein Wechsel der Quellbank den laufenden Code nicht ausblendet. Die Übertragungen sind synchron. Unterbrechen Sie sie nicht durch eine weitere bankwechselnde Kopie. Die Hilfsfunktion allein macht nicht die gesamte Anwendung interruptsicher.
Anwendungsbeispiel
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);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel liest Deskriptor 0 und prüft Typ TILES, Bank 2, Zeiger und Länge 144 Byte. Ungültige IDs und Nullzeiger müssen scheitern; bei einer fehlgeschlagenen Suche bleibt der vorherige Ausgabewert erhalten.
Erwartetes Bild: Eine rote Reihe beginnt bei (16,32) und belegt 72×8 Pixel. Dreimal folgen ein 8×8-Dreieck, ein 8×8-Quadrat mit einem Pixel Rand und eine Kachel mit vier gefüllten linken Spalten. Das Dreieck wächst von einem Pixel oben links auf acht Pixel in der untersten Zeile.
Auf dem GB zeigen das blaue Dreieck und der Rahmen bei (16,64) das Ergebnis von __farmemcpy, das grüne Paar bei (16,96) das von __far_memcpy. Jedes Paar belegt 16×8 Pixel. Der CGB nutzt diese Farben, der DMG dieselben Formen in Schwarz auf Weiß.
Erwartet werden FAILED CHECKS 000 und FIRST FAILURE 00. Die Prüfung führt 300 Bilder aus und vergleicht Text, Formmasken und Farben mit den Sollwerten. Dies ist ein Emulatornachweis, kein Test auf physischer Hardware.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Liest die Banknummer der Nutzdaten aus dem Deskriptor. Dies ist nicht die Banknummer der Tabelle. Nach dem Aufruf bleibt diese ROM-Bank auch nicht ausgewählt.
Syntax
u8 asset_get_bank(u8 asset_id);Parameter
asset_idRessourcenindex ab null. In der registrierten Tabelle gilt für eine gültige ID
asset_id < count.
Rückgabewert
Das 8-Bit-Feld bank oder 0, wenn die Suche scheitert. Bank null kann ebenfalls gültig sein. Nutzen Sie asset_get(), um den Erfolg unabhängig vom Wert zu erkennen.
Bedingungen und Grenzen
Registrieren Sie die Tabelle vor der ersten Suche. Die Registrierung ist ein gemeinsamer globaler Zustand und darf nicht gleichzeitig mit einer Suche geändert werden. Geprüft werden IDs und der Ausgabezeiger von asset_get, nicht jedoch Tabelle, Nutzdatenadressen oder Cartridge-Inhalt.
Jede Abfrage ruft erneut asset_get auf und kopiert einen Deskriptor. Wenn Bank, Zeiger und Länge gemeinsam benötigt werden, genügt ein Aufruf von asset_get mit anschließendem Lesen der Felder.
Die Beispiele legen den aufrufenden Code in die feste Bank 0, damit ein Wechsel der Quellbank den laufenden Code nicht ausblendet. Die Übertragungen sind synchron. Unterbrechen Sie sie nicht durch eine weitere bankwechselnde Kopie. Die Hilfsfunktion allein macht nicht die gesamte Anwendung interruptsicher.
Anwendungsbeispiel
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.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Erwartet wird ROM-Bank 2 der Nutzdaten, obwohl die Tabelle in Bank 3 liegt. Zusätzlich muss eine ungültige ID null zurückgeben.
Erwartetes Bild: Eine rote Reihe beginnt bei (16,32) und belegt 72×8 Pixel. Dreimal folgen ein 8×8-Dreieck, ein 8×8-Quadrat mit einem Pixel Rand und eine Kachel mit vier gefüllten linken Spalten. Das Dreieck wächst von einem Pixel oben links auf acht Pixel in der untersten Zeile.
Auf dem GB zeigen das blaue Dreieck und der Rahmen bei (16,64) das Ergebnis von __farmemcpy, das grüne Paar bei (16,96) das von __far_memcpy. Jedes Paar belegt 16×8 Pixel. Der CGB nutzt diese Farben, der DMG dieselben Formen in Schwarz auf Weiß.
Erwartet werden FAILED CHECKS 000 und FIRST FAILURE 00. Die Prüfung führt 300 Bilder aus und vergleicht Text, Formmasken und Farben mit den Sollwerten. Dies ist ein Emulatornachweis, kein Test auf physischer Hardware.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Liest die Länge der Ressource in Byte aus dem Deskriptor. Der Wert ist eine Metadatenangabe. Die Funktion untersucht keine Nutzdaten und rechnet die Länge nicht in Kacheln, Elemente oder Bilder um.
Syntax
u16 asset_get_len(u8 asset_id);Parameter
asset_idRessourcenindex ab null. In der registrierten Tabelle gilt für eine gültige ID
asset_id < count.
Rückgabewert
Das 16-Bit-Feld len in Byte oder 0 bei erfolgloser Suche. Auch eine leere Ressource hat Länge null. Unterscheiden Sie diese Fälle mit asset_get().
Bedingungen und Grenzen
Registrieren Sie die Tabelle vor der ersten Suche. Die Registrierung ist ein gemeinsamer globaler Zustand und darf nicht gleichzeitig mit einer Suche geändert werden. Geprüft werden IDs und der Ausgabezeiger von asset_get, nicht jedoch Tabelle, Nutzdatenadressen oder Cartridge-Inhalt.
Jede Abfrage ruft erneut asset_get auf und kopiert einen Deskriptor. Wenn Bank, Zeiger und Länge gemeinsam benötigt werden, genügt ein Aufruf von asset_get mit anschließendem Lesen der Felder.
Die Beispiele legen den aufrufenden Code in die feste Bank 0, damit ein Wechsel der Quellbank den laufenden Code nicht ausblendet. Die Übertragungen sind synchron. Unterbrechen Sie sie nicht durch eine weitere bankwechselnde Kopie. Die Hilfsfunktion allein macht nicht die gesamte Anwendung interruptsicher.
Anwendungsbeispiel
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.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Die Ressource mit neun Kacheln muss 144 Byte melden, nicht neun Kacheln. Eine leere Ressource und eine ungültige ID müssen beide null liefern.
Erwartetes Bild: Eine rote Reihe beginnt bei (16,32) und belegt 72×8 Pixel. Dreimal folgen ein 8×8-Dreieck, ein 8×8-Quadrat mit einem Pixel Rand und eine Kachel mit vier gefüllten linken Spalten. Das Dreieck wächst von einem Pixel oben links auf acht Pixel in der untersten Zeile.
Auf dem GB zeigen das blaue Dreieck und der Rahmen bei (16,64) das Ergebnis von __farmemcpy, das grüne Paar bei (16,96) das von __far_memcpy. Jedes Paar belegt 16×8 Pixel. Der CGB nutzt diese Farben, der DMG dieselben Formen in Schwarz auf Weiß.
Erwartet werden FAILED CHECKS 000 und FIRST FAILURE 00. Die Prüfung führt 300 Bilder aus und vergleicht Text, Formmasken und Farben mit den Sollwerten. Dies ist ein Emulatornachweis, kein Test auf physischer Hardware.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Liest die im Deskriptor gespeicherte 16-Bit-Adresse der Nutzdaten. Der zurückgegebene Nahzeiger enthält keine Banknummer. Verwenden Sie ihn zusammen mit asset_get_bank() und einer bankübergreifenden Kopierfunktion, um Daten aus einer anderen ROM-Bank zu lesen.
Syntax
const u8* asset_get_ptr(u8 asset_id);Parameter
asset_idRessourcenindex ab null. In der registrierten Tabelle gilt für eine gültige ID
asset_id < count.
Rückgabewert
Der gespeicherte const u8* oder ein Nullzeiger bei erfolgloser Suche. Der Nutzdatenzeiger im Deskriptor wird nicht auf null geprüft. Mit asset_get() lässt sich ein Suchfehler eindeutig erkennen.
Bedingungen und Grenzen
Registrieren Sie die Tabelle vor der ersten Suche. Die Registrierung ist ein gemeinsamer globaler Zustand und darf nicht gleichzeitig mit einer Suche geändert werden. Geprüft werden IDs und der Ausgabezeiger von asset_get, nicht jedoch Tabelle, Nutzdatenadressen oder Cartridge-Inhalt.
Jede Abfrage ruft erneut asset_get auf und kopiert einen Deskriptor. Wenn Bank, Zeiger und Länge gemeinsam benötigt werden, genügt ein Aufruf von asset_get mit anschließendem Lesen der Felder.
Die Beispiele legen den aufrufenden Code in die feste Bank 0, damit ein Wechsel der Quellbank den laufenden Code nicht ausblendet. Die Übertragungen sind synchron. Unterbrechen Sie sie nicht durch eine weitere bankwechselnde Kopie. Die Hilfsfunktion allein macht nicht die gesamte Anwendung interruptsicher.
Anwendungsbeispiel
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.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Der Zeiger muss der nach dem Linken feststehenden ROM-Adresse entsprechen, während ein Marker in Bank 1 weiterhin lesbar ist. Danach werden Zeiger und ROM-Bank 2 an die bankübergreifende Kopie übergeben.
Erwartetes Bild: Eine rote Reihe beginnt bei (16,32) und belegt 72×8 Pixel. Dreimal folgen ein 8×8-Dreieck, ein 8×8-Quadrat mit einem Pixel Rand und eine Kachel mit vier gefüllten linken Spalten. Das Dreieck wächst von einem Pixel oben links auf acht Pixel in der untersten Zeile.
Auf dem GB zeigen das blaue Dreieck und der Rahmen bei (16,64) das Ergebnis von __farmemcpy, das grüne Paar bei (16,96) das von __far_memcpy. Jedes Paar belegt 16×8 Pixel. Der CGB nutzt diese Farben, der DMG dieselben Formen in Schwarz auf Weiß.
Erwartet werden FAILED CHECKS 000 und FIRST FAILURE 00. Die Prüfung führt 300 Bilder aus und vergleicht Text, Formmasken und Farben mit den Sollwerten. Dies ist ein Emulatornachweis, kein Test auf physischer Hardware.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Sucht die Ressource und kopiert min(desc.len, max_len) Byte aus ihrer ROM-Bank in beschreibbaren Speicher. Der Typ wird nicht geprüft: Grafik-, Karten- und Musikdaten werden unverändert kopiert, ohne Dekodierung oder Dekomprimierung.
Syntax
u8 asset_load_raw(u8 asset_id, void* dst, u16 max_len);Parameter
asset_idRessourcenindex ab null. In der registrierten Tabelle gilt für eine gültige ID
asset_id < count.dstZiel in beschreibbarem Speicher mit genügend Platz für alle kopierten Byte. Abgesehen von einem Transfer mit Länge null erfolgt keine Prüfung auf Nullzeiger oder ungültige Zieladressen.
max_lenHöchstens zu kopierende Byte, 0–65535. Eine kleinere Grenze kürzt die Kopie; bei null werden keine Nutzdaten kopiert.
Rückgabewert
0, wenn die Suche scheitert, sonst 1 – auch bei gekürzter Kopie, Grenze null oder leerer Ressource. Der Rückgabewert ist keine Byteanzahl und bestätigt nicht, dass die gesamte Ressource in den Puffer passte.
Bedingungen und Grenzen
Registrieren Sie die Tabelle vor der ersten Suche. Die Registrierung ist ein gemeinsamer globaler Zustand und darf nicht gleichzeitig mit einer Suche geändert werden. Geprüft werden IDs und der Ausgabezeiger von asset_get, nicht jedoch Tabelle, Nutzdatenadressen oder Cartridge-Inhalt.
Der gesamte Quellbereich muss in der vorgesehenen ROM-Zuordnung lesbar und der gesamte Zielbereich beschreibbar sein. Die Kopie schaltet am Fensterende nicht automatisch zur nächsten Bank, behandelt Überlappungen nicht wie memmove und steuert keine sicheren VRAM-Schreibzeitpunkte. Verwenden Sie für VRAM die Grafikübertragungs-APIs.
Die Beispiele legen den aufrufenden Code in die feste Bank 0, damit ein Wechsel der Quellbank den laufenden Code nicht ausblendet. Die Übertragungen sind synchron. Unterbrechen Sie sie nicht durch eine weitere bankwechselnde Kopie. Die Hilfsfunktion allein macht nicht die gesamte Anwendung interruptsicher.
Anwendungsbeispiel
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);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Eine Grenze von sieben kopiert nur sieben Byte einer 144-Byte-Ressource und lässt das nächste Byte auf 0x55, meldet aber Erfolg. Außerdem werden vollständige Kopie, Grenze null, leere Ressource und das Kopieren von MAP-Daten geprüft.
Erwartetes Bild: Eine rote Reihe beginnt bei (16,32) und belegt 72×8 Pixel. Dreimal folgen ein 8×8-Dreieck, ein 8×8-Quadrat mit einem Pixel Rand und eine Kachel mit vier gefüllten linken Spalten. Das Dreieck wächst von einem Pixel oben links auf acht Pixel in der untersten Zeile.
Auf dem GB zeigen das blaue Dreieck und der Rahmen bei (16,64) das Ergebnis von __farmemcpy, das grüne Paar bei (16,96) das von __far_memcpy. Jedes Paar belegt 16×8 Pixel. Der CGB nutzt diese Farben, der DMG dieselben Formen in Schwarz auf Weiß.
Erwartet werden FAILED CHECKS 000 und FIRST FAILURE 00. Die Prüfung führt 300 Bilder aus und vergleicht Text, Formmasken und Farben mit den Sollwerten. Dies ist ein Emulatornachweis, kein Test auf physischer Hardware.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Sucht eine RAW- oder TILES-Ressource und überträgt alle desc.len Byte mit __vram_copy. Wählen Sie zuvor die ROM-Bank der Nutzdaten aus: Die GB-Funktion verwendet desc.ptr direkt und schaltet für den Transfer nicht auf desc.bank um.
Syntax
u8 asset_load_tiles(u8 asset_id, u16 vram_dst);Parameter
asset_idRessourcenindex ab null. In der registrierten Tabelle gilt für eine gültige ID
asset_id < count.vram_dstByteadresse im VRAM zwischen
$8000und$9FFF, keine Kachelnummer. Für Kachelmuster sind eine durch 16 teilbare Adresse und eine Länge als Vielfaches von 16 nötig. Die Bibliothek prüft diese Formatregeln nicht.
Rückgabewert
0 bei ungültiger ID oder einem anderen Typ als RAW/TILES; 1 nach einem akzeptierten Transfer, auch bei Länge null. Erfolg bestätigt weder das Kachelformat noch die korrekte Darstellung im VRAM.
Bedingungen und Grenzen
Registrieren Sie die Tabelle vor der ersten Suche. Die Registrierung ist ein gemeinsamer globaler Zustand und darf nicht gleichzeitig mit einer Suche geändert werden. Geprüft werden IDs und der Ausgabezeiger von asset_get, nicht jedoch Tabelle, Nutzdatenadressen oder Cartridge-Inhalt.
Die Beispiele legen den aufrufenden Code in die feste Bank 0, damit ein Wechsel der Quellbank den laufenden Code nicht ausblendet. Die Übertragungen sind synchron. Unterbrechen Sie sie nicht durch eine weitere bankwechselnde Kopie. Die Hilfsfunktion allein macht nicht die gesamte Anwendung interruptsicher.
Der Transfer schreibt nur Bytes. Er platziert keine Kacheln auf der Karte, weist keine Farben zu und reserviert keinen VRAM. Kachelkarte und Paletten werden separat eingerichtet. Die Beispiele übertragen bei abgeschalteter Darstellung und schalten sie erst nach dem Bildaufbau ein.
Die GB-Hilfsroutine stellt die vom Compiler gemerkte ROM-Bank wieder her. Halten Sie diesen Zustand mit __bankswitch aktuell; direkte Mapper-Schreibzugriffe aktualisieren ihn nicht. Der HRAM-Speicherplatz für die Rückkehrbank wird gemeinsam genutzt. Verschachtelte Übertragungen dürfen ihn nicht überschreiben.
Anwendungsbeispiel
__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);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel lädt neun eigene Muster mit je 8×8 Pixeln, insgesamt 144 Byte, und prüft die Ablehnung von MAP und ungültigen IDs. Auf dem FC werden damit sowohl der 128-Byte-Block als auch die verbleibenden 16 Byte geprüft.
Erwartetes Bild: Eine rote Reihe beginnt bei (16,32) und belegt 72×8 Pixel. Dreimal folgen ein 8×8-Dreieck, ein 8×8-Quadrat mit einem Pixel Rand und eine Kachel mit vier gefüllten linken Spalten. Das Dreieck wächst von einem Pixel oben links auf acht Pixel in der untersten Zeile.
Auf dem GB zeigen das blaue Dreieck und der Rahmen bei (16,64) das Ergebnis von __farmemcpy, das grüne Paar bei (16,96) das von __far_memcpy. Jedes Paar belegt 16×8 Pixel. Der CGB nutzt diese Farben, der DMG dieselben Formen in Schwarz auf Weiß.
Erwartet werden FAILED CHECKS 000 und FIRST FAILURE 00. Die Prüfung führt 300 Bilder aus und vergleicht Text, Formmasken und Farben mit den Sollwerten. Dies ist ein Emulatornachweis, kein Test auf physischer Hardware.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Registriert Banknummer, Adresse und Eintragszahl der einzigen aktiven Deskriptortabelle. Die Funktion speichert nur diese drei Werte. Sie kopiert weder die Tabelle noch Nutzdaten und reserviert keinen Speicher.
Syntax
void asset_set_table(u8 bank, const AssetDesc* table, u8 count);Parameter
bank8-Bit-Nummer der ROM-Bank mit der Deskriptortabelle, nicht mit den Nutzdaten.
tableNahzeiger auf
countaufeinanderfolgendeAssetDesc-Einträge. Solange die Tabelle registriert ist, müssen allecount * 6Byte in ihrer ROM-Bank lesbar bleiben.countAnzahl der Einträge, 0–255. Bei null ist keine ID gültig. Mit
asset_set_table(0, 0, 0)lässt sich sicher eine leere Tabelle registrieren.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Registrieren Sie die Tabelle vor der ersten Suche. Die Registrierung ist ein gemeinsamer globaler Zustand und darf nicht gleichzeitig mit einer Suche geändert werden. Geprüft werden IDs und der Ausgabezeiger von asset_get, nicht jedoch Tabelle, Nutzdatenadressen oder Cartridge-Inhalt.
Anwendungsbeispiel
asset_set_table(3,asset_descriptors,4); // Four descriptors in bank 3, payloads in bank 2.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel registriert vier Deskriptoren in Bank 3; ihre nicht leeren Nutzdaten liegen in Bank 2. Zusätzlich wird geprüft, dass die Suche in einer leeren Tabelle ohne Lesen von Adresse null scheitert.
Erwartetes Bild: Eine rote Reihe beginnt bei (16,32) und belegt 72×8 Pixel. Dreimal folgen ein 8×8-Dreieck, ein 8×8-Quadrat mit einem Pixel Rand und eine Kachel mit vier gefüllten linken Spalten. Das Dreieck wächst von einem Pixel oben links auf acht Pixel in der untersten Zeile.
Auf dem GB zeigen das blaue Dreieck und der Rahmen bei (16,64) das Ergebnis von __farmemcpy, das grüne Paar bei (16,96) das von __far_memcpy. Jedes Paar belegt 16×8 Pixel. Der CGB nutzt diese Farben, der DMG dieselben Formen in Schwarz auf Weiß.
Erwartet werden FAILED CHECKS 000 und FIRST FAILURE 00. Die Prüfung führt 300 Bilder aus und vergleicht Text, Formmasken und Farben mit den Sollwerten. Dies ist ein Emulatornachweis, kein Test auf physischer Hardware.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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 — Musik, Soundeffekte und Audiosteuerung
Bietet Direktzugriff auf vier Stimmen, bankbasierte Musik/Effekte, Stereorouting, Lautstärkeübergänge und eigene Wellen. Kanal-IDs von Musikstream und direkter API sind CH1=0, CH2=1, CH3=2, CH4=3. CH3 spielt Wellenformen, CH4 erzeugt Rauschen.
Binden Sie audio_hwregs_gb.c vor audio.c ein und rufen Sie beim Start Audio_Init auf. Audio_Update muss genau einmal pro Frame laufen, etwa mit 59,7 Hz. Stream-Lesezugriffe ändern vorübergehend die ROM-Zuordnung; rufen Sie diesen Treiber nicht erneut aus einem Interrupt auf.
Ein Effekt verbraucht pro Aktualisierung ein Paar (note,value) und endet bei note=0. value ist bei Pulseffekten NR12, bei CH3 NR32. Stellen Sie CH3-Daten 0xFF voran und halten Sie den Speicher bis zum Ende gültig. Prioritäten konkurrieren innerhalb eines Slots; auch gleiche Priorität kann den bisherigen Effekt ersetzen.
Audio_CancelMasterVolumeFade
Stoppt weitere Übergangsschritte und erhält die aktuellen Pegel und Register.
Syntax
void Audio_CancelMasterVolumeFade();Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
A4 wandert nach links, rechts und in die Mitte. Dort sinkt der Pegel von 7 auf 1, steigt dann auf 4 und bleibt so. Pegel 0 ist noch leise hörbar; erst der Kanalstopp erzeugt Stille. Routingänderungen können einen abklingenden Filtertransienten hinterlassen.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Setzt CH1-Sweep, Tastgrad, Hüllkurve und Tonhöhe und löst den Puls aus.
Syntax
void __stackcall Audio_Ch1NoteOn(u8 note, u8 vol_env, u8 duty2);Parameter
noteTonhöhentabellenindex 0..67. Hinweise zur Bereichsrückführung und zum Oktavunterschied von CH3 stehen in den Anmerkungen.
vol_envNR12-/NR22-/NR42-Codierung: oberes Halbbyte Anfangslautstärke, Bit 3 steigende Hüllkurve, untere drei Bits Hüllkurvenperiode. 0xC0 hält Lautstärke 12.
duty2Puls-Tastgrad: 0=12,5 %, 1=25 %, 3=75 %; alle anderen Werte wählen 50 %.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
note indiziert eine Tonhöhentabelle von 0 bis 67: 0 ist C2, 33 ist A4. Werte über 67 werden auf 67 begrenzt; 60..67 verwenden die Frequenzen von 48..55. Bei gleichem Index klingt CH3 eine Oktave tiefer als ein Pulskanal. Note-on-Funktionen lösen die Hardware direkt aus, ohne Aktivierungs- oder Pauseschalter zu prüfen.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Nach etwa einer halben Sekunde Stille folgen CH1 A4, CH2 A4, CH3 A3 und Rauschen. Jede Stimme dauert 30 Frames, dazwischen liegen 15 Frames Pause. SEQUENCE COMPLETE zeigt den Programmabschluss; beurteilen Sie den Klang anhand der Aufnahme.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Setzt CH2-Tastgrad, Hüllkurve und Tonhöhe und löst den Puls aus.
Syntax
void __stackcall Audio_Ch2NoteOn(u8 note, u8 vol_env, u8 duty2);Parameter
noteTonhöhentabellenindex 0..67. Hinweise zur Bereichsrückführung und zum Oktavunterschied von CH3 stehen in den Anmerkungen.
vol_envNR12-/NR22-/NR42-Codierung: oberes Halbbyte Anfangslautstärke, Bit 3 steigende Hüllkurve, untere drei Bits Hüllkurvenperiode. 0xC0 hält Lautstärke 12.
duty2Puls-Tastgrad: 0=12,5 %, 1=25 %, 3=75 %; alle anderen Werte wählen 50 %.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
note indiziert eine Tonhöhentabelle von 0 bis 67: 0 ist C2, 33 ist A4. Werte über 67 werden auf 67 begrenzt; 60..67 verwenden die Frequenzen von 48..55. Bei gleichem Index klingt CH3 eine Oktave tiefer als ein Pulskanal. Note-on-Funktionen lösen die Hardware direkt aus, ohne Aktivierungs- oder Pauseschalter zu prüfen.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Nach etwa einer halben Sekunde Stille folgen CH1 A4, CH2 A4, CH3 A3 und Rauschen. Jede Stimme dauert 30 Frames, dazwischen liegen 15 Frames Pause. SEQUENCE COMPLETE zeigt den Programmabschluss; beurteilen Sie den Klang anhand der Aufnahme.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Triggert die geladene CH3-Welle mit angeforderter Tonhöhe und NR32-Pegel.
Syntax
void __stackcall Audio_Ch3NoteOn(u8 note, u8 level);Parameter
noteTonhöhentabellenindex 0..67. Hinweise zur Bereichsrückführung und zum Oktavunterschied von CH3 stehen in den Anmerkungen.
levelNR32-Codierung: 0x00=stumm, 0x20=100 %, 0x40=50 %, 0x60=25 %.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
note indiziert eine Tonhöhentabelle von 0 bis 67: 0 ist C2, 33 ist A4. Werte über 67 werden auf 67 begrenzt; 60..67 verwenden die Frequenzen von 48..55. Bei gleichem Index klingt CH3 eine Oktave tiefer als ein Pulskanal. Note-on-Funktionen lösen die Hardware direkt aus, ohne Aktivierungs- oder Pauseschalter zu prüfen.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Nach etwa einer halben Sekunde Stille folgen CH1 A4, CH2 A4, CH3 A3 und Rauschen. Jede Stimme dauert 30 Frames, dazwischen liegen 15 Frames Pause. SEQUENCE COMPLETE zeigt den Programmabschluss; beurteilen Sie den Klang anhand der Aufnahme.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Speichert die Rauschparameter, setzt Hüllkurven-/Polynomzählerregister und triggert CH4.
Syntax
void __stackcall Audio_Ch4NoteOn(u8 param, u8 vol_env);Parameter
paramRohes NR43: Bits 7..4 Taktschiebung, Bit 3 kurzes LFSR, Bits 2..0 Teilercode.
vol_envNR12-/NR22-/NR42-Codierung: oberes Halbbyte Anfangslautstärke, Bit 3 steigende Hüllkurve, untere drei Bits Hüllkurvenperiode. 0xC0 hält Lautstärke 12.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
Automatischer Längenstopp ist nicht aktiviert. Beenden Sie den Ton über die Hüllkurve oder einen ausdrücklichen Stopp.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Nach etwa einer halben Sekunde Stille folgen CH1 A4, CH2 A4, CH3 A3 und Rauschen. Jede Stimme dauert 30 Frames, dazwischen liegen 15 Frames Pause. SEQUENCE COMPLETE zeigt den Programmabschluss; beurteilen Sie den Klang anhand der Aufnahme.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Bewegt jeden Ausgabepegel im angeforderten Intervall um einen Schritt zum Ziel.
Syntax
void __stackcall Audio_FadeToMasterVolume(u8 left, u8 right, u8 step_frames);Parameter
leftLinker Hauptpegel 0..7; größere Werte werden auf 7 begrenzt. Null ist keine vollständige Stille.
rightRechter Hauptpegel 0..7; größere Werte werden auf 7 begrenzt.
step_framesAnzahl Audio_Update-Aufrufe pro Pegelschritt. Null wendet den Zielwert sofort an.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
Binden Sie audio_hwregs_gb.c vor audio.c ein und rufen Sie beim Start Audio_Init auf. Audio_Update muss genau einmal pro Frame laufen, etwa mit 59,7 Hz. Stream-Lesezugriffe ändern vorübergehend die ROM-Zuordnung; rufen Sie diesen Treiber nicht erneut aus einem Interrupt auf.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
A4 wandert nach links, rechts und in die Mitte. Dort sinkt der Pegel von 7 auf 1, steigt dann auf 4 und bleibt so. Pegel 0 ist noch leise hörbar; erst der Kanalstopp erzeugt Stille. Routingänderungen können einen abklingenden Filtertransienten hinterlassen.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Aktiviert die APU, initialisiert Musik-, Effekt-, Pause-, Misch- und Wellenzustand und lässt alle Kanäle stumm.
Syntax
void Audio_Init();Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
Binden Sie audio_hwregs_gb.c vor audio.c ein und rufen Sie beim Start Audio_Init auf. Audio_Update muss genau einmal pro Frame laufen, etwa mit 59,7 Hz. Stream-Lesezugriffe ändern vorübergehend die ROM-Zuordnung; rufen Sie diesen Treiber nicht erneut aus einem Interrupt auf.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Nach etwa einer halben Sekunde Stille folgen CH1 A4, CH2 A4, CH3 A3 und Rauschen. Jede Stimme dauert 30 Frames, dazwischen liegen 15 Frames Pause. SEQUENCE COMPLETE zeigt den Programmabschluss; beurteilen Sie den Klang anhand der Aufnahme.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Kopiert sechzehn Bytes in Benutzerwellen-Cache und CH3-Wellen-RAM.
Syntax
void __stackcall Audio_LoadCustomWave(const u8 *wave16);Parameter
wave16Sechzehn lesbare Bytes; oberes und unteres Halbbyte codieren aufeinanderfolgende Abtastwerte. NULL wird ignoriert.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
Nach dem Kopieren darf der Aufrufer die Quelle wiederverwenden. Die Funktion deaktiviert den DAC zum Schreiben; der Aufrufer triggert die Note erneut.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Zu hören sind die Dreiecksvorgabe, eine eigene Pulswelle und dieselbe aus dem Cache nachgeladene Pulswelle. Jede dauert 45 Frames mit 15 Frames Pause. Alle drei liegen bei etwa 220 Hz; nur die erste klingt anders.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Installiert eine Vorgabe- oder zwischengespeicherte Benutzerwelle im CH3-Wellen-RAM.
Syntax
void __stackcall Audio_LoadWave(u8 wave_id);Parameter
wave_idAUDIO_WAVE_*-ID 0..7; 7 wählt die zwischengespeicherte eigene Welle. Werte über 7 bewirken nichts.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
Laden startet keine Note und ändert Audio_Ch3Wave nicht. Die Dreiecksvorgabe setzt auch den benutzerdefinierten Cache auf Dreieck zurück. Rufen Sie Audio_Ch3NoteOn zum Auslösen auf.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Zu hören sind die Dreiecksvorgabe, eine eigene Pulswelle und dieselbe aus dem Cache nachgeladene Pulswelle. Jede dauert 45 Frames mit 15 Frames Pause. Alle drei liegen bei etwa 220 Hz; nur die erste klingt anders.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Bereitet das Lied in der angegebenen Bank von Anfang an vor und setzt Instrumente, Panorama und delay zurück.
Syntax
void __stackcall Audio_PlayMusic(u8 bank, u8 *song);Parameter
bankROM-Bank des Streams; muss seiner Ablage entsprechen.
songStartadresse des Lieds. Der Treiber leiht das Array aus; es muss während der gesamten Wiedergabe lesbar bleiben.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
Binden Sie audio_hwregs_gb.c vor audio.c ein und rufen Sie beim Start Audio_Init auf. Audio_Update muss genau einmal pro Frame laufen, etwa mit 59,7 Hz. Stream-Lesezugriffe ändern vorübergehend die ROM-Zuordnung; rufen Sie diesen Treiber nicht erneut aus einem Interrupt auf.
Das nächste Audio_Update liest die Daten. NULL wird nicht geprüft. Bestehende Effekte bleiben aktiv.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Es folgen eine Note, Pausenstille, Fortsetzung, eine bei deaktivierter Musik gehaltene Note, ausdrückliche Kanalstille, die nächste Note nach Aktivierung und schließlich Stopp. RAM-Prüfungen zeigen zudem: 30 Pausenupdates erhalten delay, während die bloße Musiksperre es bis 30 fortschreiten lässt.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Erfasst die aktuelle ROM-Bank und fordert einen Effekt mit übernommenem Basispanorama an.
Syntax
void __stackcall Audio_PlaySFX(u8 *sfx, u8 priority);Parameter
sfxBeginn des Effekt-Bytestroms. Hinweise zu Puls- und CH3-Formaten stehen in den Anmerkungen.
priorityPriorität 0..255. Größere Werte gewinnen; gleiche Werte können den aktuellen Effekt ebenfalls ersetzen.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
Ein Effekt verbraucht pro Aktualisierung ein Paar (note,value) und endet bei note=0. value ist bei Pulseffekten NR12, bei CH3 NR32. Stellen Sie CH3-Daten 0xFF voran und halten Sie den Speicher bis zum Ende gültig. Prioritäten konkurrieren innerhalb eines Slots; auch gleiche Priorität kann den bisherigen Effekt ersetzen.
In der normalen Konfiguration schaltet das Freigeben eines Effekts CH3 aus. Bei gestoppter Musik wird CH1 stumm, bei laufender Musik aber keine frühere Musiknote automatisch wiederholt. Mit AUDIO_VBLANK_SFX_RESTORE fordert die Freigabe eine Wiederherstellung durch die ISR an.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Daten aus Bank 2 spielen einen kurzen ansteigenden Puls links, einen Welleneffekt rechts und einen mittigen Puls. Spätere Beispiele stoppen einen rechten Puls frühzeitig, deaktivieren einen Effekt und aktivieren die Wiedergabe erneut. Eine Anforderung mit Priorität 4 kann Priorität 5 nicht ersetzen.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Bestimmt den Effekttyp in der ausdrücklich angegebenen Quellbank und fordert Wiedergabe mit übernommenem Basispanorama an.
Syntax
void __stackcall Audio_PlaySFXBanked(u8 bank, u8 *sfx, u8 priority);Parameter
bankROM-Bank des Streams; muss seiner Ablage entsprechen.
sfxBeginn des Effekt-Bytestroms. Hinweise zu Puls- und CH3-Formaten stehen in den Anmerkungen.
priorityPriorität 0..255. Größere Werte gewinnen; gleiche Werte können den aktuellen Effekt ebenfalls ersetzen.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
Ein Effekt verbraucht pro Aktualisierung ein Paar (note,value) und endet bei note=0. value ist bei Pulseffekten NR12, bei CH3 NR32. Stellen Sie CH3-Daten 0xFF voran und halten Sie den Speicher bis zum Ende gültig. Prioritäten konkurrieren innerhalb eines Slots; auch gleiche Priorität kann den bisherigen Effekt ersetzen.
In der normalen Konfiguration schaltet das Freigeben eines Effekts CH3 aus. Bei gestoppter Musik wird CH1 stumm, bei laufender Musik aber keine frühere Musiknote automatisch wiederholt. Mit AUDIO_VBLANK_SFX_RESTORE fordert die Freigabe eine Wiederherstellung durch die ISR an.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Daten aus Bank 2 spielen einen kurzen ansteigenden Puls links, einen Welleneffekt rechts und einen mittigen Puls. Spätere Beispiele stoppen einen rechten Puls frühzeitig, deaktivieren einen Effekt und aktivieren die Wiedergabe erneut. Eine Anforderung mit Priorität 4 kann Priorität 5 nicht ersetzen.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Erfasst die aktuelle ROM-Bank und fordert einen Effekt mit eigenem Panorama an.
Syntax
void __stackcall Audio_PlaySFXPanned(u8 *sfx, u8 priority, u8 pan);Parameter
sfxBeginn des Effekt-Bytestroms. Hinweise zu Puls- und CH3-Formaten stehen in den Anmerkungen.
priorityPriorität 0..255. Größere Werte gewinnen; gleiche Werte können den aktuellen Effekt ebenfalls ersetzen.
pan0=Mitte, 1=links, 2=rechts, 3=stumm. Effekt-APIs übernehmen bei Werten über 3 einschließlich 0xFF das Basispanorama.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
Ein Effekt verbraucht pro Aktualisierung ein Paar (note,value) und endet bei note=0. value ist bei Pulseffekten NR12, bei CH3 NR32. Stellen Sie CH3-Daten 0xFF voran und halten Sie den Speicher bis zum Ende gültig. Prioritäten konkurrieren innerhalb eines Slots; auch gleiche Priorität kann den bisherigen Effekt ersetzen.
In der normalen Konfiguration schaltet das Freigeben eines Effekts CH3 aus. Bei gestoppter Musik wird CH1 stumm, bei laufender Musik aber keine frühere Musiknote automatisch wiederholt. Mit AUDIO_VBLANK_SFX_RESTORE fordert die Freigabe eine Wiederherstellung durch die ISR an.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Daten aus Bank 2 spielen einen kurzen ansteigenden Puls links, einen Welleneffekt rechts und einen mittigen Puls. Spätere Beispiele stoppen einen rechten Puls frühzeitig, deaktivieren einen Effekt und aktivieren die Wiedergabe erneut. Eine Anforderung mit Priorität 4 kann Priorität 5 nicht ersetzen.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Belegt einen Puls- oder CH3-Effektslot mit ausdrücklicher Bank-, Prioritäts- und Panoramaangabe.
Syntax
void __stackcall Audio_PlaySFXPannedBanked(u8 bank, u8 *sfx, u8 priority, u8 pan);Parameter
bankROM-Bank des Streams; muss seiner Ablage entsprechen.
sfxBeginn des Effekt-Bytestroms. Hinweise zu Puls- und CH3-Formaten stehen in den Anmerkungen.
priorityPriorität 0..255. Größere Werte gewinnen; gleiche Werte können den aktuellen Effekt ebenfalls ersetzen.
pan0=Mitte, 1=links, 2=rechts, 3=stumm. Effekt-APIs übernehmen bei Werten über 3 einschließlich 0xFF das Basispanorama.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
Ein Effekt verbraucht pro Aktualisierung ein Paar (note,value) und endet bei note=0. value ist bei Pulseffekten NR12, bei CH3 NR32. Stellen Sie CH3-Daten 0xFF voran und halten Sie den Speicher bis zum Ende gültig. Prioritäten konkurrieren innerhalb eines Slots; auch gleiche Priorität kann den bisherigen Effekt ersetzen.
In der normalen Konfiguration schaltet das Freigeben eines Effekts CH3 aus. Bei gestoppter Musik wird CH1 stumm, bei laufender Musik aber keine frühere Musiknote automatisch wiederholt. Mit AUDIO_VBLANK_SFX_RESTORE fordert die Freigabe eine Wiederherstellung durch die ISR an.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Daten aus Bank 2 spielen einen kurzen ansteigenden Puls links, einen Welleneffekt rechts und einen mittigen Puls. Spätere Beispiele stoppen einen rechten Puls frühzeitig, deaktivieren einen Effekt und aktivieren die Wiedergabe erneut. Eine Anforderung mit Priorität 4 kann Priorität 5 nicht ersetzen.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Speichert den Tastgradindex für die nächste CH1-Note.
Syntax
void __stackcall Audio_SetCh1Duty(u8 duty);Parameter
dutyPuls-Tastgradindex; gespeichert werden die unteren zwei Bits. 0=12,5 %, 1=25 %, 2=50 %, 3=75 %.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
Dieser Aufruf allein ändert keine aktiven Audioregister. Übergeben Sie den gespeicherten Wert an Note-on oder verwenden Sie den zugehörigen Stream zum Anwenden.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Nach etwa einer halben Sekunde Stille folgen CH1 A4, CH2 A4, CH3 A3 und Rauschen. Jede Stimme dauert 30 Frames, dazwischen liegen 15 Frames Pause. SEQUENCE COMPLETE zeigt den Programmabschluss; beurteilen Sie den Klang anhand der Aufnahme.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Speichert den Tastgradindex für die nächste CH2-Note.
Syntax
void __stackcall Audio_SetCh2Duty(u8 duty);Parameter
dutyPuls-Tastgradindex; gespeichert werden die unteren zwei Bits. 0=12,5 %, 1=25 %, 2=50 %, 3=75 %.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
Dieser Aufruf allein ändert keine aktiven Audioregister. Übergeben Sie den gespeicherten Wert an Note-on oder verwenden Sie den zugehörigen Stream zum Anwenden.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Nach etwa einer halben Sekunde Stille folgen CH1 A4, CH2 A4, CH3 A3 und Rauschen. Jede Stimme dauert 30 Frames, dazwischen liegen 15 Frames Pause. SEQUENCE COMPLETE zeigt den Programmabschluss; beurteilen Sie den Klang anhand der Aufnahme.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Speichert den NR32-Ausgabepegel für die nächste CH3-Note.
Syntax
void __stackcall Audio_SetCh3Level(u8 level);Parameter
levelNR32-Codierung: 0x00=stumm, 0x20=100 %, 0x40=50 %, 0x60=25 %.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
Dieser Aufruf allein ändert keine aktiven Audioregister. Übergeben Sie den gespeicherten Wert an Note-on oder verwenden Sie den zugehörigen Stream zum Anwenden.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Nach etwa einer halben Sekunde Stille folgen CH1 A4, CH2 A4, CH3 A3 und Rauschen. Jede Stimme dauert 30 Frames, dazwischen liegen 15 Frames Pause. SEQUENCE COMPLETE zeigt den Programmabschluss; beurteilen Sie den Klang anhand der Aufnahme.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Speichert die NR43-Rauschparameter für die nächste CH4-Note.
Syntax
void __stackcall Audio_SetCh4Param(u8 param);Parameter
paramRohes NR43: Bits 7..4 Taktschiebung, Bit 3 kurzes LFSR, Bits 2..0 Teilercode.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
Dieser Aufruf allein ändert keine aktiven Audioregister. Übergeben Sie den gespeicherten Wert an Note-on oder verwenden Sie den zugehörigen Stream zum Anwenden.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Nach etwa einer halben Sekunde Stille folgen CH1 A4, CH2 A4, CH3 A3 und Rauschen. Jede Stimme dauert 30 Frames, dazwischen liegen 15 Frames Pause. SEQUENCE COMPLETE zeigt den Programmabschluss; beurteilen Sie den Klang anhand der Aufnahme.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Begrenzt beide Hauptpegel auf 0..7, schreibt sie sofort und bricht einen aktiven Lautstärkeübergang ab.
Syntax
void __stackcall Audio_SetMasterVolume(u8 left, u8 right);Parameter
leftLinker Hauptpegel 0..7; größere Werte werden auf 7 begrenzt. Null ist keine vollständige Stille.
rightRechter Hauptpegel 0..7; größere Werte werden auf 7 begrenzt.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
A4 wandert nach links, rechts und in die Mitte. Dort sinkt der Pegel von 7 auf 1, steigt dann auf 4 und bleibt so. Pegel 0 ist noch leise hörbar; erst der Kanalstopp erzeugt Stille. Routingänderungen können einen abklingenden Filtertransienten hinterlassen.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Steuert, ob der normale Musikdecoder neue Noten schreibt.
Syntax
void __stackcall Audio_SetMusicEnabled(u8 on);Parameter
onNull deaktiviert, ungleich null aktiviert. Unterscheiden Sie anhand der Funktionsbeschreibung zwischen Stummschaltung und Sperren der Aktualisierung.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
Deaktivieren lässt den Stream und Instrument-/Panoramasteuerungen weiterlaufen. Die aktuelle Note wird nicht stumm. Zum Pausieren verwenden Sie Audio_SetPaused.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Es folgen eine Note, Pausenstille, Fortsetzung, eine bei deaktivierter Musik gehaltene Note, ausdrückliche Kanalstille, die nächste Note nach Aktivierung und schließlich Stopp. RAM-Prüfungen zeigen zudem: 30 Pausenupdates erhalten delay, während die bloße Musiksperre es bis 30 fortschreiten lässt.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Ändert das Basispanorama einer physischen Stimme und wendet aktive Effektüberschreibungen erneut an.
Syntax
void __stackcall Audio_SetPan(u8 ch, u8 pan);Parameter
chKanal-ID: 0=CH1, 1=CH2, 2=CH3, 3=CH4. Direkte APIs und Musikstreams verwenden dieselben IDs.
pan0=Mitte, 1=links, 2=rechts, 3=stumm. Effekt-APIs übernehmen bei Werten über 3 einschließlich 0xFF das Basispanorama.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
Ein unbekannter Kanal wählt CH4. pan außerhalb 0..3 bedeutet hier stumm, nicht die Übernahmeeinstellung der Effekt-API.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
A4 wandert nach links, rechts und in die Mitte. Dort sinkt der Pegel von 7 auf 1, steigt dann auf 4 und bleibt so. Pegel 0 ist noch leise hörbar; erst der Kanalstopp erzeugt Stille. Routingänderungen können einen abklingenden Filtertransienten hinterlassen.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Entpackt vier Basispanoramen aus einem Byte und aktualisiert NR51 einmal.
Syntax
void __stackcall Audio_SetPanPacked(u8 packed);Parameter
packedZwei Bits pro physischem Kanal: CH1 Bits 0..1, CH2 2..3, CH3 4..5, CH4 6..7. Jedes Feld verwendet die Panoramawerte.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
A4 wandert nach links, rechts und in die Mitte. Dort sinkt der Pegel von 7 auf 1, steigt dann auf 4 und bleibt so. Pegel 0 ist noch leise hörbar; erst der Kanalstopp erzeugt Stille. Routingänderungen können einen abklingenden Filtertransienten hinterlassen.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Schaltet bei Pause stumm und erhält Musik-/Effektpositionen. Beim Fortsetzen werden geeignete CH1-, CH2- und CH4-Noten erneut ausgelöst.
Syntax
void __stackcall Audio_SetPaused(u8 on);Parameter
onNull deaktiviert, ungleich null aktiviert. Unterscheiden Sie anhand der Funktionsbeschreibung zwischen Stummschaltung und Sperren der Aktualisierung.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
Binden Sie audio_hwregs_gb.c vor audio.c ein und rufen Sie beim Start Audio_Init auf. Audio_Update muss genau einmal pro Frame laufen, etwa mit 59,7 Hz. Stream-Lesezugriffe ändern vorübergehend die ROM-Zuordnung; rufen Sie diesen Treiber nicht erneut aus einem Interrupt auf.
Diese Routine triggert CH3 nicht erneut. Effekte laufen bei späterer Aktualisierung weiter. Direkte Note-on-Aufrufe können auch während der Pause klingen.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Es folgen eine Note, Pausenstille, Fortsetzung, eine bei deaktivierter Musik gehaltene Note, ausdrückliche Kanalstille, die nächste Note nach Aktivierung und schließlich Stopp. RAM-Prüfungen zeigen zudem: 30 Pausenupdates erhalten delay, während die bloße Musiksperre es bis 30 fortschreiten lässt.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Gibt Effektnotenschreibzugriffe frei oder sperrt sie; Deaktivieren gibt auch die Effektslots frei.
Syntax
void __stackcall Audio_SetSfxEnabled(u8 on);Parameter
onNull deaktiviert, ungleich null aktiviert. Unterscheiden Sie anhand der Funktionsbeschreibung zwischen Stummschaltung und Sperren der Aktualisierung.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
In der normalen Konfiguration schaltet das Freigeben eines Effekts CH3 aus. Bei gestoppter Musik wird CH1 stumm, bei laufender Musik aber keine frühere Musiknote automatisch wiederholt. Mit AUDIO_VBLANK_SFX_RESTORE fordert die Freigabe eine Wiederherstellung durch die ISR an.
Ein Start bei deaktivierten Effekten kann einen Stream registrieren, doch Updates unterdrücken seine Notenschreibzugriffe. Aktivieren Sie Effekte vor einer hörbaren Wiedergabeanforderung.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Daten aus Bank 2 spielen einen kurzen ansteigenden Puls links, einen Welleneffekt rechts und einen mittigen Puls. Spätere Beispiele stoppen einen rechten Puls frühzeitig, deaktivieren einen Effekt und aktivieren die Wiedergabe erneut. Eine Anforderung mit Priorität 4 kann Priorität 5 nicht ersetzen.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Stoppt eine physische Stimme und entfernt ihre Musiknote aus der Fortsetzungsmaske.
Syntax
void __stackcall Audio_StopChannel(u8 ch);Parameter
chKanal-ID: 0=CH1, 1=CH2, 2=CH3, 3=CH4. Direkte APIs und Musikstreams verwenden dieselben IDs.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
CH1/CH3 löschen auch ihren Effektslot. Werte außerhalb 0..3 bewirken nichts. Von VBlank gespeicherte Noten werden separat verwaltet.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Nach etwa einer halben Sekunde Stille folgen CH1 A4, CH2 A4, CH3 A3 und Rauschen. Jede Stimme dauert 30 Frames, dazwischen liegen 15 Frames Pause. SEQUENCE COMPLETE zeigt den Programmabschluss; beurteilen Sie den Klang anhand der Aufnahme.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Löscht Liedwiedergabe und Fortsetzungsmaske und schaltet sofort alle vier Stimmen stumm.
Syntax
void Audio_StopMusic();Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
Effektzeiger bleiben erhalten; ein späteres Audio_Update kann daher einen Effekt erklingen lassen. Rufen Sie zum vollständigen Stoppen auch Audio_StopSfx auf.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Es folgen eine Note, Pausenstille, Fortsetzung, eine bei deaktivierter Musik gehaltene Note, ausdrückliche Kanalstille, die nächste Note nach Aktivierung und schließlich Stopp. RAM-Prüfungen zeigen zudem: 30 Pausenupdates erhalten delay, während die bloße Musiksperre es bis 30 fortschreiten lässt.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Löscht beide Effektstreams und deren Panoramaüberschreibungen und gibt die ausgeliehenen Kanäle frei.
Syntax
void Audio_StopSfx();Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
Ein Effekt verbraucht pro Aktualisierung ein Paar (note,value) und endet bei note=0. value ist bei Pulseffekten NR12, bei CH3 NR32. Stellen Sie CH3-Daten 0xFF voran und halten Sie den Speicher bis zum Ende gültig. Prioritäten konkurrieren innerhalb eines Slots; auch gleiche Priorität kann den bisherigen Effekt ersetzen.
In der normalen Konfiguration schaltet das Freigeben eines Effekts CH3 aus. Bei gestoppter Musik wird CH1 stumm, bei laufender Musik aber keine frühere Musiknote automatisch wiederholt. Mit AUDIO_VBLANK_SFX_RESTORE fordert die Freigabe eine Wiederherstellung durch die ISR an.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Daten aus Bank 2 spielen einen kurzen ansteigenden Puls links, einen Welleneffekt rechts und einen mittigen Puls. Spätere Beispiele stoppen einen rechten Puls frühzeitig, deaktivieren einen Effekt und aktivieren die Wiedergabe erneut. Eine Anforderung mit Priorität 4 kann Priorität 5 nicht ersetzen.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Führt einen Lautstärkeübergangsschritt aus; außerhalb der Pause werden danach Effekte und anschließend Musik verarbeitet.
Syntax
void Audio_Update();Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
Binden Sie audio_hwregs_gb.c vor audio.c ein und rufen Sie beim Start Audio_Init auf. Audio_Update muss genau einmal pro Frame laufen, etwa mit 59,7 Hz. Stream-Lesezugriffe ändern vorübergehend die ROM-Zuordnung; rufen Sie diesen Treiber nicht erneut aus einem Interrupt auf.
Lautstärkeübergänge laufen während der Pause weiter. Auf das Lesen von WAIT n folgen n Warteaufrufe; der nächste Befehl erfolgt daher nach n+1 Aktualisierungen.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Es folgen eine Note, Pausenstille, Fortsetzung, eine bei deaktivierter Musik gehaltene Note, ausdrückliche Kanalstille, die nächste Note nach Aktivierung und schließlich Stopp. RAM-Prüfungen zeigen zudem: 30 Pausenupdates erhalten delay, während die bloße Musiksperre es bis 30 fortschreiten lässt.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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 — Musikwiedergabe im VBlank-Interrupt
Verarbeitet Musik im VBlank, koordiniert Effektbelegung und bietet einen Frame-Hook. Schalten Sie dasselbe Lied nicht zusätzlich über den normalen Musikdecoder weiter.
audio_vblank.c implementiert __kq_vblank_vector; installieren Sie keinen konkurrierenden VBlank-Vektor. Das Beispiel definiert Audio_NoiseEffectActive, schließt den normalen Musikdecoder aus und nutzt Audio_Update nur für Effekte und Lautstärkeübergänge. Sperren Sie Interrupts beim Ändern von Liedzeigern oder gemeinsamem Zustand.
Halten Sie direkt gelesene Lieddaten in festem ROM oder einem für die ISR stets sichtbaren Bereich. Ein Datensatz hat fünf Bytes: delay, CH1, CH2, CH3, CH4. In Notenfeldern hält 0xFF die aktuelle Stimme, 0xFD stoppt sie. Im delay-Feld beendet 0xFF die Wiedergabe, 0xFE wiederholt sie. Dies ist das Datensatzlayout, nicht die Kanal-ID-Nummerierung. WRAM-Warteschlangenwiedergabe ist ein separater Modus; übergeben Sie vollständige Fünfbyte-Datensätze mit AudioVBlank_QueueRefill.
AudioVBlank_DisableIrq
Löscht nur das VBlank-Bit in IE; andere Interruptquellen und Ton bleiben unverändert.
Syntax
void AudioVBlank_DisableIrq();Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
audio_vblank.c implementiert __kq_vblank_vector; installieren Sie keinen konkurrierenden VBlank-Vektor. Das Beispiel definiert Audio_NoiseEffectActive, schließt den normalen Musikdecoder aus und nutzt Audio_Update nur für Effekte und Lautstärkeübergänge. Sperren Sie Interrupts beim Ändern von Liedzeigern oder gemeinsamem Zustand.
Halten Sie direkt gelesene Lieddaten in festem ROM oder einem für die ISR stets sichtbaren Bereich. Ein Datensatz hat fünf Bytes: delay, CH1, CH2, CH3, CH4. In Notenfeldern hält 0xFF die aktuelle Stimme, 0xFD stoppt sie. Im delay-Feld beendet 0xFF die Wiedergabe, 0xFE wiederholt sie. Dies ist das Datensatzlayout, nicht die Kanal-ID-Nummerierung. WRAM-Warteschlangenwiedergabe ist ein separater Modus; übergeben Sie vollständige Fünfbyte-Datensätze mit AudioVBlank_QueueRefill.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Die ISR spielt ein Lied mit zwei Noten. Vergleichen Sie die Musiksperre, die den aktuellen Ton erhält, Stop, das ihn stummschaltet, und die IRQ-Sperre nach Neustart, die ihn ebenfalls erhält. RAM-Prüfungen bestätigen, dass der Hook bei deaktivierter Musik läuft und bei deaktiviertem IRQ stoppt.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Setzt das VBlank-Bit in IE und führt EI aus, um CPU-Interrupts global zu aktivieren.
Syntax
void AudioVBlank_EnableIrq();Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
audio_vblank.c implementiert __kq_vblank_vector; installieren Sie keinen konkurrierenden VBlank-Vektor. Das Beispiel definiert Audio_NoiseEffectActive, schließt den normalen Musikdecoder aus und nutzt Audio_Update nur für Effekte und Lautstärkeübergänge. Sperren Sie Interrupts beim Ändern von Liedzeigern oder gemeinsamem Zustand.
Halten Sie direkt gelesene Lieddaten in festem ROM oder einem für die ISR stets sichtbaren Bereich. Ein Datensatz hat fünf Bytes: delay, CH1, CH2, CH3, CH4. In Notenfeldern hält 0xFF die aktuelle Stimme, 0xFD stoppt sie. Im delay-Feld beendet 0xFF die Wiedergabe, 0xFE wiederholt sie. Dies ist das Datensatzlayout, nicht die Kanal-ID-Nummerierung. WRAM-Warteschlangenwiedergabe ist ein separater Modus; übergeben Sie vollständige Fünfbyte-Datensätze mit AudioVBlank_QueueRefill.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Die ISR spielt ein Lied mit zwei Noten. Vergleichen Sie die Musiksperre, die den aktuellen Ton erhält, Stop, das ihn stummschaltet, und die IRQ-Sperre nach Neustart, die ihn ebenfalls erhält. RAM-Prüfungen bestätigen, dass der Hook bei deaktivierter Musik läuft und bei deaktiviertem IRQ stoppt.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Initialisiert VBlank-Musikzustand, Warteschlange, Instrumente und Hook. Initialisiert weder die APU noch sperrt es Interrupts.
Syntax
void AudioVBlank_Init();Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
audio_vblank.c implementiert __kq_vblank_vector; installieren Sie keinen konkurrierenden VBlank-Vektor. Das Beispiel definiert Audio_NoiseEffectActive, schließt den normalen Musikdecoder aus und nutzt Audio_Update nur für Effekte und Lautstärkeübergänge. Sperren Sie Interrupts beim Ändern von Liedzeigern oder gemeinsamem Zustand.
Halten Sie direkt gelesene Lieddaten in festem ROM oder einem für die ISR stets sichtbaren Bereich. Ein Datensatz hat fünf Bytes: delay, CH1, CH2, CH3, CH4. In Notenfeldern hält 0xFF die aktuelle Stimme, 0xFD stoppt sie. Im delay-Feld beendet 0xFF die Wiedergabe, 0xFE wiederholt sie. Dies ist das Datensatzlayout, nicht die Kanal-ID-Nummerierung. WRAM-Warteschlangenwiedergabe ist ein separater Modus; übergeben Sie vollständige Fünfbyte-Datensätze mit AudioVBlank_QueueRefill.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Die ISR spielt ein Lied mit zwei Noten. Vergleichen Sie die Musiksperre, die den aktuellen Ton erhält, Stop, das ihn stummschaltet, und die IRQ-Sperre nach Neustart, die ihn ebenfalls erhält. RAM-Prüfungen bestätigen, dass der Hook bei deaktivierter Musik läuft und bei deaktiviertem IRQ stoppt.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Startet das gewählte Lied von vorn und verlässt den Warteschlangenmodus. Ein NULL-Lied stoppt die Wiedergabe.
Syntax
void AudioVBlank_Play();Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
audio_vblank.c implementiert __kq_vblank_vector; installieren Sie keinen konkurrierenden VBlank-Vektor. Das Beispiel definiert Audio_NoiseEffectActive, schließt den normalen Musikdecoder aus und nutzt Audio_Update nur für Effekte und Lautstärkeübergänge. Sperren Sie Interrupts beim Ändern von Liedzeigern oder gemeinsamem Zustand.
Halten Sie direkt gelesene Lieddaten in festem ROM oder einem für die ISR stets sichtbaren Bereich. Ein Datensatz hat fünf Bytes: delay, CH1, CH2, CH3, CH4. In Notenfeldern hält 0xFF die aktuelle Stimme, 0xFD stoppt sie. Im delay-Feld beendet 0xFF die Wiedergabe, 0xFE wiederholt sie. Dies ist das Datensatzlayout, nicht die Kanal-ID-Nummerierung. WRAM-Warteschlangenwiedergabe ist ein separater Modus; übergeben Sie vollständige Fünfbyte-Datensätze mit AudioVBlank_QueueRefill.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Die ISR spielt ein Lied mit zwei Noten. Vergleichen Sie die Musiksperre, die den aktuellen Ton erhält, Stop, das ihn stummschaltet, und die IRQ-Sperre nach Neustart, die ihn ebenfalls erhält. RAM-Prüfungen bestätigen, dass der Hook bei deaktivierter Musik läuft und bei deaktiviertem IRQ stoppt.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Wählt ein direkt gelesenes Lied und bereitet seine Wiedergabe von Anfang an vor.
Syntax
void __stackcall AudioVBlank_PlayMusic(u8 *song);Parameter
songStartadresse des Lieds. Der Treiber leiht das Array aus; es muss während der gesamten Wiedergabe lesbar bleiben.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
audio_vblank.c implementiert __kq_vblank_vector; installieren Sie keinen konkurrierenden VBlank-Vektor. Das Beispiel definiert Audio_NoiseEffectActive, schließt den normalen Musikdecoder aus und nutzt Audio_Update nur für Effekte und Lautstärkeübergänge. Sperren Sie Interrupts beim Ändern von Liedzeigern oder gemeinsamem Zustand.
Halten Sie direkt gelesene Lieddaten in festem ROM oder einem für die ISR stets sichtbaren Bereich. Ein Datensatz hat fünf Bytes: delay, CH1, CH2, CH3, CH4. In Notenfeldern hält 0xFF die aktuelle Stimme, 0xFD stoppt sie. Im delay-Feld beendet 0xFF die Wiedergabe, 0xFE wiederholt sie. Dies ist das Datensatzlayout, nicht die Kanal-ID-Nummerierung. WRAM-Warteschlangenwiedergabe ist ein separater Modus; übergeben Sie vollständige Fünfbyte-Datensätze mit AudioVBlank_QueueRefill.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Die ISR spielt ein Lied mit zwei Noten. Vergleichen Sie die Musiksperre, die den aktuellen Ton erhält, Stop, das ihn stummschaltet, und die IRQ-Sperre nach Neustart, die ihn ebenfalls erhält. RAM-Prüfungen bestätigen, dass der Hook bei deaktivierter Musik läuft und bei deaktiviertem IRQ stoppt.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Die lokalen Unterschiede dieser API stehen bei den Änderungen und Prüfungen vom 2026-10-03.
Aktiviert die Wiedergabe, wenn der Queue-Modus aktiv und mindestens ein Datensatz vorhanden ist. Zeigerpositionen, Verzögerung, Musikaktivierung und Pausenzustand bleiben erhalten. Setzen Sie die Queue vor einem neuen Datenstrom zurück und befüllen Sie sie vorab.
Syntax
u8 AudioVBlank_QueuePlay();Rückgabewert
Gibt bei Annahme eins zurück, bei leerer Queue oder außerhalb des Queue-Modus null. Zum Abarbeiten muss die ISR laufen, die Musik aktiviert und der Treiber nicht pausiert sein.
Bedingungen und Grenzen
Rufen Sie nach AudioVBlank_Init nacheinander QueueReset, QueueRefill und QueuePlay auf. Binden Sie die normale audio_vblank.c ein; AUDIO_VBLANK_CORE_ONLY schließt die in C geschriebenen Funktionen zum Befüllen der Queue aus. Der Hauptprogrammcode füllt eine Queue mit sechzehn Datensätzen zu je fünf Bytes, die die VBlank-ISR abarbeitet.
Die Queue darf nur von einer Stelle im Hauptprogramm befüllt werden. Vermeiden Sie rekursive Aufrufe und Aufrufe aus einer ISR oder FrameHook. Beim kurzen Freigabeschritt jedes Datensatzes wird IE gesichert und werden die Interruptquellen gesperrt; anschließend werden IE und SVBK wiederhergestellt. IME bleibt unverändert. Der aufrufende Code muss die Quellbank im ROM/RAM auswählen und währenddessen beibehalten.
Zeitgesteuerte Datensätze enthalten delay, ch1_note, ch2_note, ch3_note und ch4_noise_param. Auch END muss als vollständiger Datensatz mit fünf Bytes vorliegen. LOOP wird im befüllenden Code durch erneutes Einreihen der gewünschten Datensätze umgesetzt. Übergeben Sie keinen unveränderten Befehlsstrom variabler Länge für die direkte Wiedergabe.
Anwendungsbeispiel
if(AudioVBlank_QueuePlay()==0) sound_result[0]++;
AudioVBlank_EnableIrq();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel spielt eine selbst komponierte Phrase mit acht Noten sechsmal ab und stoppt danach. Dabei werden 49 Datensätze — 48 Noten und END — durch die Queue mit sechzehn Plätzen geleitet. Geprüft werden die Annahme aller 49 Datensätze, null Unterläufe, das Ende der Wiedergabe, leere und volle Queue, Nullzeiger und Anzahl null, die Wiederherstellung der CGB-WRAM-Bank, unverändertes IME sowie Ton während und Stille nach der Wiedergabe.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Die lokalen Unterschiede dieser API stehen bei den Änderungen und Prüfungen vom 2026-10-03.
Kopiert vollständige Datensätze mit je fünf Bytes in freie Queue-Plätze und gibt jeden erst nach Abschluss seiner Kopie frei. Pro Aufruf werden höchstens sechzehn Datensätze angenommen.
Syntax
u8 __stackcall AudioVBlank_QueueRefill(const u8 *records, u8 count);Parameter
recordsDatensatzarray in der aktuell lesbaren Bank. Für jeden angenommenen Datensatz müssen fünf Bytes lesbar sein. Bei einem Nullzeiger wird null zurückgegeben.
countAnzahl der Datensätze, deren Aufnahme versucht werden soll, keine Byteanzahl. Werte über sechzehn werden auf sechzehn begrenzt; null bewirkt nichts.
Rückgabewert
Gibt die tatsächlich angenommene Anzahl von Datensätzen zurück, von 0 bis 16. Bei voller Queue, Nullzeiger, Anzahl null oder außerhalb des Queue-Modus wird null zurückgegeben. Rücken Sie den Quellzeiger um das Fünffache des Rückgabewerts vor. Da die ISR während des Aufrufs Plätze freigeben kann, entspricht das Ergebnis nicht unbedingt der Zahl freier Plätze beim Eintritt.
Bedingungen und Grenzen
Rufen Sie nach AudioVBlank_Init nacheinander QueueReset, QueueRefill und QueuePlay auf. Binden Sie die normale audio_vblank.c ein; AUDIO_VBLANK_CORE_ONLY schließt die in C geschriebenen Funktionen zum Befüllen der Queue aus. Der Hauptprogrammcode füllt eine Queue mit sechzehn Datensätzen zu je fünf Bytes, die die VBlank-ISR abarbeitet.
Die Queue darf nur von einer Stelle im Hauptprogramm befüllt werden. Vermeiden Sie rekursive Aufrufe und Aufrufe aus einer ISR oder FrameHook. Beim kurzen Freigabeschritt jedes Datensatzes wird IE gesichert und werden die Interruptquellen gesperrt; anschließend werden IE und SVBK wiederhergestellt. IME bleibt unverändert. Der aufrufende Code muss die Quellbank im ROM/RAM auswählen und währenddessen beibehalten.
Zeitgesteuerte Datensätze enthalten delay, ch1_note, ch2_note, ch3_note und ch4_noise_param. Auch END muss als vollständiger Datensatz mit fünf Bytes vorliegen. LOOP wird im befüllenden Code durch erneutes Einreihen der gewünschten Datensätze umgesetzt. Übergeben Sie keinen unveränderten Befehlsstrom variabler Länge für die direkte Wiedergabe.
Anwendungsbeispiel
next=AudioVBlank_QueueRefill(queue_song,16);
// next counts records; each record occupies five source bytes.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel spielt eine selbst komponierte Phrase mit acht Noten sechsmal ab und stoppt danach. Dabei werden 49 Datensätze — 48 Noten und END — durch die Queue mit sechzehn Plätzen geleitet. Geprüft werden die Annahme aller 49 Datensätze, null Unterläufe, das Ende der Wiedergabe, leere und volle Queue, Nullzeiger und Anzahl null, die Wiederherstellung der CGB-WRAM-Bank, unverändertes IME sowie Ton während und Stille nach der Wiedergabe.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Die lokalen Unterschiede dieser API stehen bei den Änderungen und Prüfungen vom 2026-10-03.
Stoppt die Wiedergabe, schaltet den Ton stumm, wählt den Queue-Modus und setzt Lese- und Schreibposition, Anzahl und Unterlaufzähler auf null. Ausstehende Datensätze werden verworfen, um einen neuen Datenstrom vorzubereiten.
Syntax
void AudioVBlank_QueueReset();Rückgabewert
Kein Rückgabewert. Die Einstellungen für Musikaktivierung und Pause bleiben erhalten.
Bedingungen und Grenzen
Rufen Sie nach AudioVBlank_Init nacheinander QueueReset, QueueRefill und QueuePlay auf. Binden Sie die normale audio_vblank.c ein; AUDIO_VBLANK_CORE_ONLY schließt die in C geschriebenen Funktionen zum Befüllen der Queue aus. Der Hauptprogrammcode füllt eine Queue mit sechzehn Datensätzen zu je fünf Bytes, die die VBlank-ISR abarbeitet.
Die Queue darf nur von einer Stelle im Hauptprogramm befüllt werden. Vermeiden Sie rekursive Aufrufe und Aufrufe aus einer ISR oder FrameHook. Beim kurzen Freigabeschritt jedes Datensatzes wird IE gesichert und werden die Interruptquellen gesperrt; anschließend werden IE und SVBK wiederhergestellt. IME bleibt unverändert. Der aufrufende Code muss die Quellbank im ROM/RAM auswählen und währenddessen beibehalten.
Zeitgesteuerte Datensätze enthalten delay, ch1_note, ch2_note, ch3_note und ch4_noise_param. Auch END muss als vollständiger Datensatz mit fünf Bytes vorliegen. LOOP wird im befüllenden Code durch erneutes Einreihen der gewünschten Datensätze umgesetzt. Übergeben Sie keinen unveränderten Befehlsstrom variabler Länge für die direkte Wiedergabe.
Anwendungsbeispiel
AudioVBlank_QueueReset(); // Silence playback and discard any queued records.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel spielt eine selbst komponierte Phrase mit acht Noten sechsmal ab und stoppt danach. Dabei werden 49 Datensätze — 48 Noten und END — durch die Queue mit sechzehn Plätzen geleitet. Geprüft werden die Annahme aller 49 Datensätze, null Unterläufe, das Ende der Wiedergabe, leere und volle Queue, Nullzeiger und Anzahl null, die Wiederherstellung der CGB-WRAM-Bank, unverändertes IME sowie Ton während und Stille nach der Wiedergabe.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Setzt die reine Pulsfreigabeanforderung 2, falls nichts aussteht, und erhält eine vorhandene Wiederherstellungsanforderung 1.
Syntax
void AudioVBlank_RequestRestoreCh1();Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
audio_vblank.c implementiert __kq_vblank_vector; installieren Sie keinen konkurrierenden VBlank-Vektor. Das Beispiel definiert Audio_NoiseEffectActive, schließt den normalen Musikdecoder aus und nutzt Audio_Update nur für Effekte und Lautstärkeübergänge. Sperren Sie Interrupts beim Ändern von Liedzeigern oder gemeinsamem Zustand.
Bei direktem Wiederherstellungsaufruf stellt der Aufrufer sicher, dass der Effekt die Stimme freigegeben hat, und löscht danach das ausstehende Flag. Anforderungsfunktionen allein schreiben keine Audioregister.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Es folgen Pulswiederherstellung, Stille, Wellenwiederherstellung und Stille, jeweils 30 Frames. Eine Freigabeanforderung erhält den ausstehenden Wert 1; ohne ausstehendes Ereignis ergibt sie den reinen Freigabewert 2. IRQ ist hier deaktiviert, und der Aufrufer verwaltet die Kanalbelegung ausdrücklich.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Setzt die reine Wellenfreigabeanforderung 2, falls nichts aussteht, und erhält eine vorhandene Wiederherstellungsanforderung 1.
Syntax
void AudioVBlank_RequestRestoreCh3();Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
audio_vblank.c implementiert __kq_vblank_vector; installieren Sie keinen konkurrierenden VBlank-Vektor. Das Beispiel definiert Audio_NoiseEffectActive, schließt den normalen Musikdecoder aus und nutzt Audio_Update nur für Effekte und Lautstärkeübergänge. Sperren Sie Interrupts beim Ändern von Liedzeigern oder gemeinsamem Zustand.
Bei direktem Wiederherstellungsaufruf stellt der Aufrufer sicher, dass der Effekt die Stimme freigegeben hat, und löscht danach das ausstehende Flag. Anforderungsfunktionen allein schreiben keine Audioregister.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Es folgen Pulswiederherstellung, Stille, Wellenwiederherstellung und Stille, jeweils 30 Frames. Eine Freigabeanforderung erhält den ausstehenden Wert 1; ohne ausstehendes Ereignis ergibt sie den reinen Freigabewert 2. IRQ ist hier deaktiviert, und der Aufrufer verwaltet die Kanalbelegung ausdrücklich.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Stellt eine gespeicherte Musiknote auf der vom Effekt belegten Pulsstimme (CH1 oder CH2) wieder her oder gibt sie stumm frei.
Syntax
void AudioVBlank_RestoreCh1();Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
audio_vblank.c implementiert __kq_vblank_vector; installieren Sie keinen konkurrierenden VBlank-Vektor. Das Beispiel definiert Audio_NoiseEffectActive, schließt den normalen Musikdecoder aus und nutzt Audio_Update nur für Effekte und Lautstärkeübergänge. Sperren Sie Interrupts beim Ändern von Liedzeigern oder gemeinsamem Zustand.
Bei direktem Wiederherstellungsaufruf stellt der Aufrufer sicher, dass der Effekt die Stimme freigegeben hat, und löscht danach das ausstehende Flag. Anforderungsfunktionen allein schreiben keine Audioregister.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Es folgen Pulswiederherstellung, Stille, Wellenwiederherstellung und Stille, jeweils 30 Frames. Eine Freigabeanforderung erhält den ausstehenden Wert 1; ohne ausstehendes Ereignis ergibt sie den reinen Freigabewert 2. IRQ ist hier deaktiviert, und der Aufrufer verwaltet die Kanalbelegung ausdrücklich.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Stellt nach Effektfreigabe die gespeicherte CH3-Note wieder her oder deaktiviert dessen DAC.
Syntax
void AudioVBlank_RestoreCh3();Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
audio_vblank.c implementiert __kq_vblank_vector; installieren Sie keinen konkurrierenden VBlank-Vektor. Das Beispiel definiert Audio_NoiseEffectActive, schließt den normalen Musikdecoder aus und nutzt Audio_Update nur für Effekte und Lautstärkeübergänge. Sperren Sie Interrupts beim Ändern von Liedzeigern oder gemeinsamem Zustand.
Bei direktem Wiederherstellungsaufruf stellt der Aufrufer sicher, dass der Effekt die Stimme freigegeben hat, und löscht danach das ausstehende Flag. Anforderungsfunktionen allein schreiben keine Audioregister.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Es folgen Pulswiederherstellung, Stille, Wellenwiederherstellung und Stille, jeweils 30 Frames. Eine Freigabeanforderung erhält den ausstehenden Wert 1; ohne ausstehendes Ereignis ergibt sie den reinen Freigabewert 2. IRQ ist hier deaktiviert, und der Aufrufer verwaltet die Kanalbelegung ausdrücklich.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Gibt VBlank-Musik frei oder sperrt sie und löscht beim Deaktivieren Wiederherstellungsanforderungen. Aktueller Ton und IRQ bleiben unverändert.
Syntax
void __stackcall AudioVBlank_SetEnabled(u8 on);Parameter
onNull deaktiviert, ungleich null aktiviert. Unterscheiden Sie anhand der Funktionsbeschreibung zwischen Stummschaltung und Sperren der Aktualisierung.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
audio_vblank.c implementiert __kq_vblank_vector; installieren Sie keinen konkurrierenden VBlank-Vektor. Das Beispiel definiert Audio_NoiseEffectActive, schließt den normalen Musikdecoder aus und nutzt Audio_Update nur für Effekte und Lautstärkeübergänge. Sperren Sie Interrupts beim Ändern von Liedzeigern oder gemeinsamem Zustand.
Halten Sie direkt gelesene Lieddaten in festem ROM oder einem für die ISR stets sichtbaren Bereich. Ein Datensatz hat fünf Bytes: delay, CH1, CH2, CH3, CH4. In Notenfeldern hält 0xFF die aktuelle Stimme, 0xFD stoppt sie. Im delay-Feld beendet 0xFF die Wiedergabe, 0xFE wiederholt sie. Dies ist das Datensatzlayout, nicht die Kanal-ID-Nummerierung. WRAM-Warteschlangenwiedergabe ist ein separater Modus; übergeben Sie vollständige Fünfbyte-Datensätze mit AudioVBlank_QueueRefill.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Die ISR spielt ein Lied mit zwei Noten. Vergleichen Sie die Musiksperre, die den aktuellen Ton erhält, Stop, das ihn stummschaltet, und die IRQ-Sperre nach Neustart, die ihn ebenfalls erhält. RAM-Prüfungen bestätigen, dass der Hook bei deaktivierter Musik läuft und bei deaktiviertem IRQ stoppt.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Wählt ein direkt gelesenes Lied und setzt seine Cursor zurück, ohne das Wiedergabeflag zu ändern.
Syntax
void __stackcall AudioVBlank_SetMusic(u8 *song);Parameter
songStartadresse des Lieds. Der Treiber leiht das Array aus; es muss während der gesamten Wiedergabe lesbar bleiben.
Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
audio_vblank.c implementiert __kq_vblank_vector; installieren Sie keinen konkurrierenden VBlank-Vektor. Das Beispiel definiert Audio_NoiseEffectActive, schließt den normalen Musikdecoder aus und nutzt Audio_Update nur für Effekte und Lautstärkeübergänge. Sperren Sie Interrupts beim Ändern von Liedzeigern oder gemeinsamem Zustand.
Halten Sie direkt gelesene Lieddaten in festem ROM oder einem für die ISR stets sichtbaren Bereich. Ein Datensatz hat fünf Bytes: delay, CH1, CH2, CH3, CH4. In Notenfeldern hält 0xFF die aktuelle Stimme, 0xFD stoppt sie. Im delay-Feld beendet 0xFF die Wiedergabe, 0xFE wiederholt sie. Dies ist das Datensatzlayout, nicht die Kanal-ID-Nummerierung. WRAM-Warteschlangenwiedergabe ist ein separater Modus; übergeben Sie vollständige Fünfbyte-Datensätze mit AudioVBlank_QueueRefill.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Die ISR spielt ein Lied mit zwei Noten. Vergleichen Sie die Musiksperre, die den aktuellen Ton erhält, Stop, das ihn stummschaltet, und die IRQ-Sperre nach Neustart, die ihn ebenfalls erhält. RAM-Prüfungen bestätigen, dass der Hook bei deaktivierter Musik läuft und bei deaktiviertem IRQ stoppt.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Löscht Wiedergabe-, delay- und Wiederherstellungszustand und schaltet Puls-, Rausch- und Wellenstimmen sofort stumm. IRQ bleibt aktiviert.
Syntax
void AudioVBlank_Stop();Rückgabewert
Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.
Bedingungen und Grenzen
audio_vblank.c implementiert __kq_vblank_vector; installieren Sie keinen konkurrierenden VBlank-Vektor. Das Beispiel definiert Audio_NoiseEffectActive, schließt den normalen Musikdecoder aus und nutzt Audio_Update nur für Effekte und Lautstärkeübergänge. Sperren Sie Interrupts beim Ändern von Liedzeigern oder gemeinsamem Zustand.
Halten Sie direkt gelesene Lieddaten in festem ROM oder einem für die ISR stets sichtbaren Bereich. Ein Datensatz hat fünf Bytes: delay, CH1, CH2, CH3, CH4. In Notenfeldern hält 0xFF die aktuelle Stimme, 0xFD stoppt sie. Im delay-Feld beendet 0xFF die Wiedergabe, 0xFE wiederholt sie. Dies ist das Datensatzlayout, nicht die Kanal-ID-Nummerierung. WRAM-Warteschlangenwiedergabe ist ein separater Modus; übergeben Sie vollständige Fünfbyte-Datensätze mit AudioVBlank_QueueRefill.
Anwendungsbeispiel
// 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();
}Erwartetes Ergebnis
Die ISR spielt ein Lied mit zwei Noten. Vergleichen Sie die Musiksperre, die den aktuellen Ton erhält, Stop, das ihn stummschaltet, und die IRQ-Sperre nach Neustart, die ihn ebenfalls erhält. RAM-Prüfungen bestätigen, dass der Hook bei deaktivierter Musik läuft und bei deaktiviertem IRQ stoppt.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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 — Bankabhängiger Zugriff auf Code und Daten
Eine ROM-Bank ist ein Speicherblock des Moduls, der in den CPU-Adressraum eingeblendet wird. Verschiedene Banken können an derselben CPU-Adresse liegen; ein 16-Bit-Zeiger allein identifiziert Bankdaten deshalb nicht eindeutig. BankPtr ist ein gepackter Deskriptor aus drei Bytes: einem Bankbyte und einem Zwei-Byte-Zeiger. Er wird mit farptr_make erstellt und mit farptr_read8, farptr_read16 oder farptr_read gelesen.
Das GB-Beispiel verwendet ein MBC5-Modul: Code in der festen Bank 0 bleibt unter $0000–$3FFF erreichbar, während die Banken 1, 2 und 3 unter $4000–$7FFF eingeblendet werden. Legen Sie bank_switch und den danach ausgeführten Code im festen ROM ab. Initialisieren Sie den Bibliothekszustand mit bank_switch, bevor Sie ihn abfragen. Auf GB akzeptiert far_call einen Callback-Zeiger; __farcall benötigt einen Funktionsnamen.
bank_get_current
Liefert die zuletzt von bank_switch gespeicherte Banknummer. Gelesen wird der Softwarezustand, nicht ein Register des Moduls.
Syntax
u8 bank_get_current();Rückgabewert
Der zuletzt von bank_switch gespeicherte u8-Wert; vor der Initialisierung null.
Bedingungen und Grenzen
Der Bibliothekszustand beginnt bei null und erkennt die Startzuordnung des Moduls nicht. Initialisieren Sie ihn mit bank_switch. Direkte Intrinsics und Mapper-Schreibzugriffe aktualisieren diesen separaten Zustand nicht; bank_get_current kann die tatsächliche Hardwarezuordnung daher nicht prüfen.
Anwendungsbeispiel
starting_bank=bank_get_current(); // Last value recorded by bank_switch.
bank_expect(starting_bank==2,1);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Der anfängliche Aufruf bank_switch(2) speichert und wählt Bank 2. Ein späterer direkter Wechsel wählt Bank 1 und liest A1 aus home1, während bank_get_current weiterhin 2 meldet. Nach dem Zurückschalten liefert home2 wieder B2.
Das vollständige Programm zeigt Datenzugriffe über Bank und Nahadresse, bankübergreifende Callbacks und den Unterschied zwischen Bibliothekszustand und tatsächlicher Zuordnung. Alle Zahlen sind hexadezimal. BANK IN und BANK OUT müssen 02 zeigen, BYTE HEX D3, WORD HEX 5C7A sowie FAILED CHECKS und FIRST FAILURE jeweils 00. CGB und FC zeigen blaue Schrift, DMG schwarze.
CALL COUNT zeigt 03: far_call, __farcall und __farcall_ptr rufen den Callback jeweils einmal auf.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Die lokalen Unterschiede dieser API stehen bei den Änderungen und Prüfungen vom 2026-10-03.
Wählt die ROM-Bank und speichert ihre Nummer sowohl in der bank-Bibliothek als auch im Bankzustand des Compilers. Fernzugriffe und Fernaufrufe stellen damit die vorherige Zuordnung wieder her.
Syntax
void bank_switch(u8 bank);Parameter
bankVorzeichenlose 8-Bit-ROM-Banknummer. Bei Aufrufen muss sie zur Funktionsplatzierung passen, bei Lesezugriffen wählt sie die Quelle. Verwenden Sie den gültigen Bereich des Modultyps.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Ein dauerhafter Bankwechsel darf weder den laufenden Code noch seine Rückkehradresse ausblenden. Legen Sie den Aufruf, gegebenenfalls bank_switch selbst und den anschließend ausgeführten Code wie im Beispiel in die gemeinsame beziehungsweise feste Bank 0.
Der Bibliothekszustand beginnt bei null und erkennt die Startzuordnung des Moduls nicht. Initialisieren Sie ihn mit bank_switch. Direkte Intrinsics und Mapper-Schreibzugriffe aktualisieren diesen separaten Zustand nicht; bank_get_current kann die tatsächliche Hardwarezuordnung daher nicht prüfen.
Diese GB-Bankschnittstellen verwenden acht Bankbits und setzen das neunte MBC5-Bankbit nicht. Modulregeln, etwa die Behandlung von Bank null, gelten weiterhin. Das Beispiel nutzt ausdrücklich MBC5-Banken 1–3; mischen Sie diesen Zustand nicht mit unprotokollierten direkten Mapper-Schreibzugriffen.
Anwendungsbeispiel
bank_switch(2); // Select the payload window and update library bookkeeping.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Der anfängliche Aufruf bank_switch(2) speichert und wählt Bank 2. Ein späterer direkter Wechsel wählt Bank 1 und liest A1 aus home1, während bank_get_current weiterhin 2 meldet. Nach dem Zurückschalten liefert home2 wieder B2.
Das vollständige Programm zeigt Datenzugriffe über Bank und Nahadresse, bankübergreifende Callbacks und den Unterschied zwischen Bibliothekszustand und tatsächlicher Zuordnung. Alle Zahlen sind hexadezimal. BANK IN und BANK OUT müssen 02 zeigen, BYTE HEX D3, WORD HEX 5C7A sowie FAILED CHECKS und FIRST FAILURE jeweils 00. CGB und FC zeigen blaue Schrift, DMG schwarze.
CALL COUNT zeigt 03: far_call, __farcall und __farcall_ptr rufen den Callback jeweils einmal auf.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Übergibt Banknummer und Callback-Zeiger an __farcall_ptr. Diese Bibliotheksfunktion führt den Callback ohne Argumente aus und kehrt nach Wiederherstellung der Aufruferbank zurück.
Syntax
void far_call(u8 bank, const void* func);Parameter
bankVorzeichenlose 8-Bit-ROM-Banknummer. Bei Aufrufen muss sie zur Funktionsplatzierung passen, bei Lesezugriffen wählt sie die Quelle. Verwenden Sie den gültigen Bereich des Modultyps.
funcGültige ausführbare Adresse eines Callbacks ohne Parameter, angegeben als Funktionsname oder Laufzeitzeiger. Nullzeiger und falsche Bank-Adress-Paare werden zur Laufzeit nicht geprüft.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Diese Aufrufe reichen keine Benutzerargumente weiter und machen den Callback nicht interrupt-reentrant. Verwalten Sie seine Daten, seinen Stack und seine Interruptnutzung korrekt. Die Bankwiederherstellung ist mit verschachtelten und wiederholten Aufrufen geprüft; reale Hardware und beliebige Interruptverschachtelungen deckt dieses Beispiel nicht ab.
Diese GB-Bankschnittstellen verwenden acht Bankbits und setzen das neunte MBC5-Bankbit nicht. Modulregeln, etwa die Behandlung von Bank null, gelten weiterhin. Das Beispiel nutzt ausdrücklich MBC5-Banken 1–3; mischen Sie diesen Zustand nicht mit unprotokollierten direkten Mapper-Schreibzugriffen.
Anwendungsbeispiel
far_call(3,callback); // No arguments; callback reads payload[0] in bank 3.
bank_expect(callback_count==1 && callback_byte==0xD3,15);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
An dieser Stelle des vollständigen Programms erhöht far_call den Wert von callback_count auf 1. Der Callback liest D3 aus Bank 3. Ein späterer Nahzugriff auf home2 mit Ergebnis B2 bestätigt die Rückkehr bei eingeblendeter Bank 2.
Das vollständige Programm zeigt Datenzugriffe über Bank und Nahadresse, bankübergreifende Callbacks und den Unterschied zwischen Bibliothekszustand und tatsächlicher Zuordnung. Alle Zahlen sind hexadezimal. BANK IN und BANK OUT müssen 02 zeigen, BYTE HEX D3, WORD HEX 5C7A sowie FAILED CHECKS und FIRST FAILURE jeweils 00. CGB und FC zeigen blaue Schrift, DMG schwarze.
CALL COUNT zeigt 03: far_call, __farcall und __farcall_ptr rufen den Callback jeweils einmal auf.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Kopiert über das Fernspeicher-Intrinsic len Bytes aus der angegebenen ROM-Bank in den RAM-Puffer des Aufrufers. Vor der Rückkehr wird die vorherige Bank wiederhergestellt.
Syntax
void far_data_read(u8 bank, const void* addr, void* dst, u16 len);Parameter
bankVorzeichenlose 8-Bit-ROM-Banknummer. Bei Aufrufen muss sie zur Funktionsplatzierung passen, bei Lesezugriffen wählt sie die Quelle. Verwenden Sie den gültigen Bereich des Modultyps.
addrNahzeiger auf lesbare Bytes in der gewählten ROM-Bank. Er enthält keine Banknummer.
dstZiel in beschreibbarem Speicher mit genügend Platz für alle kopierten Byte. Abgesehen von einem Transfer mit Länge null erfolgt keine Prüfung auf Nullzeiger oder ungültige Zieladressen.
lenByteanzahl, 0–65535. Bei null wird kein Speicher kopiert; Bankauswahl und Wiederherstellung werden trotzdem ausgeführt.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Der gesamte Quellbereich muss in der vorgesehenen ROM-Zuordnung lesbar und der gesamte Zielbereich beschreibbar sein. Die Kopie schaltet am Fensterende nicht automatisch zur nächsten Bank, behandelt Überlappungen nicht wie memmove und steuert keine sicheren VRAM-Schreibzeitpunkte. Verwenden Sie für VRAM die Grafikübertragungs-APIs.
Fernlesezugriffe und Kopien arbeiten synchron und nutzen gemeinsamen Arbeitsspeicher des Compilers. Ein Interrupt darf währenddessen keinen weiteren Banktransfer über denselben Speicher ausführen. Auf GB nutzt die Kopierhilfe außerdem einen gemeinsamen HRAM-Platz für die gespeicherte Bank. Das Beispiel führt die Operationen aus festem Code ohne konkurrierenden Transfer-Handler aus.
Diese GB-Bankschnittstellen verwenden acht Bankbits und setzen das neunte MBC5-Bankbit nicht. Modulregeln, etwa die Behandlung von Bank null, gelten weiterhin. Das Beispiel nutzt ausdrücklich MBC5-Banken 1–3; mischen Sie diesen Zustand nicht mit unprotokollierten direkten Mapper-Schreibzugriffen.
Anwendungsbeispiel
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);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieser Ausschnitt kopiert mit far_data_read 4 Bytes und prüft den Puffer gegen D3 7A 5C 96. Quelldeskriptor oder Quellzeiger des Aufrufers bleiben erhalten; das vollständige Programm prüft zusätzlich eine Kopie der Länge null und die Bankwiederherstellung.
Das vollständige Programm zeigt Datenzugriffe über Bank und Nahadresse, bankübergreifende Callbacks und den Unterschied zwischen Bibliothekszustand und tatsächlicher Zuordnung. Alle Zahlen sind hexadezimal. BANK IN und BANK OUT müssen 02 zeigen, BYTE HEX D3, WORD HEX 5C7A sowie FAILED CHECKS und FIRST FAILURE jeweils 00. CGB und FC zeigen blaue Schrift, DMG schwarze.
CALL COUNT zeigt 03: far_call, __farcall und __farcall_ptr rufen den Callback jeweils einmal auf.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Liest mit __farpeek16 zwei aufeinanderfolgende Bytes als Little-Endian-Wort. Das erste Byte bildet die unteren acht Bits.
Syntax
u16 far_data_read16(u8 bank, const void* addr);Parameter
bankVorzeichenlose 8-Bit-ROM-Banknummer. Bei Aufrufen muss sie zur Funktionsplatzierung passen, bei Lesezugriffen wählt sie die Quelle. Verwenden Sie den gültigen Bereich des Modultyps.
addrNahzeiger auf lesbare Bytes in der gewählten ROM-Bank. Er enthält keine Banknummer.
Rückgabewert
Das gelesene Little-Endian-Wort als u16 (0–65535).
Bedingungen und Grenzen
Das gesamte Byte oder Wort muss in der gewählten CPU-Zuordnung lesbar sein. Zeiger werden nicht geprüft, Adressen nicht begrenzt und Fenstergrenzen lösen keinen automatischen Wechsel zur nächsten ROM-Bank aus. Ein Wort benötigt zwei gültige aufeinanderfolgende Bytes.
Fernlesezugriffe und Kopien arbeiten synchron und nutzen gemeinsamen Arbeitsspeicher des Compilers. Ein Interrupt darf währenddessen keinen weiteren Banktransfer über denselben Speicher ausführen. Auf GB nutzt die Kopierhilfe außerdem einen gemeinsamen HRAM-Platz für die gespeicherte Bank. Das Beispiel führt die Operationen aus festem Code ohne konkurrierenden Transfer-Handler aus.
Diese GB-Bankschnittstellen verwenden acht Bankbits und setzen das neunte MBC5-Bankbit nicht. Modulregeln, etwa die Behandlung von Bank null, gelten weiterhin. Das Beispiel nutzt ausdrücklich MBC5-Banken 1–3; mischen Sie diesen Zustand nicht mit unprotokollierten direkten Mapper-Schreibzugriffen.
Anwendungsbeispiel
word_value=far_data_read16(3,payload+1); // Little-endian 7A 5C -> 0x5C7A.
bank_expect(word_value==0x5C7A,6);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieser Ausschnitt liest mit far_data_read16 den Ausdruck payload+1 in Bank 3 und prüft 5C7A. Das vollständige Programm bestätigt durch einen Nahzugriff auf home2 außerdem die Wiederherstellung von Bank 2.
Das vollständige Programm zeigt Datenzugriffe über Bank und Nahadresse, bankübergreifende Callbacks und den Unterschied zwischen Bibliothekszustand und tatsächlicher Zuordnung. Alle Zahlen sind hexadezimal. BANK IN und BANK OUT müssen 02 zeigen, BYTE HEX D3, WORD HEX 5C7A sowie FAILED CHECKS und FIRST FAILURE jeweils 00. CGB und FC zeigen blaue Schrift, DMG schwarze.
CALL COUNT zeigt 03: far_call, __farcall und __farcall_ptr rufen den Callback jeweils einmal auf.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Liest über __farpeek8 ein Byte aus der angegebenen ROM-Bank und Adresse, stellt die vorherige Bank wieder her und liefert den Wert.
Syntax
u8 far_data_read8(u8 bank, const void* addr);Parameter
bankVorzeichenlose 8-Bit-ROM-Banknummer. Bei Aufrufen muss sie zur Funktionsplatzierung passen, bei Lesezugriffen wählt sie die Quelle. Verwenden Sie den gültigen Bereich des Modultyps.
addrNahzeiger auf lesbare Bytes in der gewählten ROM-Bank. Er enthält keine Banknummer.
Rückgabewert
Das gelesene Byte als u8 (0–255).
Bedingungen und Grenzen
Das gesamte Byte oder Wort muss in der gewählten CPU-Zuordnung lesbar sein. Zeiger werden nicht geprüft, Adressen nicht begrenzt und Fenstergrenzen lösen keinen automatischen Wechsel zur nächsten ROM-Bank aus. Ein Wort benötigt zwei gültige aufeinanderfolgende Bytes.
Fernlesezugriffe und Kopien arbeiten synchron und nutzen gemeinsamen Arbeitsspeicher des Compilers. Ein Interrupt darf währenddessen keinen weiteren Banktransfer über denselben Speicher ausführen. Auf GB nutzt die Kopierhilfe außerdem einen gemeinsamen HRAM-Platz für die gespeicherte Bank. Das Beispiel führt die Operationen aus festem Code ohne konkurrierenden Transfer-Handler aus.
Diese GB-Bankschnittstellen verwenden acht Bankbits und setzen das neunte MBC5-Bankbit nicht. Modulregeln, etwa die Behandlung von Bank null, gelten weiterhin. Das Beispiel nutzt ausdrücklich MBC5-Banken 1–3; mischen Sie diesen Zustand nicht mit unprotokollierten direkten Mapper-Schreibzugriffen.
Anwendungsbeispiel
byte_value=far_data_read8(3,payload); // One byte: 0xD3.
bank_expect(byte_value==0xD3,5);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieser Ausschnitt liest mit far_data_read8 den Ausdruck payload in Bank 3 und prüft D3. Das vollständige Programm bestätigt durch einen Nahzugriff auf home2 außerdem die Wiederherstellung von Bank 2.
Das vollständige Programm zeigt Datenzugriffe über Bank und Nahadresse, bankübergreifende Callbacks und den Unterschied zwischen Bibliothekszustand und tatsächlicher Zuordnung. Alle Zahlen sind hexadezimal. BANK IN und BANK OUT müssen 02 zeigen, BYTE HEX D3, WORD HEX 5C7A sowie FAILED CHECKS und FIRST FAILURE jeweils 00. CGB und FC zeigen blaue Schrift, DMG schwarze.
CALL COUNT zeigt 03: far_call, __farcall und __farcall_ptr rufen den Callback jeweils einmal auf.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Speichert ein Bankbyte und einen CPU-sichtbaren Zeiger im BankPtr des Aufrufers. Dabei entsteht nur ein Deskriptor; weder wird die Bank umgeschaltet noch werden die referenzierten Daten gelesen.
Syntax
void farptr_make(BankPtr* out, u8 bank, const u8* ptr);Parameter
outZeiger auf beschreibbaren Speicher für einen drei Byte großen BankPtr. Ein Nullzeiger für out führt zu keiner Schreiboperation.
bankVorzeichenlose 8-Bit-ROM-Banknummer. Bei Aufrufen muss sie zur Funktionsplatzierung passen, bei Lesezugriffen wählt sie die Quelle. Verwenden Sie den gültigen Bereich des Modultyps.
ptrIm Deskriptor zu speichernde CPU-sichtbare 16-Bit-Adresse. Sie wird unverändert übernommen; ihre Gültigkeit in der gewählten Bank wird nicht geprüft.
Rückgabewert
Keiner (void).
Anwendungsbeispiel
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.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Der Deskriptor erhält Bank 3 und payload+1. Seine Leseoperationen liefern 7A, 5C7A und die drei Bytes 7A 5C 96. Der Aufruf mit Nullausgabe darf keinen Zustand ändern.
Das vollständige Programm zeigt Datenzugriffe über Bank und Nahadresse, bankübergreifende Callbacks und den Unterschied zwischen Bibliothekszustand und tatsächlicher Zuordnung. Alle Zahlen sind hexadezimal. BANK IN und BANK OUT müssen 02 zeigen, BYTE HEX D3, WORD HEX 5C7A sowie FAILED CHECKS und FIRST FAILURE jeweils 00. CGB und FC zeigen blaue Schrift, DMG schwarze.
CALL COUNT zeigt 03: far_call, __farcall und __farcall_ptr rufen den Callback jeweils einmal auf.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Kopiert len Bytes von einem BankPtr in beschreibbaren RAM. Da der Deskriptor als Wert übergeben wird, zeigt der Zeiger des Aufrufers weiterhin auf den Anfang der Quelle.
Syntax
void farptr_read(BankPtr ptr, void* dst, u16 len);Parameter
ptrEin BankPtr-Wert mit den Feldern bank und ptr. Übergeben Sie den Deskriptor selbst, nicht seine Adresse. Der Deskriptor des Aufrufers bleibt unverändert.
dstZiel in beschreibbarem Speicher mit genügend Platz für alle kopierten Byte. Abgesehen von einem Transfer mit Länge null erfolgt keine Prüfung auf Nullzeiger oder ungültige Zieladressen.
lenByteanzahl, 0–65535. Bei null wird kein Speicher kopiert; Bankauswahl und Wiederherstellung werden trotzdem ausgeführt.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Der gesamte Quellbereich muss in der vorgesehenen ROM-Zuordnung lesbar und der gesamte Zielbereich beschreibbar sein. Die Kopie schaltet am Fensterende nicht automatisch zur nächsten Bank, behandelt Überlappungen nicht wie memmove und steuert keine sicheren VRAM-Schreibzeitpunkte. Verwenden Sie für VRAM die Grafikübertragungs-APIs.
Fernlesezugriffe und Kopien arbeiten synchron und nutzen gemeinsamen Arbeitsspeicher des Compilers. Ein Interrupt darf währenddessen keinen weiteren Banktransfer über denselben Speicher ausführen. Auf GB nutzt die Kopierhilfe außerdem einen gemeinsamen HRAM-Platz für die gespeicherte Bank. Das Beispiel führt die Operationen aus festem Code ohne konkurrierenden Transfer-Handler aus.
Diese GB-Bankschnittstellen verwenden acht Bankbits und setzen das neunte MBC5-Bankbit nicht. Modulregeln, etwa die Behandlung von Bank null, gelten weiterhin. Das Beispiel nutzt ausdrücklich MBC5-Banken 1–3; mischen Sie diesen Zustand nicht mit unprotokollierten direkten Mapper-Schreibzugriffen.
Anwendungsbeispiel
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);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieser Ausschnitt kopiert mit farptr_read 3 Bytes und prüft den Puffer gegen 7A 5C 96. Quelldeskriptor oder Quellzeiger des Aufrufers bleiben erhalten; das vollständige Programm prüft zusätzlich eine Kopie der Länge null und die Bankwiederherstellung.
Das vollständige Programm zeigt Datenzugriffe über Bank und Nahadresse, bankübergreifende Callbacks und den Unterschied zwischen Bibliothekszustand und tatsächlicher Zuordnung. Alle Zahlen sind hexadezimal. BANK IN und BANK OUT müssen 02 zeigen, BYTE HEX D3, WORD HEX 5C7A sowie FAILED CHECKS und FIRST FAILURE jeweils 00. CGB und FC zeigen blaue Schrift, DMG schwarze.
CALL COUNT zeigt 03: far_call, __farcall und __farcall_ptr rufen den Callback jeweils einmal auf.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Liest ein Little-Endian-Wort aus Bank und Adresse eines BankPtr. Der Deskriptor wird als Wert übergeben; sein Zeiger wird nicht weitergesetzt.
Syntax
u16 farptr_read16(BankPtr ptr);Parameter
ptrEin BankPtr-Wert mit den Feldern bank und ptr. Übergeben Sie den Deskriptor selbst, nicht seine Adresse. Der Deskriptor des Aufrufers bleibt unverändert.
Rückgabewert
Das gelesene Little-Endian-Wort als u16 (0–65535).
Bedingungen und Grenzen
Das gesamte Byte oder Wort muss in der gewählten CPU-Zuordnung lesbar sein. Zeiger werden nicht geprüft, Adressen nicht begrenzt und Fenstergrenzen lösen keinen automatischen Wechsel zur nächsten ROM-Bank aus. Ein Wort benötigt zwei gültige aufeinanderfolgende Bytes.
Fernlesezugriffe und Kopien arbeiten synchron und nutzen gemeinsamen Arbeitsspeicher des Compilers. Ein Interrupt darf währenddessen keinen weiteren Banktransfer über denselben Speicher ausführen. Auf GB nutzt die Kopierhilfe außerdem einen gemeinsamen HRAM-Platz für die gespeicherte Bank. Das Beispiel führt die Operationen aus festem Code ohne konkurrierenden Transfer-Handler aus.
Diese GB-Bankschnittstellen verwenden acht Bankbits und setzen das neunte MBC5-Bankbit nicht. Modulregeln, etwa die Behandlung von Bank null, gelten weiterhin. Das Beispiel nutzt ausdrücklich MBC5-Banken 1–3; mischen Sie diesen Zustand nicht mit unprotokollierten direkten Mapper-Schreibzugriffen.
Anwendungsbeispiel
bank_expect(farptr_read16(pointer)==0x5C7A,10);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieser Ausschnitt liest mit farptr_read16 den Ausdruck pointer.ptr in Bank 3 und prüft 5C7A. Das vollständige Programm bestätigt durch einen Nahzugriff auf home2 außerdem die Wiederherstellung von Bank 2.
Das vollständige Programm zeigt Datenzugriffe über Bank und Nahadresse, bankübergreifende Callbacks und den Unterschied zwischen Bibliothekszustand und tatsächlicher Zuordnung. Alle Zahlen sind hexadezimal. BANK IN und BANK OUT müssen 02 zeigen, BYTE HEX D3, WORD HEX 5C7A sowie FAILED CHECKS und FIRST FAILURE jeweils 00. CGB und FC zeigen blaue Schrift, DMG schwarze.
CALL COUNT zeigt 03: far_call, __farcall und __farcall_ptr rufen den Callback jeweils einmal auf.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Liest ein Byte über beide Felder eines als Wert übergebenen BankPtr. Der Deskriptor ergänzt die Banknummer, die einem gewöhnlichen Nahzeiger fehlt.
Syntax
u8 farptr_read8(BankPtr ptr);Parameter
ptrEin BankPtr-Wert mit den Feldern bank und ptr. Übergeben Sie den Deskriptor selbst, nicht seine Adresse. Der Deskriptor des Aufrufers bleibt unverändert.
Rückgabewert
Das gelesene Byte als u8 (0–255).
Bedingungen und Grenzen
Das gesamte Byte oder Wort muss in der gewählten CPU-Zuordnung lesbar sein. Zeiger werden nicht geprüft, Adressen nicht begrenzt und Fenstergrenzen lösen keinen automatischen Wechsel zur nächsten ROM-Bank aus. Ein Wort benötigt zwei gültige aufeinanderfolgende Bytes.
Fernlesezugriffe und Kopien arbeiten synchron und nutzen gemeinsamen Arbeitsspeicher des Compilers. Ein Interrupt darf währenddessen keinen weiteren Banktransfer über denselben Speicher ausführen. Auf GB nutzt die Kopierhilfe außerdem einen gemeinsamen HRAM-Platz für die gespeicherte Bank. Das Beispiel führt die Operationen aus festem Code ohne konkurrierenden Transfer-Handler aus.
Diese GB-Bankschnittstellen verwenden acht Bankbits und setzen das neunte MBC5-Bankbit nicht. Modulregeln, etwa die Behandlung von Bank null, gelten weiterhin. Das Beispiel nutzt ausdrücklich MBC5-Banken 1–3; mischen Sie diesen Zustand nicht mit unprotokollierten direkten Mapper-Schreibzugriffen.
Anwendungsbeispiel
bank_expect(farptr_read8(pointer)==0x7A,9);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieser Ausschnitt liest mit farptr_read8 den Ausdruck pointer.ptr in Bank 3 und prüft 7A. Das vollständige Programm bestätigt durch einen Nahzugriff auf home2 außerdem die Wiederherstellung von Bank 2.
Das vollständige Programm zeigt Datenzugriffe über Bank und Nahadresse, bankübergreifende Callbacks und den Unterschied zwischen Bibliothekszustand und tatsächlicher Zuordnung. Alle Zahlen sind hexadezimal. BANK IN und BANK OUT müssen 02 zeigen, BYTE HEX D3, WORD HEX 5C7A sowie FAILED CHECKS und FIRST FAILURE jeweils 00. CGB und FC zeigen blaue Schrift, DMG schwarze.
CALL COUNT zeigt 03: far_call, __farcall und __farcall_ptr rufen den Callback jeweils einmal auf.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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 — Weltkoordinaten und sichtbare Bereiche
Verwaltet Q8.8-Kamerapositionen, Ziele und Grenzen und rechnet Welt-/Bildschirmkoordinaten um. Wählen Sie eigene Camera8_8-Objekte oder die kleingeschriebene API für eine gemeinsame Kamera.
Camera_Add
Addiert Q8.8-Verschiebungen zur aktuellen Position und wendet danach aktivierte Grenzen an.
Syntax
void Camera_Add(Camera8_8* cam, s16 dfx, s16 dfy);Parameter
camGültiger Zeiger auf ein initialisiertes
Camera8_8, das dem aufrufenden Code gehört.dfxVorzeichenbehaftete Q8.8-Verschiebung; 256 entspricht einem Pixel.
dfyVorzeichenbehaftete Q8.8-Verschiebung; 256 entspricht einem Pixel.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Koordinaten haben acht Nachkommabits. Halten Sie Positionen, Ziele sowie Zwischensummen und -differenzen im Bereich von s16. Aktualisieren Sie die Anzeige getrennt mit Camera_ApplyBg oder durch Übertragen der gepufferten Werte.
Anwendungsbeispiel
Camera_Add(&cam,256,512);result[13]=cam.fx;result[14]=cam.fy;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel vermittelt Q8.8-Verfolgung, Begrenzung und Koordinatenumrechnung. Die Verfolgung ergibt X/Y=3584/4096; die Grenzen ergeben 3072/3584. BG X bleibt bei einer vorgemerkten Änderung 13 und wird nach der Übertragung 8. Das zusätzliche Bild zeigt, wie eine Kamera bei (8,16) ein 32×24-Weltrechteck von (32,32) an Bildschirmposition (24,16) bringt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Überträgt die aktuelle Position der gemeinsamen Kamera sofort auf die Hintergrundverschiebung.
Syntax
void camera_apply();Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Es wird nicht auf VBlank gewartet. Synchronisieren Sie im aufrufenden Code, wenn Änderungen innerhalb eines Frames unerwünscht sind. Negative Brüche werden abgerundet: −1/256 wird zu −1 Pixel, also zum Registerwert 255.
Anwendungsbeispiel
camera_apply();result[31]=M_SCX;result[32]=M_SCY;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel vermittelt Q8.8-Verfolgung, Begrenzung und Koordinatenumrechnung. Die Verfolgung ergibt X/Y=3584/4096; die Grenzen ergeben 3072/3584. BG X bleibt bei einer vorgemerkten Änderung 13 und wird nach der Übertragung 8. Das zusätzliche Bild zeigt, wie eine Kamera bei (8,16) ein 32×24-Weltrechteck von (32,32) an Bildschirmposition (24,16) bringt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Rundet die Kameraposition auf ganze Pixel ab und schreibt die unteren acht Bits sofort in die Hintergrund-Scrollregister.
Syntax
void Camera_ApplyBg(const Camera8_8* cam);Parameter
camGültiger Zeiger auf ein initialisiertes
Camera8_8, das dem aufrufenden Code gehört.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Es wird nicht auf VBlank gewartet. Synchronisieren Sie im aufrufenden Code, wenn Änderungen innerhalb eines Frames unerwünscht sind. Negative Brüche werden abgerundet: −1/256 wird zu −1 Pixel, also zum Registerwert 255.
Anwendungsbeispiel
Camera_ApplyBg(&cam);result[21]=M_SCX;result[22]=M_SCY;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel vermittelt Q8.8-Verfolgung, Begrenzung und Koordinatenumrechnung. Die Verfolgung ergibt X/Y=3584/4096; die Grenzen ergeben 3072/3584. BG X bleibt bei einer vorgemerkten Änderung 13 und wird nach der Übertragung 8. Das zusätzliche Bild zeigt, wie eine Kamera bei (8,16) ein 32×24-Weltrechteck von (32,32) an Bildschirmposition (24,16) bringt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Rundet die Kameraposition auf ganze Pixel ab und merkt sie als ausstehende Hintergrundverschiebung vor.
Syntax
void Camera_ApplyBgBuffered(const Camera8_8* cam);Parameter
camGültiger Zeiger auf ein initialisiertes
Camera8_8, das dem aufrufenden Code gehört.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Hardware und nachgeführte aktuelle Werte bleiben bis zu Scroll_Flush oder __scroll_flush unverändert. Dieser Aufruf wartet nicht auf VBlank.
Anwendungsbeispiel
Camera_Set(&cam,2048,4096);Camera_ApplyBgBuffered(&cam);result[23]=M_SCX;Scroll_Flush();result[24]=M_SCX;result[25]=M_SCY;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel vermittelt Q8.8-Verfolgung, Begrenzung und Koordinatenumrechnung. Die Verfolgung ergibt X/Y=3584/4096; die Grenzen ergeben 3072/3584. BG X bleibt bei einer vorgemerkten Änderung 13 und wird nach der Übertragung 8. Das zusätzliche Bild zeigt, wie eine Kamera bei (8,16) ein 32×24-Weltrechteck von (32,32) an Bildschirmposition (24,16) bringt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Wendet die aus Weltgröße minus Bildschirmgröße ermittelten Grenzen auf die gemeinsame Kamera an.
Syntax
void camera_clamp(u16 world_w_px, u16 world_h_px, u8 screen_w_px, u8 screen_h_px);Parameter
world_w_pxWeltgröße in ganzen Pixeln; der positive Überschuss gegenüber dem Bildschirm muss zwischen 0 und 127 liegen.
world_h_pxWeltgröße in ganzen Pixeln; der positive Überschuss gegenüber dem Bildschirm muss zwischen 0 und 127 liegen.
screen_w_pxGröße des sichtbaren Ausschnitts in ganzen Pixeln; ist er mindestens so groß wie die Welt, ist der Bewegungsspielraum auf dieser Achse null.
screen_h_pxGröße des sichtbaren Ausschnitts in ganzen Pixeln; ist er mindestens so groß wie die Welt, ist der Bewegungsspielraum auf dieser Achse null.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Ist die Welt kleiner als der sichtbare Ausschnitt, beträgt der Bewegungsspielraum null. Eine positive Differenz von mindestens 128 überschreitet bei der Umrechnung den vorzeichenbehafteten Q8.8-Bereich. Die u16-Parameter bedeuten nicht, dass die Kamera beliebig große Welten durchfahren kann. Diese Aufrufe teilen sich eine Kamera; verwenden Sie für unabhängige Kameraobjekte die mit Großbuchstaben beginnende API. Positionen, die von ganzen Pixeln nach Q8.8 umgerechnet werden, müssen zwischen −128 und 127 liegen.
Anwendungsbeispiel
camera_clamp(176,160,160,144);result[29]=camera_world_to_screen_x(100);result[30]=camera_world_to_screen_y(90);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel vermittelt Q8.8-Verfolgung, Begrenzung und Koordinatenumrechnung. Die Verfolgung ergibt X/Y=3584/4096; die Grenzen ergeben 3072/3584. BG X bleibt bei einer vorgemerkten Änderung 13 und wird nach der Übertragung 8. Das zusätzliche Bild zeigt, wie eine Kamera bei (8,16) ein 32×24-Weltrechteck von (32,32) an Bildschirmposition (24,16) bringt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Zieht die Bildschirmgröße von der Weltgröße ab und legt die daraus entstehenden nichtnegativen Kameragrenzen fest.
Syntax
void Camera_ClampToSize(Camera8_8* cam, u16 world_w_px, u16 world_h_px, u8 screen_w_px, u8 screen_h_px);Parameter
camGültiger Zeiger auf ein initialisiertes
Camera8_8, das dem aufrufenden Code gehört.world_w_pxWeltgröße in ganzen Pixeln; der positive Überschuss gegenüber dem Bildschirm muss zwischen 0 und 127 liegen.
world_h_pxWeltgröße in ganzen Pixeln; der positive Überschuss gegenüber dem Bildschirm muss zwischen 0 und 127 liegen.
screen_w_pxGröße des sichtbaren Ausschnitts in ganzen Pixeln; ist er mindestens so groß wie die Welt, ist der Bewegungsspielraum auf dieser Achse null.
screen_h_pxGröße des sichtbaren Ausschnitts in ganzen Pixeln; ist er mindestens so groß wie die Welt, ist der Bewegungsspielraum auf dieser Achse null.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Ist die Welt kleiner als der sichtbare Ausschnitt, beträgt der Bewegungsspielraum null. Eine positive Differenz von mindestens 128 überschreitet bei der Umrechnung den vorzeichenbehafteten Q8.8-Bereich. Die u16-Parameter bedeuten nicht, dass die Kamera beliebig große Welten durchfahren kann.
Anwendungsbeispiel
Camera_ClampToSize(&cam,176,160,160,144);result[15]=cam.max_fx;result[16]=cam.max_fy;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel vermittelt Q8.8-Verfolgung, Begrenzung und Koordinatenumrechnung. Die Verfolgung ergibt X/Y=3584/4096; die Grenzen ergeben 3072/3584. BG X bleibt bei einer vorgemerkten Änderung 13 und wird nach der Übertragung 8. Das zusätzliche Bild zeigt, wie eine Kamera bei (8,16) ein 32×24-Weltrechteck von (32,32) an Bildschirmposition (24,16) bringt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Deaktiviert die Begrenzung, ohne Position, Ziel oder gespeicherte Grenzen zu ändern.
Syntax
void Camera_ClearBounds(Camera8_8* cam);Parameter
camGültiger Zeiger auf ein initialisiertes
Camera8_8, das dem aufrufenden Code gehört.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Koordinaten haben acht Nachkommabits. Halten Sie Positionen, Ziele sowie Zwischensummen und -differenzen im Bereich von s16. Aktualisieren Sie die Anzeige getrennt mit Camera_ApplyBg oder durch Übertragen der gepufferten Werte.
Anwendungsbeispiel
Camera_ClearBounds(&cam);result[12]=cam.use_bounds;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel vermittelt Q8.8-Verfolgung, Begrenzung und Koordinatenumrechnung. Die Verfolgung ergibt X/Y=3584/4096; die Grenzen ergeben 3072/3584. BG X bleibt bei einer vorgemerkten Änderung 13 und wird nach der Übertragung 8. Das zusätzliche Bild zeigt, wie eine Kamera bei (8,16) ein 32×24-Weltrechteck von (32,32) an Bildschirmposition (24,16) bringt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Deaktiviert die Verfolgung und behält die aktuelle Position sowie das gespeicherte Ziel bei.
Syntax
void Camera_ClearTarget(Camera8_8* cam);Parameter
camGültiger Zeiger auf ein initialisiertes
Camera8_8, das dem aufrufenden Code gehört.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Koordinaten haben acht Nachkommabits. Halten Sie Positionen, Ziele sowie Zwischensummen und -differenzen im Bereich von s16. Aktualisieren Sie die Anzeige getrennt mit Camera_ApplyBg oder durch Übertragen der gepufferten Werte.
Anwendungsbeispiel
Camera_ClearTarget(&cam);result[8]=cam.use_target;result[9]=cam.target_fx;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel vermittelt Q8.8-Verfolgung, Begrenzung und Koordinatenumrechnung. Die Verfolgung ergibt X/Y=3584/4096; die Grenzen ergeben 3072/3584. BG X bleibt bei einer vorgemerkten Änderung 13 und wird nach der Übertragung 8. Das zusätzliche Bild zeigt, wie eine Kamera bei (8,16) ein 32×24-Weltrechteck von (32,32) an Bildschirmposition (24,16) bringt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Verschiebt die gemeinsame Kamera sofort so, dass ein Weltpunkt am gewünschten Bildschirmanker erscheint.
Syntax
void camera_follow_xy(s16 x, s16 y, u8 screen_cx, u8 screen_cy);Parameter
xWelt-X-Koordinate in ganzen Pixeln; Ergebnis und Zwischendifferenz müssen in
s16passen.yWelt-Y-Koordinate in ganzen Pixeln; Ergebnis und Zwischendifferenz müssen in
s16passen.screen_cxKoordinate des Bildschirmankers in ganzen Pixeln, 0–255.
screen_cyKoordinate des Bildschirmankers in ganzen Pixeln, 0–255.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Koordinaten haben acht Nachkommabits. Halten Sie Positionen, Ziele sowie Zwischensummen und -differenzen im Bereich von s16. Aktualisieren Sie die Anzeige getrennt mit Camera_ApplyBg oder durch Übertragen der gepufferten Werte. Diese Aufrufe teilen sich eine Kamera; verwenden Sie für unabhängige Kameraobjekte die mit Großbuchstaben beginnende API. Positionen, die von ganzen Pixeln nach Q8.8 umgerechnet werden, müssen zwischen −128 und 127 liegen.
Anwendungsbeispiel
camera_follow_xy(100,90,80,72);result[27]=camera_world_to_screen_x(100);result[28]=camera_world_to_screen_y(90);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel vermittelt Q8.8-Verfolgung, Begrenzung und Koordinatenumrechnung. Die Verfolgung ergibt X/Y=3584/4096; die Grenzen ergeben 3072/3584. BG X bleibt bei einer vorgemerkten Änderung 13 und wird nach der Übertragung 8. Das zusätzliche Bild zeigt, wie eine Kamera bei (8,16) ein 32×24-Weltrechteck von (32,32) an Bildschirmposition (24,16) bringt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Setzt Position, Ziel und Grenzen auf null und deaktiviert Verfolgung und Begrenzung.
Syntax
void Camera_Init(Camera8_8* cam);Parameter
camZu initialisierendes, beschreibbares
Camera8_8; darf nicht NULL sein.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Koordinaten haben acht Nachkommabits. Halten Sie Positionen, Ziele sowie Zwischensummen und -differenzen im Bereich von s16. Aktualisieren Sie die Anzeige getrennt mit Camera_ApplyBg oder durch Übertragen der gepufferten Werte.
Anwendungsbeispiel
Camera_Init(&cam);result[0]=cam.fx;result[1]=cam.use_target;result[2]=cam.use_bounds;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel vermittelt Q8.8-Verfolgung, Begrenzung und Koordinatenumrechnung. Die Verfolgung ergibt X/Y=3584/4096; die Grenzen ergeben 3072/3584. BG X bleibt bei einer vorgemerkten Änderung 13 und wird nach der Übertragung 8. Das zusätzliche Bild zeigt, wie eine Kamera bei (8,16) ein 32×24-Weltrechteck von (32,32) an Bildschirmposition (24,16) bringt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Addiert den ganzzahligen X-Anteil der Kamera zu Bildschirm-X und erhält so Welt-X.
Syntax
s16 Camera_ScreenToWorldX(const Camera8_8* cam, s16 screen_x);Parameter
camGültiger Zeiger auf ein initialisiertes
Camera8_8, das dem aufrufenden Code gehört.screen_xBildschirm-X-Koordinate in ganzen Pixeln; Ergebnis und Zwischendifferenz müssen in
s16passen.
Rückgabewert
Gibt die umgerechnete ganzzahlige Pixelkoordinate als s16 zurück; prüft weder die Sichtbarkeit noch beschneidet sie den Wert.
Bedingungen und Grenzen
Koordinaten haben acht Nachkommabits. Halten Sie Positionen, Ziele sowie Zwischensummen und -differenzen im Bereich von s16. Aktualisieren Sie die Anzeige getrennt mit Camera_ApplyBg oder durch Übertragen der gepufferten Werte.
Anwendungsbeispiel
result[19]=Camera_ScreenToWorldX(&cam,27);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel vermittelt Q8.8-Verfolgung, Begrenzung und Koordinatenumrechnung. Die Verfolgung ergibt X/Y=3584/4096; die Grenzen ergeben 3072/3584. BG X bleibt bei einer vorgemerkten Änderung 13 und wird nach der Übertragung 8. Das zusätzliche Bild zeigt, wie eine Kamera bei (8,16) ein 32×24-Weltrechteck von (32,32) an Bildschirmposition (24,16) bringt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Addiert den ganzzahligen Y-Anteil der Kamera zu Bildschirm-Y und erhält so Welt-Y.
Syntax
s16 Camera_ScreenToWorldY(const Camera8_8* cam, s16 screen_y);Parameter
camGültiger Zeiger auf ein initialisiertes
Camera8_8, das dem aufrufenden Code gehört.screen_yBildschirm-Y-Koordinate in ganzen Pixeln; Ergebnis und Zwischendifferenz müssen in
s16passen.
Rückgabewert
Gibt die umgerechnete ganzzahlige Pixelkoordinate als s16 zurück; prüft weder die Sichtbarkeit noch beschneidet sie den Wert.
Bedingungen und Grenzen
Koordinaten haben acht Nachkommabits. Halten Sie Positionen, Ziele sowie Zwischensummen und -differenzen im Bereich von s16. Aktualisieren Sie die Anzeige getrennt mit Camera_ApplyBg oder durch Übertragen der gepufferten Werte.
Anwendungsbeispiel
result[20]=Camera_ScreenToWorldY(&cam,24);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel vermittelt Q8.8-Verfolgung, Begrenzung und Koordinatenumrechnung. Die Verfolgung ergibt X/Y=3584/4096; die Grenzen ergeben 3072/3584. BG X bleibt bei einer vorgemerkten Änderung 13 und wird nach der Übertragung 8. Das zusätzliche Bild zeigt, wie eine Kamera bei (8,16) ein 32×24-Weltrechteck von (32,32) an Bildschirmposition (24,16) bringt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Ersetzt die aktuelle Kameraposition und begrenzt sie sofort auf gegebenenfalls aktivierte Grenzen.
Syntax
void Camera_Set(Camera8_8* cam, s16 fx, s16 fy);Parameter
camGültiger Zeiger auf ein initialisiertes
Camera8_8, das dem aufrufenden Code gehört.fxX-Koordinate. Vorzeichenbehaftete Q8.8-Koordinate: 256 entspricht einem Pixel; der Bereich reicht von −128 bis 127+255/256 Pixel.
fyY-Koordinate. Vorzeichenbehaftete Q8.8-Koordinate: 256 entspricht einem Pixel; der Bereich reicht von −128 bis 127+255/256 Pixel.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Koordinaten haben acht Nachkommabits. Halten Sie Positionen, Ziele sowie Zwischensummen und -differenzen im Bereich von s16. Aktualisieren Sie die Anzeige getrennt mit Camera_ApplyBg oder durch Übertragen der gepufferten Werte.
Anwendungsbeispiel
Camera_Set(&cam,2560,5120);result[3]=cam.fx;result[4]=cam.fy;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel vermittelt Q8.8-Verfolgung, Begrenzung und Koordinatenumrechnung. Die Verfolgung ergibt X/Y=3584/4096; die Grenzen ergeben 3072/3584. BG X bleibt bei einer vorgemerkten Änderung 13 und wird nach der Übertragung 8. Das zusätzliche Bild zeigt, wie eine Kamera bei (8,16) ein 32×24-Weltrechteck von (32,32) an Bildschirmposition (24,16) bringt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Verschiebt die gemeinsame Kamera anhand ganzzahliger Pixelkoordinaten und wendet ihre aktivierten Grenzen an.
Syntax
void camera_set(s16 x, s16 y);Parameter
xWelt-X-Koordinate in ganzen Pixeln; Ergebnis und Zwischendifferenz müssen in
s16passen.yWelt-Y-Koordinate in ganzen Pixeln; Ergebnis und Zwischendifferenz müssen in
s16passen.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Koordinaten haben acht Nachkommabits. Halten Sie Positionen, Ziele sowie Zwischensummen und -differenzen im Bereich von s16. Aktualisieren Sie die Anzeige getrennt mit Camera_ApplyBg oder durch Übertragen der gepufferten Werte. Diese Aufrufe teilen sich eine Kamera; verwenden Sie für unabhängige Kameraobjekte die mit Großbuchstaben beginnende API. Positionen, die von ganzen Pixeln nach Q8.8 umgerechnet werden, müssen zwischen −128 und 127 liegen.
Anwendungsbeispiel
camera_set(5,6);result[26]=camera_world_to_screen_x(20);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel vermittelt Q8.8-Verfolgung, Begrenzung und Koordinatenumrechnung. Die Verfolgung ergibt X/Y=3584/4096; die Grenzen ergeben 3072/3584. BG X bleibt bei einer vorgemerkten Änderung 13 und wird nach der Übertragung 8. Das zusätzliche Bild zeigt, wie eine Kamera bei (8,16) ein 32×24-Weltrechteck von (32,32) an Bildschirmposition (24,16) bringt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Legt die Mindest- und Höchstkoordinaten fest, aktiviert die Begrenzung und begrenzt sofort die aktuelle Position.
Syntax
void Camera_SetBounds(Camera8_8* cam, s16 min_fx, s16 min_fy, s16 max_fx, s16 max_fy);Parameter
camGültiger Zeiger auf ein initialisiertes
Camera8_8, das dem aufrufenden Code gehört.min_fxKleinste X-Koordinate. Vorzeichenbehaftete Q8.8-Koordinate: 256 entspricht einem Pixel; der Bereich reicht von −128 bis 127+255/256 Pixel.
min_fyKleinste Y-Koordinate. Vorzeichenbehaftete Q8.8-Koordinate: 256 entspricht einem Pixel; der Bereich reicht von −128 bis 127+255/256 Pixel.
max_fxGrößte X-Koordinate. Vorzeichenbehaftete Q8.8-Koordinate: 256 entspricht einem Pixel; der Bereich reicht von −128 bis 127+255/256 Pixel.
max_fyGrößte Y-Koordinate. Vorzeichenbehaftete Q8.8-Koordinate: 256 entspricht einem Pixel; der Bereich reicht von −128 bis 127+255/256 Pixel.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Übergeben Sie je Achse Minimum ≤ Maximum; die Grenzen werden nicht umgeordnet. Das gespeicherte Ziel wird nicht begrenzt.
Anwendungsbeispiel
Camera_SetBounds(&cam,0,0,3072,3584);result[10]=cam.fx;result[11]=cam.fy;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel vermittelt Q8.8-Verfolgung, Begrenzung und Koordinatenumrechnung. Die Verfolgung ergibt X/Y=3584/4096; die Grenzen ergeben 3072/3584. BG X bleibt bei einer vorgemerkten Änderung 13 und wird nach der Übertragung 8. Das zusätzliche Bild zeigt, wie eine Kamera bei (8,16) ein 32×24-Weltrechteck von (32,32) an Bildschirmposition (24,16) bringt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Speichert ein Ziel und aktiviert die Verfolgung, ohne die aktuelle Position zu verschieben.
Syntax
void Camera_SetTarget(Camera8_8* cam, s16 fx, s16 fy);Parameter
camGültiger Zeiger auf ein initialisiertes
Camera8_8, das dem aufrufenden Code gehört.fxX-Koordinate. Vorzeichenbehaftete Q8.8-Koordinate: 256 entspricht einem Pixel; der Bereich reicht von −128 bis 127+255/256 Pixel.
fyY-Koordinate. Vorzeichenbehaftete Q8.8-Koordinate: 256 entspricht einem Pixel; der Bereich reicht von −128 bis 127+255/256 Pixel.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Koordinaten haben acht Nachkommabits. Halten Sie Positionen, Ziele sowie Zwischensummen und -differenzen im Bereich von s16. Aktualisieren Sie die Anzeige getrennt mit Camera_ApplyBg oder durch Übertragen der gepufferten Werte.
Anwendungsbeispiel
Camera_SetTarget(&cam,4608,3072);result[5]=cam.use_target;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel vermittelt Q8.8-Verfolgung, Begrenzung und Koordinatenumrechnung. Die Verfolgung ergibt X/Y=3584/4096; die Grenzen ergeben 3072/3584. BG X bleibt bei einer vorgemerkten Änderung 13 und wird nach der Übertragung 8. Das zusätzliche Bild zeigt, wie eine Kamera bei (8,16) ein 32×24-Weltrechteck von (32,32) an Bildschirmposition (24,16) bringt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Nähert sich dem Ziel um einen durch Rechtsschieben bestimmten Anteil der Reststrecke; bei deaktivierter Verfolgung geschieht nichts.
Syntax
void Camera_StepTowardTarget(Camera8_8* cam, u8 shift);Parameter
camGültiger Zeiger auf ein initialisiertes
Camera8_8, das dem aufrufenden Code gehört.shiftExponent der Zweierpotenz, durch die die Differenz geteilt wird: 0 verwendet die ganze Differenz, 1 die Hälfte. Werte über 7 werden auf 7 begrenzt.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Eine kleine positive Differenz kann auf null abgeschnitten werden; ein arithmetischer Rechtsshift kann eine kleine negative Differenz zu −1 machen. Die Gleichheit mit dem Ziel wird vor der Begrenzung geprüft. Ein Ziel außerhalb der Grenzen kann die Verfolgung daher aktiv halten oder sie beenden, obwohl die endgültige begrenzte Position vom Ziel abweicht.
Anwendungsbeispiel
Camera_StepTowardTarget(&cam,1);result[6]=cam.fx;result[7]=cam.fy;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel vermittelt Q8.8-Verfolgung, Begrenzung und Koordinatenumrechnung. Die Verfolgung ergibt X/Y=3584/4096; die Grenzen ergeben 3072/3584. BG X bleibt bei einer vorgemerkten Änderung 13 und wird nach der Übertragung 8. Das zusätzliche Bild zeigt, wie eine Kamera bei (8,16) ein 32×24-Weltrechteck von (32,32) an Bildschirmposition (24,16) bringt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Wandelt Welt-X in Bildschirm-X um, indem der ganzzahlige X-Anteil der gemeinsamen Kamera abgezogen wird.
Syntax
s16 camera_world_to_screen_x(s16 world_x);Parameter
world_xWelt-X-Koordinate in ganzen Pixeln; Ergebnis und Zwischendifferenz müssen in
s16passen.
Rückgabewert
Gibt die umgerechnete ganzzahlige Pixelkoordinate als s16 zurück; prüft weder die Sichtbarkeit noch beschneidet sie den Wert.
Bedingungen und Grenzen
Koordinaten haben acht Nachkommabits. Halten Sie Positionen, Ziele sowie Zwischensummen und -differenzen im Bereich von s16. Aktualisieren Sie die Anzeige getrennt mit Camera_ApplyBg oder durch Übertragen der gepufferten Werte. Diese Aufrufe teilen sich eine Kamera; verwenden Sie für unabhängige Kameraobjekte die mit Großbuchstaben beginnende API. Positionen, die von ganzen Pixeln nach Q8.8 umgerechnet werden, müssen zwischen −128 und 127 liegen.
Anwendungsbeispiel
result[33]=camera_world_to_screen_x(20);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel vermittelt Q8.8-Verfolgung, Begrenzung und Koordinatenumrechnung. Die Verfolgung ergibt X/Y=3584/4096; die Grenzen ergeben 3072/3584. BG X bleibt bei einer vorgemerkten Änderung 13 und wird nach der Übertragung 8. Das zusätzliche Bild zeigt, wie eine Kamera bei (8,16) ein 32×24-Weltrechteck von (32,32) an Bildschirmposition (24,16) bringt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Wandelt Welt-Y in Bildschirm-Y um, indem der ganzzahlige Y-Anteil der gemeinsamen Kamera abgezogen wird.
Syntax
s16 camera_world_to_screen_y(s16 world_y);Parameter
world_yWelt-Y-Koordinate in ganzen Pixeln; Ergebnis und Zwischendifferenz müssen in
s16passen.
Rückgabewert
Gibt die umgerechnete ganzzahlige Pixelkoordinate als s16 zurück; prüft weder die Sichtbarkeit noch beschneidet sie den Wert.
Bedingungen und Grenzen
Koordinaten haben acht Nachkommabits. Halten Sie Positionen, Ziele sowie Zwischensummen und -differenzen im Bereich von s16. Aktualisieren Sie die Anzeige getrennt mit Camera_ApplyBg oder durch Übertragen der gepufferten Werte. Diese Aufrufe teilen sich eine Kamera; verwenden Sie für unabhängige Kameraobjekte die mit Großbuchstaben beginnende API. Positionen, die von ganzen Pixeln nach Q8.8 umgerechnet werden, müssen zwischen −128 und 127 liegen.
Anwendungsbeispiel
result[34]=camera_world_to_screen_y(20);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel vermittelt Q8.8-Verfolgung, Begrenzung und Koordinatenumrechnung. Die Verfolgung ergibt X/Y=3584/4096; die Grenzen ergeben 3072/3584. BG X bleibt bei einer vorgemerkten Änderung 13 und wird nach der Übertragung 8. Das zusätzliche Bild zeigt, wie eine Kamera bei (8,16) ein 32×24-Weltrechteck von (32,32) an Bildschirmposition (24,16) bringt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Zieht den ganzzahligen X-Anteil der Kamera von einer ganzzahligen Welt-X-Koordinate ab und liefert so Bildschirm-X.
Syntax
s16 Camera_WorldToScreenX(const Camera8_8* cam, s16 world_x);Parameter
camGültiger Zeiger auf ein initialisiertes
Camera8_8, das dem aufrufenden Code gehört.world_xWelt-X-Koordinate in ganzen Pixeln; Ergebnis und Zwischendifferenz müssen in
s16passen.
Rückgabewert
Gibt die umgerechnete ganzzahlige Pixelkoordinate als s16 zurück; prüft weder die Sichtbarkeit noch beschneidet sie den Wert.
Bedingungen und Grenzen
Koordinaten haben acht Nachkommabits. Halten Sie Positionen, Ziele sowie Zwischensummen und -differenzen im Bereich von s16. Aktualisieren Sie die Anzeige getrennt mit Camera_ApplyBg oder durch Übertragen der gepufferten Werte.
Anwendungsbeispiel
result[17]=Camera_WorldToScreenX(&cam,40);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel vermittelt Q8.8-Verfolgung, Begrenzung und Koordinatenumrechnung. Die Verfolgung ergibt X/Y=3584/4096; die Grenzen ergeben 3072/3584. BG X bleibt bei einer vorgemerkten Änderung 13 und wird nach der Übertragung 8. Das zusätzliche Bild zeigt, wie eine Kamera bei (8,16) ein 32×24-Weltrechteck von (32,32) an Bildschirmposition (24,16) bringt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Zieht den ganzzahligen Y-Anteil der Kamera von einer ganzzahligen Welt-Y-Koordinate ab und liefert so Bildschirm-Y.
Syntax
s16 Camera_WorldToScreenY(const Camera8_8* cam, s16 world_y);Parameter
camGültiger Zeiger auf ein initialisiertes
Camera8_8, das dem aufrufenden Code gehört.world_yWelt-Y-Koordinate in ganzen Pixeln; Ergebnis und Zwischendifferenz müssen in
s16passen.
Rückgabewert
Gibt die umgerechnete ganzzahlige Pixelkoordinate als s16 zurück; prüft weder die Sichtbarkeit noch beschneidet sie den Wert.
Bedingungen und Grenzen
Koordinaten haben acht Nachkommabits. Halten Sie Positionen, Ziele sowie Zwischensummen und -differenzen im Bereich von s16. Aktualisieren Sie die Anzeige getrennt mit Camera_ApplyBg oder durch Übertragen der gepufferten Werte.
Anwendungsbeispiel
result[18]=Camera_WorldToScreenY(&cam,40);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel vermittelt Q8.8-Verfolgung, Begrenzung und Koordinatenumrechnung. Die Verfolgung ergibt X/Y=3584/4096; die Grenzen ergeben 3072/3584. BG X bleibt bei einer vorgemerkten Änderung 13 und wird nach der Übertragung 8. Das zusätzliche Bild zeigt, wie eine Kamera bei (8,16) ein 32×24-Weltrechteck von (32,32) an Bildschirmposition (24,16) bringt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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-Paletten für BG und OBJ
cgb_palette.h und cgb_palette.c bieten RGB15-Packung und sofortige CGB-Palettenaktualisierung. BG-Funktionen dienen Hintergrund/Fenster, OBJ-Funktionen den Sprites. Einzel- und Komponentenfunktionen ändern eine Farbe, Bereichsfunktionen aufeinanderfolgende Wörter, Ganzpalettenfunktionen vier Wörter. Raw-Bereiche verwenden absolute Farbplätze, Registerintrinsics Bytepositionen. Die Palettenzuweisung erfolgt getrennt über Kartenattribute oder OAM. Binden Sie die Implementierung wie im vollständigen Beispiel genau einmal ein.
Paletten- und geschützte Registerschreibzugriffe schreiben im DMG-Modus nichts. Safe bedeutet hier eine CGB-Modusprüfung, keine PPU-Zugriffswarteschleife und keinen kritischen Abschnitt. Verwenden Sie die Funktionen bei ausgeschaltetem LCD oder für kurze Aktualisierungen innerhalb einer zugänglichen PPU-Phase. Sie warten nicht auf VBlank und schützen mehrbyteige Updates nicht vor Interrupts.
BG-/Fenster- und OBJ-Paletten haben getrennte Speicher. Bibliothekszugriffe aktivieren die Indexerhöhung und lassen das Indexregister verändert. OBJ-Farbindex null ist beim Zeichnen von Sprites transparent, obwohl seine Bytes gespeichert und gelesen werden können.
cgb_bg_color
Die lokalen Unterschiede dieser API stehen bei den Änderungen und Prüfungen vom 2026-10-03.
Schreibt sofort einen gepackten RGB15-Farbwert in den Palettenspeicher für Hintergrund/Fenster. Paletten- und Farbindex wählen einen von 32 Farbplätzen aus; Kachelmuster und die einer Kachel zugewiesene Palette bleiben dabei unverändert.
Syntax
void cgb_bg_color(u8 palette_index, u8 color_index, u16 rgb15);Parameter
palette_indexPalettennummer 0–7; nur die unteren drei Bits werden verwendet (
& 7).color_indexFarbindex innerhalb der Palette, 0–3; nur die unteren zwei Bits werden verwendet (
& 3).rgb15Gepackte 15-Bit-RGB-Farbe, gewöhnlich 0–32767. Beide Bytes des
u16werden geschrieben, das niederwertige zuerst; die Bibliothek löscht Bit 15 nicht ausdrücklich. Erzeugen Sie gültige Werte mitCGB_RGB15odercgb_rgb15.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Paletten- und geschützte Registerschreibzugriffe schreiben im DMG-Modus nichts. Safe bedeutet hier eine CGB-Modusprüfung, keine PPU-Zugriffswarteschleife und keinen kritischen Abschnitt. Verwenden Sie die Funktionen bei ausgeschaltetem LCD oder für kurze Aktualisierungen innerhalb einer zugänglichen PPU-Phase. Sie warten nicht auf VBlank und schützen mehrbyteige Updates nicht vor Interrupts.
BG-/Fenster- und OBJ-Paletten haben getrennte Speicher. Bibliothekszugriffe aktivieren die Indexerhöhung und lassen das Indexregister verändert. OBJ-Farbindex null ist beim Zeichnen von Sprites transparent, obwohl seine Bytes gespeichert und gelesen werden können.
Anwendungsbeispiel
cgb_bg_color(1,3,31); // Red background color 3 of palette 1.
expect_color(0,7,31);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Programm zeigt, wie BG- und OBJ-Paletten dasselbe Muster unabhängig einfärben. Jedes Dreieck ist 8 × 8 Pixel groß: oben ein Pixel links, unten eine volle Zeile. Bei x = 16, 32, 48, 64, 80, 96, 112 ist die BG-Reihe bei y = 24 rot, blau, grün, rot, blau, grün, rot; die OBJ-Reihe bei y = 64 ist blau, grün, rot, blau, grün, rot, blau. Die Spalten verwenden der Reihe nach Einzelfarbe, Komponenten, indizierten Bereich, ganze Palette, absoluten Bereich, kanonischen Registernamen und Registeralias.
Bei y = 88 zeigen sieben 8 × 8-Felder: rotes Dreieck (x = 16), blauen quadratischen Rahmen mit einem Pixel Strichstärke aus Bank 1 (32), horizontal gespiegeltes grünes Dreieck (48), vertikal gespiegeltes rotes Dreieck (64), in beiden Richtungen gespiegeltes blaues Dreieck (80), grünes Dreieck vor einem roten Sprite, das durch Farbindex null sichtbar bleibt (96), sowie ein volles rotes Sprite vor dem BG-Dreieck als Kontrolle ohne BG-Priorität (112). Koordinaten in Pixeln ab der linken oberen Ecke; weiße Freiflächen und schwarzer Text.
FAILED CHECKS 000 bestätigt RGB-Masken, Wahrheitsflags einschließlich Wert 2, normalisierte Palettenindizes, palettenübergreifende Zugriffe, Begrenzung bei Platz 31, Nullzeiger/Nullängen ohne Schreibzugriff und Farbrücklesen bei ausgeschaltetem LCD. Vier Kombinationen werden geprüft: duales ROM auf DMG/CGB, reines DMG-ROM auf DMG und reines CGB-ROM auf CGB. Auf DMG ist CGB MODE 0, Dreiecke sind schwarz, Bank-/Spiegelattribute ändern die Anzeige nicht und die letzten beiden unteren Felder sind schwarze Quadrate. Auf CGB ist CGB MODE 1. Echte Hardware und Palettenzugriffskonflikte bei eingeschaltetem LCD sind nicht geprüft.




Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Schreibt aufeinanderfolgende RGB15-Wörter in den Palettenspeicher für Hintergrund/Fenster, beginnend bei den angegebenen Paletten- und Farbindizes. Die Folge darf eine Vierfarbenpalette überschreiten, endet aber spätestens am Ende der 32 Farbplätze.
Syntax
void cgb_bg_colors(u8 palette_index, u8 start_color_index, const u16* colors, u8 color_count);Parameter
palette_indexPalettennummer 0–7; nur die unteren drei Bits werden verwendet (
& 7).start_color_indexFarbindex innerhalb der Palette, 0–3; nur die unteren zwei Bits werden verwendet (
& 3).colorsLesbarer
const u16*mit den benötigten Farbwörtern. Die Daten werden während des Aufrufs gelesen, nicht eingereiht. Quelle und ROM-Bank müssen erreichbar bleiben; es erfolgt kein automatischer Bankwechsel. Ein Nullzeiger bewirkt keine Schreibzugriffe.color_countAnzahl der Farbwörter, nicht Bytes, als
u8(0–255). Null bewirkt nichts. Begrenzt auf32 - normalisierter_Startplatz; nur entsprechend viele Quellwörter werden gelesen.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Paletten- und geschützte Registerschreibzugriffe schreiben im DMG-Modus nichts. Safe bedeutet hier eine CGB-Modusprüfung, keine PPU-Zugriffswarteschleife und keinen kritischen Abschnitt. Verwenden Sie die Funktionen bei ausgeschaltetem LCD oder für kurze Aktualisierungen innerhalb einer zugänglichen PPU-Phase. Sie warten nicht auf VBlank und schützen mehrbyteige Updates nicht vor Interrupts.
BG-/Fenster- und OBJ-Paletten haben getrennte Speicher. Bibliothekszugriffe aktivieren die Indexerhöhung und lassen das Indexregister verändert. OBJ-Farbindex null ist beim Zeichnen von Sprites transparent, obwohl seine Bytes gespeichert und gelesen werden können.
Anwendungsbeispiel
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);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Programm zeigt, wie BG- und OBJ-Paletten dasselbe Muster unabhängig einfärben. Jedes Dreieck ist 8 × 8 Pixel groß: oben ein Pixel links, unten eine volle Zeile. Bei x = 16, 32, 48, 64, 80, 96, 112 ist die BG-Reihe bei y = 24 rot, blau, grün, rot, blau, grün, rot; die OBJ-Reihe bei y = 64 ist blau, grün, rot, blau, grün, rot, blau. Die Spalten verwenden der Reihe nach Einzelfarbe, Komponenten, indizierten Bereich, ganze Palette, absoluten Bereich, kanonischen Registernamen und Registeralias.
Bei y = 88 zeigen sieben 8 × 8-Felder: rotes Dreieck (x = 16), blauen quadratischen Rahmen mit einem Pixel Strichstärke aus Bank 1 (32), horizontal gespiegeltes grünes Dreieck (48), vertikal gespiegeltes rotes Dreieck (64), in beiden Richtungen gespiegeltes blaues Dreieck (80), grünes Dreieck vor einem roten Sprite, das durch Farbindex null sichtbar bleibt (96), sowie ein volles rotes Sprite vor dem BG-Dreieck als Kontrolle ohne BG-Priorität (112). Koordinaten in Pixeln ab der linken oberen Ecke; weiße Freiflächen und schwarzer Text.
FAILED CHECKS 000 bestätigt RGB-Masken, Wahrheitsflags einschließlich Wert 2, normalisierte Palettenindizes, palettenübergreifende Zugriffe, Begrenzung bei Platz 31, Nullzeiger/Nullängen ohne Schreibzugriff und Farbrücklesen bei ausgeschaltetem LCD. Vier Kombinationen werden geprüft: duales ROM auf DMG/CGB, reines DMG-ROM auf DMG und reines CGB-ROM auf CGB. Auf DMG ist CGB MODE 0, Dreiecke sind schwarz, Bank-/Spiegelattribute ändern die Anzeige nicht und die letzten beiden unteren Felder sind schwarze Quadrate. Auf CGB ist CGB MODE 1. Echte Hardware und Palettenzugriffskonflikte bei eingeschaltetem LCD sind nicht geprüft.




Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Schreibt aufeinanderfolgende RGB15-Wörter in den Palettenspeicher für Hintergrund/Fenster, ausgehend von einem absoluten Farbplatz. Der Start ist ein einzelner Index von 0 bis 31 statt eines Paletten-/Farbindexpaares. Die Daten sind Farbwörter, keine Musterbytes.
Syntax
void cgb_bg_colors_raw(u8 start_color_slot, const u16* colors, u8 color_count);Parameter
start_color_slotAbsoluter Farbplatz 0–31, vor der Längenbegrenzung mit
& 31normalisiert. Farbplatz = Palette × 4 + Farbe; kein Byteoffset.colorsLesbarer
const u16*mit den benötigten Farbwörtern. Die Daten werden während des Aufrufs gelesen, nicht eingereiht. Quelle und ROM-Bank müssen erreichbar bleiben; es erfolgt kein automatischer Bankwechsel. Ein Nullzeiger bewirkt keine Schreibzugriffe.color_countAnzahl der Farbwörter, nicht Bytes, als
u8(0–255). Null bewirkt nichts. Begrenzt auf32 - normalisierter_Startplatz; nur entsprechend viele Quellwörter werden gelesen.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Paletten- und geschützte Registerschreibzugriffe schreiben im DMG-Modus nichts. Safe bedeutet hier eine CGB-Modusprüfung, keine PPU-Zugriffswarteschleife und keinen kritischen Abschnitt. Verwenden Sie die Funktionen bei ausgeschaltetem LCD oder für kurze Aktualisierungen innerhalb einer zugänglichen PPU-Phase. Sie warten nicht auf VBlank und schützen mehrbyteige Updates nicht vor Interrupts.
BG-/Fenster- und OBJ-Paletten haben getrennte Speicher. Bibliothekszugriffe aktivieren die Indexerhöhung und lassen das Indexregister verändert. OBJ-Farbindex null ist beim Zeichnen von Sprites transparent, obwohl seine Bytes gespeichert und gelesen werden können.
Anwendungsbeispiel
cgb_bg_colors_raw(23,blue_word,1); // Absolute slot 23 = palette 5, color 3.
expect_color(0,23,31744);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Programm zeigt, wie BG- und OBJ-Paletten dasselbe Muster unabhängig einfärben. Jedes Dreieck ist 8 × 8 Pixel groß: oben ein Pixel links, unten eine volle Zeile. Bei x = 16, 32, 48, 64, 80, 96, 112 ist die BG-Reihe bei y = 24 rot, blau, grün, rot, blau, grün, rot; die OBJ-Reihe bei y = 64 ist blau, grün, rot, blau, grün, rot, blau. Die Spalten verwenden der Reihe nach Einzelfarbe, Komponenten, indizierten Bereich, ganze Palette, absoluten Bereich, kanonischen Registernamen und Registeralias.
Bei y = 88 zeigen sieben 8 × 8-Felder: rotes Dreieck (x = 16), blauen quadratischen Rahmen mit einem Pixel Strichstärke aus Bank 1 (32), horizontal gespiegeltes grünes Dreieck (48), vertikal gespiegeltes rotes Dreieck (64), in beiden Richtungen gespiegeltes blaues Dreieck (80), grünes Dreieck vor einem roten Sprite, das durch Farbindex null sichtbar bleibt (96), sowie ein volles rotes Sprite vor dem BG-Dreieck als Kontrolle ohne BG-Priorität (112). Koordinaten in Pixeln ab der linken oberen Ecke; weiße Freiflächen und schwarzer Text.
FAILED CHECKS 000 bestätigt RGB-Masken, Wahrheitsflags einschließlich Wert 2, normalisierte Palettenindizes, palettenübergreifende Zugriffe, Begrenzung bei Platz 31, Nullzeiger/Nullängen ohne Schreibzugriff und Farbrücklesen bei ausgeschaltetem LCD. Vier Kombinationen werden geprüft: duales ROM auf DMG/CGB, reines DMG-ROM auf DMG und reines CGB-ROM auf CGB. Auf DMG ist CGB MODE 0, Dreiecke sind schwarz, Bank-/Spiegelattribute ändern die Anzeige nicht und die letzten beiden unteren Felder sind schwarze Quadrate. Auf CGB ist CGB MODE 1. Echte Hardware und Palettenzugriffskonflikte bei eingeschaltetem LCD sind nicht geprüft.




Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Ersetzt alle vier Farben einer Palette für Hintergrund/Fenster durch vier RGB15-Wörter. Entspricht einem Bereichsschreibvorgang ab Farbe null mit Anzahl vier; weist die Palette keiner Kachel und keinem Sprite zu.
Syntax
void cgb_bg_palette(u8 palette_index, const u16* colors);Parameter
palette_indexPalettennummer 0–7; nur die unteren drei Bits werden verwendet (
& 7).colorsLesbarer
const u16*mit den benötigten Farbwörtern. Die Daten werden während des Aufrufs gelesen, nicht eingereiht. Quelle und ROM-Bank müssen erreichbar bleiben; es erfolgt kein automatischer Bankwechsel. Ein Nullzeiger bewirkt keine Schreibzugriffe.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Paletten- und geschützte Registerschreibzugriffe schreiben im DMG-Modus nichts. Safe bedeutet hier eine CGB-Modusprüfung, keine PPU-Zugriffswarteschleife und keinen kritischen Abschnitt. Verwenden Sie die Funktionen bei ausgeschaltetem LCD oder für kurze Aktualisierungen innerhalb einer zugänglichen PPU-Phase. Sie warten nicht auf VBlank und schützen mehrbyteige Updates nicht vor Interrupts.
BG-/Fenster- und OBJ-Paletten haben getrennte Speicher. Bibliothekszugriffe aktivieren die Indexerhöhung und lassen das Indexregister verändert. OBJ-Farbindex null ist beim Zeichnen von Sprites transparent, obwohl seine Bytes gespeichert und gelesen werden können.
Anwendungsbeispiel
cgb_bg_palette(4,red_palette); // Exactly four color words for BG palette 4.
expect_color(0,16,32767); expect_color(0,19,31);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Programm zeigt, wie BG- und OBJ-Paletten dasselbe Muster unabhängig einfärben. Jedes Dreieck ist 8 × 8 Pixel groß: oben ein Pixel links, unten eine volle Zeile. Bei x = 16, 32, 48, 64, 80, 96, 112 ist die BG-Reihe bei y = 24 rot, blau, grün, rot, blau, grün, rot; die OBJ-Reihe bei y = 64 ist blau, grün, rot, blau, grün, rot, blau. Die Spalten verwenden der Reihe nach Einzelfarbe, Komponenten, indizierten Bereich, ganze Palette, absoluten Bereich, kanonischen Registernamen und Registeralias.
Bei y = 88 zeigen sieben 8 × 8-Felder: rotes Dreieck (x = 16), blauen quadratischen Rahmen mit einem Pixel Strichstärke aus Bank 1 (32), horizontal gespiegeltes grünes Dreieck (48), vertikal gespiegeltes rotes Dreieck (64), in beiden Richtungen gespiegeltes blaues Dreieck (80), grünes Dreieck vor einem roten Sprite, das durch Farbindex null sichtbar bleibt (96), sowie ein volles rotes Sprite vor dem BG-Dreieck als Kontrolle ohne BG-Priorität (112). Koordinaten in Pixeln ab der linken oberen Ecke; weiße Freiflächen und schwarzer Text.
FAILED CHECKS 000 bestätigt RGB-Masken, Wahrheitsflags einschließlich Wert 2, normalisierte Palettenindizes, palettenübergreifende Zugriffe, Begrenzung bei Platz 31, Nullzeiger/Nullängen ohne Schreibzugriff und Farbrücklesen bei ausgeschaltetem LCD. Vier Kombinationen werden geprüft: duales ROM auf DMG/CGB, reines DMG-ROM auf DMG und reines CGB-ROM auf CGB. Auf DMG ist CGB MODE 0, Dreiecke sind schwarz, Bank-/Spiegelattribute ändern die Anzeige nicht und die letzten beiden unteren Felder sind schwarze Quadrate. Auf CGB ist CGB MODE 1. Echte Hardware und Palettenzugriffskonflikte bei eingeschaltetem LCD sind nicht geprüft.




Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Die lokalen Unterschiede dieser API stehen bei den Änderungen und Prüfungen vom 2026-10-03.
Packt Rot, Grün und Blau mit cgb_rgb15 und schreibt eine Farbe in den Palettenspeicher für Hintergrund/Fenster. Geeignet, wenn die Komponenten einzeln statt als gepacktes Wort vorliegen.
Syntax
void cgb_bg_rgb(u8 palette_index, u8 color_index, u8 r5, u8 g5, u8 b5);Parameter
palette_indexPalettennummer 0–7; nur die unteren drei Bits werden verwendet (
& 7).color_indexFarbindex innerhalb der Palette, 0–3; nur die unteren zwei Bits werden verwendet (
& 3).r5, g5, b5Rot-, Grün- und Blaukomponente in dieser Reihenfolge, üblicherweise jeweils 0–31. Maskierung statt Sättigung; jedes Argument erscheint genau einmal in der Makroexpansion.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Paletten- und geschützte Registerschreibzugriffe schreiben im DMG-Modus nichts. Safe bedeutet hier eine CGB-Modusprüfung, keine PPU-Zugriffswarteschleife und keinen kritischen Abschnitt. Verwenden Sie die Funktionen bei ausgeschaltetem LCD oder für kurze Aktualisierungen innerhalb einer zugänglichen PPU-Phase. Sie warten nicht auf VBlank und schützen mehrbyteige Updates nicht vor Interrupts.
BG-/Fenster- und OBJ-Paletten haben getrennte Speicher. Bibliothekszugriffe aktivieren die Indexerhöhung und lassen das Indexregister verändert. OBJ-Farbindex null ist beim Zeichnen von Sprites transparent, obwohl seine Bytes gespeichert und gelesen werden können.
Anwendungsbeispiel
cgb_bg_rgb(2,3,0,0,31); // Blue, supplied as three five-bit components.
expect_color(0,11,31744);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Programm zeigt, wie BG- und OBJ-Paletten dasselbe Muster unabhängig einfärben. Jedes Dreieck ist 8 × 8 Pixel groß: oben ein Pixel links, unten eine volle Zeile. Bei x = 16, 32, 48, 64, 80, 96, 112 ist die BG-Reihe bei y = 24 rot, blau, grün, rot, blau, grün, rot; die OBJ-Reihe bei y = 64 ist blau, grün, rot, blau, grün, rot, blau. Die Spalten verwenden der Reihe nach Einzelfarbe, Komponenten, indizierten Bereich, ganze Palette, absoluten Bereich, kanonischen Registernamen und Registeralias.
Bei y = 88 zeigen sieben 8 × 8-Felder: rotes Dreieck (x = 16), blauen quadratischen Rahmen mit einem Pixel Strichstärke aus Bank 1 (32), horizontal gespiegeltes grünes Dreieck (48), vertikal gespiegeltes rotes Dreieck (64), in beiden Richtungen gespiegeltes blaues Dreieck (80), grünes Dreieck vor einem roten Sprite, das durch Farbindex null sichtbar bleibt (96), sowie ein volles rotes Sprite vor dem BG-Dreieck als Kontrolle ohne BG-Priorität (112). Koordinaten in Pixeln ab der linken oberen Ecke; weiße Freiflächen und schwarzer Text.
FAILED CHECKS 000 bestätigt RGB-Masken, Wahrheitsflags einschließlich Wert 2, normalisierte Palettenindizes, palettenübergreifende Zugriffe, Begrenzung bei Platz 31, Nullzeiger/Nullängen ohne Schreibzugriff und Farbrücklesen bei ausgeschaltetem LCD. Vier Kombinationen werden geprüft: duales ROM auf DMG/CGB, reines DMG-ROM auf DMG und reines CGB-ROM auf CGB. Auf DMG ist CGB MODE 0, Dreiecke sind schwarz, Bank-/Spiegelattribute ändern die Anzeige nicht und die letzten beiden unteren Felder sind schwarze Quadrate. Auf CGB ist CGB MODE 1. Echte Hardware und Palettenzugriffskonflikte bei eingeschaltetem LCD sind nicht geprüft.




Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Die lokalen Unterschiede dieser API stehen bei den Änderungen und Prüfungen vom 2026-10-03.
Schreibt sofort einen gepackten RGB15-Farbwert in den Palettenspeicher für Sprites (OBJ). Paletten- und Farbindex wählen einen von 32 Farbplätzen aus; Kachelmuster und die einer Kachel zugewiesene Palette bleiben dabei unverändert.
Syntax
void cgb_obj_color(u8 palette_index, u8 color_index, u16 rgb15);Parameter
palette_indexPalettennummer 0–7; nur die unteren drei Bits werden verwendet (
& 7).color_indexFarbindex innerhalb der Palette, 0–3; nur die unteren zwei Bits werden verwendet (
& 3).rgb15Gepackte 15-Bit-RGB-Farbe, gewöhnlich 0–32767. Beide Bytes des
u16werden geschrieben, das niederwertige zuerst; die Bibliothek löscht Bit 15 nicht ausdrücklich. Erzeugen Sie gültige Werte mitCGB_RGB15odercgb_rgb15.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Paletten- und geschützte Registerschreibzugriffe schreiben im DMG-Modus nichts. Safe bedeutet hier eine CGB-Modusprüfung, keine PPU-Zugriffswarteschleife und keinen kritischen Abschnitt. Verwenden Sie die Funktionen bei ausgeschaltetem LCD oder für kurze Aktualisierungen innerhalb einer zugänglichen PPU-Phase. Sie warten nicht auf VBlank und schützen mehrbyteige Updates nicht vor Interrupts.
BG-/Fenster- und OBJ-Paletten haben getrennte Speicher. Bibliothekszugriffe aktivieren die Indexerhöhung und lassen das Indexregister verändert. OBJ-Farbindex null ist beim Zeichnen von Sprites transparent, obwohl seine Bytes gespeichert und gelesen werden können.
Anwendungsbeispiel
cgb_obj_color(1,3,31744); // Blue sprite color at the same palette/color indices.
expect_color(1,7,31744);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Programm zeigt, wie BG- und OBJ-Paletten dasselbe Muster unabhängig einfärben. Jedes Dreieck ist 8 × 8 Pixel groß: oben ein Pixel links, unten eine volle Zeile. Bei x = 16, 32, 48, 64, 80, 96, 112 ist die BG-Reihe bei y = 24 rot, blau, grün, rot, blau, grün, rot; die OBJ-Reihe bei y = 64 ist blau, grün, rot, blau, grün, rot, blau. Die Spalten verwenden der Reihe nach Einzelfarbe, Komponenten, indizierten Bereich, ganze Palette, absoluten Bereich, kanonischen Registernamen und Registeralias.
Bei y = 88 zeigen sieben 8 × 8-Felder: rotes Dreieck (x = 16), blauen quadratischen Rahmen mit einem Pixel Strichstärke aus Bank 1 (32), horizontal gespiegeltes grünes Dreieck (48), vertikal gespiegeltes rotes Dreieck (64), in beiden Richtungen gespiegeltes blaues Dreieck (80), grünes Dreieck vor einem roten Sprite, das durch Farbindex null sichtbar bleibt (96), sowie ein volles rotes Sprite vor dem BG-Dreieck als Kontrolle ohne BG-Priorität (112). Koordinaten in Pixeln ab der linken oberen Ecke; weiße Freiflächen und schwarzer Text.
FAILED CHECKS 000 bestätigt RGB-Masken, Wahrheitsflags einschließlich Wert 2, normalisierte Palettenindizes, palettenübergreifende Zugriffe, Begrenzung bei Platz 31, Nullzeiger/Nullängen ohne Schreibzugriff und Farbrücklesen bei ausgeschaltetem LCD. Vier Kombinationen werden geprüft: duales ROM auf DMG/CGB, reines DMG-ROM auf DMG und reines CGB-ROM auf CGB. Auf DMG ist CGB MODE 0, Dreiecke sind schwarz, Bank-/Spiegelattribute ändern die Anzeige nicht und die letzten beiden unteren Felder sind schwarze Quadrate. Auf CGB ist CGB MODE 1. Echte Hardware und Palettenzugriffskonflikte bei eingeschaltetem LCD sind nicht geprüft.




Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Schreibt aufeinanderfolgende RGB15-Wörter in den Palettenspeicher für Sprites (OBJ), beginnend bei den angegebenen Paletten- und Farbindizes. Die Folge darf eine Vierfarbenpalette überschreiten, endet aber spätestens am Ende der 32 Farbplätze.
Syntax
void cgb_obj_colors(u8 palette_index, u8 start_color_index, const u16* colors, u8 color_count);Parameter
palette_indexPalettennummer 0–7; nur die unteren drei Bits werden verwendet (
& 7).start_color_indexFarbindex innerhalb der Palette, 0–3; nur die unteren zwei Bits werden verwendet (
& 3).colorsLesbarer
const u16*mit den benötigten Farbwörtern. Die Daten werden während des Aufrufs gelesen, nicht eingereiht. Quelle und ROM-Bank müssen erreichbar bleiben; es erfolgt kein automatischer Bankwechsel. Ein Nullzeiger bewirkt keine Schreibzugriffe.color_countAnzahl der Farbwörter, nicht Bytes, als
u8(0–255). Null bewirkt nichts. Begrenzt auf32 - normalisierter_Startplatz; nur entsprechend viele Quellwörter werden gelesen.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Paletten- und geschützte Registerschreibzugriffe schreiben im DMG-Modus nichts. Safe bedeutet hier eine CGB-Modusprüfung, keine PPU-Zugriffswarteschleife und keinen kritischen Abschnitt. Verwenden Sie die Funktionen bei ausgeschaltetem LCD oder für kurze Aktualisierungen innerhalb einer zugänglichen PPU-Phase. Sie warten nicht auf VBlank und schützen mehrbyteige Updates nicht vor Interrupts.
BG-/Fenster- und OBJ-Paletten haben getrennte Speicher. Bibliothekszugriffe aktivieren die Indexerhöhung und lassen das Indexregister verändert. OBJ-Farbindex null ist beim Zeichnen von Sprites transparent, obwohl seine Bytes gespeichert und gelesen werden können.
Anwendungsbeispiel
cgb_obj_colors(3,2,tail_red,2); // Sprite color 3 becomes red.
expect_color(1,14,0); expect_color(1,15,31);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Programm zeigt, wie BG- und OBJ-Paletten dasselbe Muster unabhängig einfärben. Jedes Dreieck ist 8 × 8 Pixel groß: oben ein Pixel links, unten eine volle Zeile. Bei x = 16, 32, 48, 64, 80, 96, 112 ist die BG-Reihe bei y = 24 rot, blau, grün, rot, blau, grün, rot; die OBJ-Reihe bei y = 64 ist blau, grün, rot, blau, grün, rot, blau. Die Spalten verwenden der Reihe nach Einzelfarbe, Komponenten, indizierten Bereich, ganze Palette, absoluten Bereich, kanonischen Registernamen und Registeralias.
Bei y = 88 zeigen sieben 8 × 8-Felder: rotes Dreieck (x = 16), blauen quadratischen Rahmen mit einem Pixel Strichstärke aus Bank 1 (32), horizontal gespiegeltes grünes Dreieck (48), vertikal gespiegeltes rotes Dreieck (64), in beiden Richtungen gespiegeltes blaues Dreieck (80), grünes Dreieck vor einem roten Sprite, das durch Farbindex null sichtbar bleibt (96), sowie ein volles rotes Sprite vor dem BG-Dreieck als Kontrolle ohne BG-Priorität (112). Koordinaten in Pixeln ab der linken oberen Ecke; weiße Freiflächen und schwarzer Text.
FAILED CHECKS 000 bestätigt RGB-Masken, Wahrheitsflags einschließlich Wert 2, normalisierte Palettenindizes, palettenübergreifende Zugriffe, Begrenzung bei Platz 31, Nullzeiger/Nullängen ohne Schreibzugriff und Farbrücklesen bei ausgeschaltetem LCD. Vier Kombinationen werden geprüft: duales ROM auf DMG/CGB, reines DMG-ROM auf DMG und reines CGB-ROM auf CGB. Auf DMG ist CGB MODE 0, Dreiecke sind schwarz, Bank-/Spiegelattribute ändern die Anzeige nicht und die letzten beiden unteren Felder sind schwarze Quadrate. Auf CGB ist CGB MODE 1. Echte Hardware und Palettenzugriffskonflikte bei eingeschaltetem LCD sind nicht geprüft.




Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Schreibt aufeinanderfolgende RGB15-Wörter in den Palettenspeicher für Sprites (OBJ), ausgehend von einem absoluten Farbplatz. Der Start ist ein einzelner Index von 0 bis 31 statt eines Paletten-/Farbindexpaares. Die Daten sind Farbwörter, keine Musterbytes.
Syntax
void cgb_obj_colors_raw(u8 start_color_slot, const u16* colors, u8 color_count);Parameter
start_color_slotAbsoluter Farbplatz 0–31, vor der Längenbegrenzung mit
& 31normalisiert. Farbplatz = Palette × 4 + Farbe; kein Byteoffset.colorsLesbarer
const u16*mit den benötigten Farbwörtern. Die Daten werden während des Aufrufs gelesen, nicht eingereiht. Quelle und ROM-Bank müssen erreichbar bleiben; es erfolgt kein automatischer Bankwechsel. Ein Nullzeiger bewirkt keine Schreibzugriffe.color_countAnzahl der Farbwörter, nicht Bytes, als
u8(0–255). Null bewirkt nichts. Begrenzt auf32 - normalisierter_Startplatz; nur entsprechend viele Quellwörter werden gelesen.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Paletten- und geschützte Registerschreibzugriffe schreiben im DMG-Modus nichts. Safe bedeutet hier eine CGB-Modusprüfung, keine PPU-Zugriffswarteschleife und keinen kritischen Abschnitt. Verwenden Sie die Funktionen bei ausgeschaltetem LCD oder für kurze Aktualisierungen innerhalb einer zugänglichen PPU-Phase. Sie warten nicht auf VBlank und schützen mehrbyteige Updates nicht vor Interrupts.
BG-/Fenster- und OBJ-Paletten haben getrennte Speicher. Bibliothekszugriffe aktivieren die Indexerhöhung und lassen das Indexregister verändert. OBJ-Farbindex null ist beim Zeichnen von Sprites transparent, obwohl seine Bytes gespeichert und gelesen werden können.
Anwendungsbeispiel
cgb_obj_colors_raw(23,green_word,1); // Same absolute slot in the separate OBJ store.
expect_color(1,23,992);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Programm zeigt, wie BG- und OBJ-Paletten dasselbe Muster unabhängig einfärben. Jedes Dreieck ist 8 × 8 Pixel groß: oben ein Pixel links, unten eine volle Zeile. Bei x = 16, 32, 48, 64, 80, 96, 112 ist die BG-Reihe bei y = 24 rot, blau, grün, rot, blau, grün, rot; die OBJ-Reihe bei y = 64 ist blau, grün, rot, blau, grün, rot, blau. Die Spalten verwenden der Reihe nach Einzelfarbe, Komponenten, indizierten Bereich, ganze Palette, absoluten Bereich, kanonischen Registernamen und Registeralias.
Bei y = 88 zeigen sieben 8 × 8-Felder: rotes Dreieck (x = 16), blauen quadratischen Rahmen mit einem Pixel Strichstärke aus Bank 1 (32), horizontal gespiegeltes grünes Dreieck (48), vertikal gespiegeltes rotes Dreieck (64), in beiden Richtungen gespiegeltes blaues Dreieck (80), grünes Dreieck vor einem roten Sprite, das durch Farbindex null sichtbar bleibt (96), sowie ein volles rotes Sprite vor dem BG-Dreieck als Kontrolle ohne BG-Priorität (112). Koordinaten in Pixeln ab der linken oberen Ecke; weiße Freiflächen und schwarzer Text.
FAILED CHECKS 000 bestätigt RGB-Masken, Wahrheitsflags einschließlich Wert 2, normalisierte Palettenindizes, palettenübergreifende Zugriffe, Begrenzung bei Platz 31, Nullzeiger/Nullängen ohne Schreibzugriff und Farbrücklesen bei ausgeschaltetem LCD. Vier Kombinationen werden geprüft: duales ROM auf DMG/CGB, reines DMG-ROM auf DMG und reines CGB-ROM auf CGB. Auf DMG ist CGB MODE 0, Dreiecke sind schwarz, Bank-/Spiegelattribute ändern die Anzeige nicht und die letzten beiden unteren Felder sind schwarze Quadrate. Auf CGB ist CGB MODE 1. Echte Hardware und Palettenzugriffskonflikte bei eingeschaltetem LCD sind nicht geprüft.




Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Ersetzt alle vier Farben einer Palette für Sprites (OBJ) durch vier RGB15-Wörter. Entspricht einem Bereichsschreibvorgang ab Farbe null mit Anzahl vier; weist die Palette keiner Kachel und keinem Sprite zu.
Syntax
void cgb_obj_palette(u8 palette_index, const u16* colors);Parameter
palette_indexPalettennummer 0–7; nur die unteren drei Bits werden verwendet (
& 7).colorsLesbarer
const u16*mit den benötigten Farbwörtern. Die Daten werden während des Aufrufs gelesen, nicht eingereiht. Quelle und ROM-Bank müssen erreichbar bleiben; es erfolgt kein automatischer Bankwechsel. Ein Nullzeiger bewirkt keine Schreibzugriffe.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Paletten- und geschützte Registerschreibzugriffe schreiben im DMG-Modus nichts. Safe bedeutet hier eine CGB-Modusprüfung, keine PPU-Zugriffswarteschleife und keinen kritischen Abschnitt. Verwenden Sie die Funktionen bei ausgeschaltetem LCD oder für kurze Aktualisierungen innerhalb einer zugänglichen PPU-Phase. Sie warten nicht auf VBlank und schützen mehrbyteige Updates nicht vor Interrupts.
BG-/Fenster- und OBJ-Paletten haben getrennte Speicher. Bibliothekszugriffe aktivieren die Indexerhöhung und lassen das Indexregister verändert. OBJ-Farbindex null ist beim Zeichnen von Sprites transparent, obwohl seine Bytes gespeichert und gelesen werden können.
Anwendungsbeispiel
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);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Programm zeigt, wie BG- und OBJ-Paletten dasselbe Muster unabhängig einfärben. Jedes Dreieck ist 8 × 8 Pixel groß: oben ein Pixel links, unten eine volle Zeile. Bei x = 16, 32, 48, 64, 80, 96, 112 ist die BG-Reihe bei y = 24 rot, blau, grün, rot, blau, grün, rot; die OBJ-Reihe bei y = 64 ist blau, grün, rot, blau, grün, rot, blau. Die Spalten verwenden der Reihe nach Einzelfarbe, Komponenten, indizierten Bereich, ganze Palette, absoluten Bereich, kanonischen Registernamen und Registeralias.
Bei y = 88 zeigen sieben 8 × 8-Felder: rotes Dreieck (x = 16), blauen quadratischen Rahmen mit einem Pixel Strichstärke aus Bank 1 (32), horizontal gespiegeltes grünes Dreieck (48), vertikal gespiegeltes rotes Dreieck (64), in beiden Richtungen gespiegeltes blaues Dreieck (80), grünes Dreieck vor einem roten Sprite, das durch Farbindex null sichtbar bleibt (96), sowie ein volles rotes Sprite vor dem BG-Dreieck als Kontrolle ohne BG-Priorität (112). Koordinaten in Pixeln ab der linken oberen Ecke; weiße Freiflächen und schwarzer Text.
FAILED CHECKS 000 bestätigt RGB-Masken, Wahrheitsflags einschließlich Wert 2, normalisierte Palettenindizes, palettenübergreifende Zugriffe, Begrenzung bei Platz 31, Nullzeiger/Nullängen ohne Schreibzugriff und Farbrücklesen bei ausgeschaltetem LCD. Vier Kombinationen werden geprüft: duales ROM auf DMG/CGB, reines DMG-ROM auf DMG und reines CGB-ROM auf CGB. Auf DMG ist CGB MODE 0, Dreiecke sind schwarz, Bank-/Spiegelattribute ändern die Anzeige nicht und die letzten beiden unteren Felder sind schwarze Quadrate. Auf CGB ist CGB MODE 1. Echte Hardware und Palettenzugriffskonflikte bei eingeschaltetem LCD sind nicht geprüft.




Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Die lokalen Unterschiede dieser API stehen bei den Änderungen und Prüfungen vom 2026-10-03.
Packt Rot, Grün und Blau mit cgb_rgb15 und schreibt eine Farbe in den Palettenspeicher für Sprites (OBJ). Geeignet, wenn die Komponenten einzeln statt als gepacktes Wort vorliegen.
Syntax
void cgb_obj_rgb(u8 palette_index, u8 color_index, u8 r5, u8 g5, u8 b5);Parameter
palette_indexPalettennummer 0–7; nur die unteren drei Bits werden verwendet (
& 7).color_indexFarbindex innerhalb der Palette, 0–3; nur die unteren zwei Bits werden verwendet (
& 3).r5, g5, b5Rot-, Grün- und Blaukomponente in dieser Reihenfolge, üblicherweise jeweils 0–31. Maskierung statt Sättigung; jedes Argument erscheint genau einmal in der Makroexpansion.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Paletten- und geschützte Registerschreibzugriffe schreiben im DMG-Modus nichts. Safe bedeutet hier eine CGB-Modusprüfung, keine PPU-Zugriffswarteschleife und keinen kritischen Abschnitt. Verwenden Sie die Funktionen bei ausgeschaltetem LCD oder für kurze Aktualisierungen innerhalb einer zugänglichen PPU-Phase. Sie warten nicht auf VBlank und schützen mehrbyteige Updates nicht vor Interrupts.
BG-/Fenster- und OBJ-Paletten haben getrennte Speicher. Bibliothekszugriffe aktivieren die Indexerhöhung und lassen das Indexregister verändert. OBJ-Farbindex null ist beim Zeichnen von Sprites transparent, obwohl seine Bytes gespeichert und gelesen werden können.
Anwendungsbeispiel
cgb_obj_rgb(2,3,0,31,0); // Green sprite color.
expect_color(1,11,992);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Programm zeigt, wie BG- und OBJ-Paletten dasselbe Muster unabhängig einfärben. Jedes Dreieck ist 8 × 8 Pixel groß: oben ein Pixel links, unten eine volle Zeile. Bei x = 16, 32, 48, 64, 80, 96, 112 ist die BG-Reihe bei y = 24 rot, blau, grün, rot, blau, grün, rot; die OBJ-Reihe bei y = 64 ist blau, grün, rot, blau, grün, rot, blau. Die Spalten verwenden der Reihe nach Einzelfarbe, Komponenten, indizierten Bereich, ganze Palette, absoluten Bereich, kanonischen Registernamen und Registeralias.
Bei y = 88 zeigen sieben 8 × 8-Felder: rotes Dreieck (x = 16), blauen quadratischen Rahmen mit einem Pixel Strichstärke aus Bank 1 (32), horizontal gespiegeltes grünes Dreieck (48), vertikal gespiegeltes rotes Dreieck (64), in beiden Richtungen gespiegeltes blaues Dreieck (80), grünes Dreieck vor einem roten Sprite, das durch Farbindex null sichtbar bleibt (96), sowie ein volles rotes Sprite vor dem BG-Dreieck als Kontrolle ohne BG-Priorität (112). Koordinaten in Pixeln ab der linken oberen Ecke; weiße Freiflächen und schwarzer Text.
FAILED CHECKS 000 bestätigt RGB-Masken, Wahrheitsflags einschließlich Wert 2, normalisierte Palettenindizes, palettenübergreifende Zugriffe, Begrenzung bei Platz 31, Nullzeiger/Nullängen ohne Schreibzugriff und Farbrücklesen bei ausgeschaltetem LCD. Vier Kombinationen werden geprüft: duales ROM auf DMG/CGB, reines DMG-ROM auf DMG und reines CGB-ROM auf CGB. Auf DMG ist CGB MODE 0, Dreiecke sind schwarz, Bank-/Spiegelattribute ändern die Anzeige nicht und die letzten beiden unteren Felder sind schwarze Quadrate. Auf CGB ist CGB MODE 1. Echte Hardware und Palettenzugriffskonflikte bei eingeschaltetem LCD sind nicht geprüft.




Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Packt RGB in einen u16: Rot in Bits 0–4, Grün in 5–9 und Blau in 10–14; Bit 15 ist null. Die Maske 31 erhält nur die unteren fünf Bits jeder Komponente, ohne Sättigung. Berechnet lediglich einen Wert, auf DMG wie CGB, ohne Hardwarezugriff.
Syntax
#define CGB_RGB15(r5, g5, b5) ((u16)((u16)((r5) & 31) | ((u16)((g5) & 31) << 5) | ((u16)((b5) & 31) << 10)))Parameter
r5, g5, b5Rot-, Grün- und Blaukomponente in dieser Reihenfolge, üblicherweise jeweils 0–31. Maskierung statt Sättigung; jedes Argument erscheint genau einmal in der Makroexpansion.
Rückgabewert
Gepackter RGB15-Wert als u16, von 0 bis 32767.
Anwendungsbeispiel
if (CGB_RGB15(component,64,95)!=31775) failures++; // (31,0,31), not saturation.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Programm zeigt, wie BG- und OBJ-Paletten dasselbe Muster unabhängig einfärben. Jedes Dreieck ist 8 × 8 Pixel groß: oben ein Pixel links, unten eine volle Zeile. Bei x = 16, 32, 48, 64, 80, 96, 112 ist die BG-Reihe bei y = 24 rot, blau, grün, rot, blau, grün, rot; die OBJ-Reihe bei y = 64 ist blau, grün, rot, blau, grün, rot, blau. Die Spalten verwenden der Reihe nach Einzelfarbe, Komponenten, indizierten Bereich, ganze Palette, absoluten Bereich, kanonischen Registernamen und Registeralias.
Bei y = 88 zeigen sieben 8 × 8-Felder: rotes Dreieck (x = 16), blauen quadratischen Rahmen mit einem Pixel Strichstärke aus Bank 1 (32), horizontal gespiegeltes grünes Dreieck (48), vertikal gespiegeltes rotes Dreieck (64), in beiden Richtungen gespiegeltes blaues Dreieck (80), grünes Dreieck vor einem roten Sprite, das durch Farbindex null sichtbar bleibt (96), sowie ein volles rotes Sprite vor dem BG-Dreieck als Kontrolle ohne BG-Priorität (112). Koordinaten in Pixeln ab der linken oberen Ecke; weiße Freiflächen und schwarzer Text.
FAILED CHECKS 000 bestätigt RGB-Masken, Wahrheitsflags einschließlich Wert 2, normalisierte Palettenindizes, palettenübergreifende Zugriffe, Begrenzung bei Platz 31, Nullzeiger/Nullängen ohne Schreibzugriff und Farbrücklesen bei ausgeschaltetem LCD. Vier Kombinationen werden geprüft: duales ROM auf DMG/CGB, reines DMG-ROM auf DMG und reines CGB-ROM auf CGB. Auf DMG ist CGB MODE 0, Dreiecke sind schwarz, Bank-/Spiegelattribute ändern die Anzeige nicht und die letzten beiden unteren Felder sind schwarze Quadrate. Auf CGB ist CGB MODE 1. Echte Hardware und Palettenzugriffskonflikte bei eingeschaltetem LCD sind nicht geprüft.




Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
kitaqgb/lib/cgb_palette.h:16
cgb_rgb15
Packt RGB in einen u16: Rot in Bits 0–4, Grün in 5–9 und Blau in 10–14; Bit 15 ist null. Die Maske 31 erhält nur die unteren fünf Bits jeder Komponente, ohne Sättigung. Berechnet lediglich einen Wert, auf DMG wie CGB, ohne Hardwarezugriff.
Syntax
u16 cgb_rgb15(u8 r5, u8 g5, u8 b5);Parameter
r5, g5, b5Rot-, Grün- und Blaukomponente in dieser Reihenfolge, üblicherweise jeweils 0–31. Maskierung statt Sättigung; jedes Argument erscheint genau einmal in der Makroexpansion.
Rückgabewert
Gepackter RGB15-Wert als u16, von 0 bis 32767.
Anwendungsbeispiel
if (cgb_rgb15(component,64,95)!=31775) failures++; // Same packed value through a function.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Programm zeigt, wie BG- und OBJ-Paletten dasselbe Muster unabhängig einfärben. Jedes Dreieck ist 8 × 8 Pixel groß: oben ein Pixel links, unten eine volle Zeile. Bei x = 16, 32, 48, 64, 80, 96, 112 ist die BG-Reihe bei y = 24 rot, blau, grün, rot, blau, grün, rot; die OBJ-Reihe bei y = 64 ist blau, grün, rot, blau, grün, rot, blau. Die Spalten verwenden der Reihe nach Einzelfarbe, Komponenten, indizierten Bereich, ganze Palette, absoluten Bereich, kanonischen Registernamen und Registeralias.
Bei y = 88 zeigen sieben 8 × 8-Felder: rotes Dreieck (x = 16), blauen quadratischen Rahmen mit einem Pixel Strichstärke aus Bank 1 (32), horizontal gespiegeltes grünes Dreieck (48), vertikal gespiegeltes rotes Dreieck (64), in beiden Richtungen gespiegeltes blaues Dreieck (80), grünes Dreieck vor einem roten Sprite, das durch Farbindex null sichtbar bleibt (96), sowie ein volles rotes Sprite vor dem BG-Dreieck als Kontrolle ohne BG-Priorität (112). Koordinaten in Pixeln ab der linken oberen Ecke; weiße Freiflächen und schwarzer Text.
FAILED CHECKS 000 bestätigt RGB-Masken, Wahrheitsflags einschließlich Wert 2, normalisierte Palettenindizes, palettenübergreifende Zugriffe, Begrenzung bei Platz 31, Nullzeiger/Nullängen ohne Schreibzugriff und Farbrücklesen bei ausgeschaltetem LCD. Vier Kombinationen werden geprüft: duales ROM auf DMG/CGB, reines DMG-ROM auf DMG und reines CGB-ROM auf CGB. Auf DMG ist CGB MODE 0, Dreiecke sind schwarz, Bank-/Spiegelattribute ändern die Anzeige nicht und die letzten beiden unteren Felder sind schwarze Quadrate. Auf CGB ist CGB MODE 1. Echte Hardware und Palettenzugriffskonflikte bei eingeschaltetem LCD sind nicht geprüft.




Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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-Kachelnummern und -attribute
cgb_tile.h bündelt Deklarationen für Kachelkarten-Intrinsics und Makros zum Erzeugen von CGB-Kachelattributen. Eine Kachelnummer wählt ein Muster; das Attribut wählt Palette, Muster-VRAM-Bank, Spiegelungen und Hintergrundpriorität. Attribute verändern keine Musterpixel.
Die Familie __settile adressiert Karte 0x9800; __settileat nutzt eine ausdrückliche Kartenbasis, __settilebg die von LCDC gewählte Hintergrundkarte und __settilewin dessen Fensterkarte. Die attr-Formen schreiben nur Attribute, die cgb-Formen Kachelnummern und Attribute. bulk-Formen übertragen fortlaufende Bytes an die angegebene Adresse. Wählen Sie nach Ziel und geschriebenen Daten.
Verwenden Sie Makros wie KQ_CGB_ATTR_PAL für einzelne Attributbits oder KQ_CGB_ATTR zum Kombinieren der Felder. Das Bankfeld wählt die VRAM-Bank des Musters, keine ROM-Bank. Gewöhnliche Kachelnummern-Schreibzugriffe nutzen die aktuelle VRAM-Bank; wählen Sie vor kombinierten Kachel-/Attributoperationen Bank null. Auf dem DMG bleiben reine Attributoperationen ohne Wirkung; kombinierte Operationen schreiben weiterhin die Kachelnummern.
Der Compiler erzeugt die Implementierung der __-Intrinsics; cgb_tile.c muss nicht eingebunden werden. Gewöhnliche Schreibpfade warten auf VRAM-Zugriff, ändern teilweise aber auch den Interruptfreigabezustand. _unsafe- und _fast-Formen lassen diese Wartezeiten aus. Verwenden Sie sie nur bei garantiert beschreibbarem VRAM, etwa bei ausgeschaltetem LCD. Prüfen Sie die Interrupt-, Bank- und Längenbedingungen jedes Eintrags.
KQ_CGB_ATTR
Erzeugt ein vollständiges CGB-Kartenattributbyte aus Palette, Musterbank, horizontaler und vertikaler Spiegelung sowie BG-Priorität. Palette belegt Bits 0–2, die vier booleschen Felder setzen Bits 3, 5, 6 und 7. Bit 4 bleibt null.
Syntax
#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)))Parameter
palettePalettennummer 0–7; nur die unteren drei Bits werden verwendet (
& 7).bank, xflip, yflip, priorityNull deaktiviert das Feld; jeder Wert ungleich null aktiviert es. Auch 2 aktiviert es: geprüft wird der Wahrheitswert, nicht das unterste Bit.
Rückgabewert
Attributfeld oder kombiniertes Attributbyte als u8, mit der oben beschriebenen Bitbelegung.
Bedingungen und Grenzen
Diese Makros berechnen nur u8-Werte, ohne VRAM- oder Registerzugriffe. Jedes Argument erscheint einmal. Übernehmen Sie das Ergebnis mit einer CGB-Attribut-API oder einem ausdrücklichen Schreibzugriff auf die Karte in Bank 1. DMG zeigt keine CGB-Kartenattribute an.
Erzeugt Bit 3 eines CGB-Kartenattributs: 0x08 bei jedem bank-Wert ungleich null, sonst 0. Wählt die VRAM-Bank des angezeigten Musters; schreibt weder VBK noch die CPU-Bankauswahl.
Erzeugt das Flag für horizontale Spiegelung: 0x20 bei enabled ungleich null, sonst 0. Im CGB-Kartenattribut werden die acht Pixel jeder Kachelzeile umgekehrt angezeigt; das gespeicherte Muster bleibt unverändert.
Erzeugt das Flag für vertikale Spiegelung: 0x40 bei enabled ungleich null, sonst 0. Im CGB-Kartenattribut werden die acht Zeilen umgekehrt angezeigt, ohne das gespeicherte Muster zu ändern.
Erzeugt das BG-vor-OBJ-Prioritätsflag: 0x80 bei enabled ungleich null, sonst 0. Bei aktivierter CGB-Gesamtpriorität (LCDC-Bit 0) verdecken BG-Farbindizes ungleich null die Sprites. Durch Farbindex null bleiben Sprites sichtbar; die ganze Kachel wird dadurch nicht deckend.
Anwendungsbeispiel
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);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Programm zeigt, wie BG- und OBJ-Paletten dasselbe Muster unabhängig einfärben. Jedes Dreieck ist 8 × 8 Pixel groß: oben ein Pixel links, unten eine volle Zeile. Bei x = 16, 32, 48, 64, 80, 96, 112 ist die BG-Reihe bei y = 24 rot, blau, grün, rot, blau, grün, rot; die OBJ-Reihe bei y = 64 ist blau, grün, rot, blau, grün, rot, blau. Die Spalten verwenden der Reihe nach Einzelfarbe, Komponenten, indizierten Bereich, ganze Palette, absoluten Bereich, kanonischen Registernamen und Registeralias.
Bei y = 88 zeigen sieben 8 × 8-Felder: rotes Dreieck (x = 16), blauen quadratischen Rahmen mit einem Pixel Strichstärke aus Bank 1 (32), horizontal gespiegeltes grünes Dreieck (48), vertikal gespiegeltes rotes Dreieck (64), in beiden Richtungen gespiegeltes blaues Dreieck (80), grünes Dreieck vor einem roten Sprite, das durch Farbindex null sichtbar bleibt (96), sowie ein volles rotes Sprite vor dem BG-Dreieck als Kontrolle ohne BG-Priorität (112). Koordinaten in Pixeln ab der linken oberen Ecke; weiße Freiflächen und schwarzer Text.
FAILED CHECKS 000 bestätigt RGB-Masken, Wahrheitsflags einschließlich Wert 2, normalisierte Palettenindizes, palettenübergreifende Zugriffe, Begrenzung bei Platz 31, Nullzeiger/Nullängen ohne Schreibzugriff und Farbrücklesen bei ausgeschaltetem LCD. Vier Kombinationen werden geprüft: duales ROM auf DMG/CGB, reines DMG-ROM auf DMG und reines CGB-ROM auf CGB. Auf DMG ist CGB MODE 0, Dreiecke sind schwarz, Bank-/Spiegelattribute ändern die Anzeige nicht und die letzten beiden unteren Felder sind schwarze Quadrate. Auf CGB ist CGB MODE 1. Echte Hardware und Palettenzugriffskonflikte bei eingeschaltetem LCD sind nicht geprüft.




Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
kitaqgb/lib/cgb_tile.h:23
KQ_CGB_ATTR_BANK
Erzeugt Bit 3 eines CGB-Kartenattributs: 0x08 bei jedem bank-Wert ungleich null, sonst 0. Wählt die VRAM-Bank des angezeigten Musters; schreibt weder VBK noch die CPU-Bankauswahl.
Syntax
#define KQ_CGB_ATTR_BANK(bank) ((u8)((bank) ? KQ_CGB_ATTR_BANK1 : 0))Parameter
bankNull deaktiviert das Feld; jeder Wert ungleich null aktiviert es. Auch 2 aktiviert es: geprüft wird der Wahrheitswert, nicht das unterste Bit.
Rückgabewert
Attributfeld oder kombiniertes Attributbyte als u8, mit der oben beschriebenen Bitbelegung.
Bedingungen und Grenzen
Diese Makros berechnen nur u8-Werte, ohne VRAM- oder Registerzugriffe. Jedes Argument erscheint einmal. Übernehmen Sie das Ergebnis mit einer CGB-Attribut-API oder einem ausdrücklichen Schreibzugriff auf die Karte in Bank 1. DMG zeigt keine CGB-Kartenattribute an.
Anwendungsbeispiel
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.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Programm zeigt, wie BG- und OBJ-Paletten dasselbe Muster unabhängig einfärben. Jedes Dreieck ist 8 × 8 Pixel groß: oben ein Pixel links, unten eine volle Zeile. Bei x = 16, 32, 48, 64, 80, 96, 112 ist die BG-Reihe bei y = 24 rot, blau, grün, rot, blau, grün, rot; die OBJ-Reihe bei y = 64 ist blau, grün, rot, blau, grün, rot, blau. Die Spalten verwenden der Reihe nach Einzelfarbe, Komponenten, indizierten Bereich, ganze Palette, absoluten Bereich, kanonischen Registernamen und Registeralias.
Bei y = 88 zeigen sieben 8 × 8-Felder: rotes Dreieck (x = 16), blauen quadratischen Rahmen mit einem Pixel Strichstärke aus Bank 1 (32), horizontal gespiegeltes grünes Dreieck (48), vertikal gespiegeltes rotes Dreieck (64), in beiden Richtungen gespiegeltes blaues Dreieck (80), grünes Dreieck vor einem roten Sprite, das durch Farbindex null sichtbar bleibt (96), sowie ein volles rotes Sprite vor dem BG-Dreieck als Kontrolle ohne BG-Priorität (112). Koordinaten in Pixeln ab der linken oberen Ecke; weiße Freiflächen und schwarzer Text.
FAILED CHECKS 000 bestätigt RGB-Masken, Wahrheitsflags einschließlich Wert 2, normalisierte Palettenindizes, palettenübergreifende Zugriffe, Begrenzung bei Platz 31, Nullzeiger/Nullängen ohne Schreibzugriff und Farbrücklesen bei ausgeschaltetem LCD. Vier Kombinationen werden geprüft: duales ROM auf DMG/CGB, reines DMG-ROM auf DMG und reines CGB-ROM auf CGB. Auf DMG ist CGB MODE 0, Dreiecke sind schwarz, Bank-/Spiegelattribute ändern die Anzeige nicht und die letzten beiden unteren Felder sind schwarze Quadrate. Auf CGB ist CGB MODE 1. Echte Hardware und Palettenzugriffskonflikte bei eingeschaltetem LCD sind nicht geprüft.




Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
kitaqgb/lib/cgb_tile.h:19
KQ_CGB_ATTR_PAL
Erzeugt das Palettenfeld eines CGB-Kartenattributs: n & 7, als u8. Mit anderen Attributflags durch bitweises ODER kombinierbar.
Syntax
#define KQ_CGB_ATTR_PAL(n) ((u8)((n) & KQ_CGB_ATTR_PAL_MASK))Parameter
nPalettennummer 0–7; nur die unteren drei Bits werden verwendet (
& 7).
Rückgabewert
Attributfeld oder kombiniertes Attributbyte als u8, mit der oben beschriebenen Bitbelegung.
Bedingungen und Grenzen
Diese Makros berechnen nur u8-Werte, ohne VRAM- oder Registerzugriffe. Jedes Argument erscheint einmal. Übernehmen Sie das Ergebnis mit einer CGB-Attribut-API oder einem ausdrücklichen Schreibzugriff auf die Karte in Bank 1. DMG zeigt keine CGB-Kartenattribute an.
Anwendungsbeispiel
attr=KQ_CGB_ATTR_PAL(9); // 9 & 7 = palette 1, red in this BG example.
if (attr!=1) failures++;
cell(2,11,1,attr);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Programm zeigt, wie BG- und OBJ-Paletten dasselbe Muster unabhängig einfärben. Jedes Dreieck ist 8 × 8 Pixel groß: oben ein Pixel links, unten eine volle Zeile. Bei x = 16, 32, 48, 64, 80, 96, 112 ist die BG-Reihe bei y = 24 rot, blau, grün, rot, blau, grün, rot; die OBJ-Reihe bei y = 64 ist blau, grün, rot, blau, grün, rot, blau. Die Spalten verwenden der Reihe nach Einzelfarbe, Komponenten, indizierten Bereich, ganze Palette, absoluten Bereich, kanonischen Registernamen und Registeralias.
Bei y = 88 zeigen sieben 8 × 8-Felder: rotes Dreieck (x = 16), blauen quadratischen Rahmen mit einem Pixel Strichstärke aus Bank 1 (32), horizontal gespiegeltes grünes Dreieck (48), vertikal gespiegeltes rotes Dreieck (64), in beiden Richtungen gespiegeltes blaues Dreieck (80), grünes Dreieck vor einem roten Sprite, das durch Farbindex null sichtbar bleibt (96), sowie ein volles rotes Sprite vor dem BG-Dreieck als Kontrolle ohne BG-Priorität (112). Koordinaten in Pixeln ab der linken oberen Ecke; weiße Freiflächen und schwarzer Text.
FAILED CHECKS 000 bestätigt RGB-Masken, Wahrheitsflags einschließlich Wert 2, normalisierte Palettenindizes, palettenübergreifende Zugriffe, Begrenzung bei Platz 31, Nullzeiger/Nullängen ohne Schreibzugriff und Farbrücklesen bei ausgeschaltetem LCD. Vier Kombinationen werden geprüft: duales ROM auf DMG/CGB, reines DMG-ROM auf DMG und reines CGB-ROM auf CGB. Auf DMG ist CGB MODE 0, Dreiecke sind schwarz, Bank-/Spiegelattribute ändern die Anzeige nicht und die letzten beiden unteren Felder sind schwarze Quadrate. Auf CGB ist CGB MODE 1. Echte Hardware und Palettenzugriffskonflikte bei eingeschaltetem LCD sind nicht geprüft.




Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
kitaqgb/lib/cgb_tile.h:18
KQ_CGB_ATTR_PRIORITY_IF
Erzeugt das BG-vor-OBJ-Prioritätsflag: 0x80 bei enabled ungleich null, sonst 0. Bei aktivierter CGB-Gesamtpriorität (LCDC-Bit 0) verdecken BG-Farbindizes ungleich null die Sprites. Durch Farbindex null bleiben Sprites sichtbar; die ganze Kachel wird dadurch nicht deckend.
Syntax
#define KQ_CGB_ATTR_PRIORITY_IF(enabled) ((u8)((enabled) ? KQ_CGB_ATTR_PRIORITY : 0))Parameter
enabledNull deaktiviert das Feld; jeder Wert ungleich null aktiviert es. Auch 2 aktiviert es: geprüft wird der Wahrheitswert, nicht das unterste Bit.
Rückgabewert
Attributfeld oder kombiniertes Attributbyte als u8, mit der oben beschriebenen Bitbelegung.
Bedingungen und Grenzen
Diese Makros berechnen nur u8-Werte, ohne VRAM- oder Registerzugriffe. Jedes Argument erscheint einmal. Übernehmen Sie das Ergebnis mit einer CGB-Attribut-API oder einem ausdrücklichen Schreibzugriff auf die Karte in Bank 1. DMG zeigt keine CGB-Kartenattribute an.
Anwendungsbeispiel
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.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Programm zeigt, wie BG- und OBJ-Paletten dasselbe Muster unabhängig einfärben. Jedes Dreieck ist 8 × 8 Pixel groß: oben ein Pixel links, unten eine volle Zeile. Bei x = 16, 32, 48, 64, 80, 96, 112 ist die BG-Reihe bei y = 24 rot, blau, grün, rot, blau, grün, rot; die OBJ-Reihe bei y = 64 ist blau, grün, rot, blau, grün, rot, blau. Die Spalten verwenden der Reihe nach Einzelfarbe, Komponenten, indizierten Bereich, ganze Palette, absoluten Bereich, kanonischen Registernamen und Registeralias.
Bei y = 88 zeigen sieben 8 × 8-Felder: rotes Dreieck (x = 16), blauen quadratischen Rahmen mit einem Pixel Strichstärke aus Bank 1 (32), horizontal gespiegeltes grünes Dreieck (48), vertikal gespiegeltes rotes Dreieck (64), in beiden Richtungen gespiegeltes blaues Dreieck (80), grünes Dreieck vor einem roten Sprite, das durch Farbindex null sichtbar bleibt (96), sowie ein volles rotes Sprite vor dem BG-Dreieck als Kontrolle ohne BG-Priorität (112). Koordinaten in Pixeln ab der linken oberen Ecke; weiße Freiflächen und schwarzer Text.
FAILED CHECKS 000 bestätigt RGB-Masken, Wahrheitsflags einschließlich Wert 2, normalisierte Palettenindizes, palettenübergreifende Zugriffe, Begrenzung bei Platz 31, Nullzeiger/Nullängen ohne Schreibzugriff und Farbrücklesen bei ausgeschaltetem LCD. Vier Kombinationen werden geprüft: duales ROM auf DMG/CGB, reines DMG-ROM auf DMG und reines CGB-ROM auf CGB. Auf DMG ist CGB MODE 0, Dreiecke sind schwarz, Bank-/Spiegelattribute ändern die Anzeige nicht und die letzten beiden unteren Felder sind schwarze Quadrate. Auf CGB ist CGB MODE 1. Echte Hardware und Palettenzugriffskonflikte bei eingeschaltetem LCD sind nicht geprüft.




Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
kitaqgb/lib/cgb_tile.h:22
KQ_CGB_ATTR_XFLIP_IF
Erzeugt das Flag für horizontale Spiegelung: 0x20 bei enabled ungleich null, sonst 0. Im CGB-Kartenattribut werden die acht Pixel jeder Kachelzeile umgekehrt angezeigt; das gespeicherte Muster bleibt unverändert.
Syntax
#define KQ_CGB_ATTR_XFLIP_IF(enabled) ((u8)((enabled) ? KQ_CGB_ATTR_XFLIP : 0))Parameter
enabledNull deaktiviert das Feld; jeder Wert ungleich null aktiviert es. Auch 2 aktiviert es: geprüft wird der Wahrheitswert, nicht das unterste Bit.
Rückgabewert
Attributfeld oder kombiniertes Attributbyte als u8, mit der oben beschriebenen Bitbelegung.
Bedingungen und Grenzen
Diese Makros berechnen nur u8-Werte, ohne VRAM- oder Registerzugriffe. Jedes Argument erscheint einmal. Übernehmen Sie das Ergebnis mit einer CGB-Attribut-API oder einem ausdrücklichen Schreibzugriff auf die Karte in Bank 1. DMG zeigt keine CGB-Kartenattribute an.
Anwendungsbeispiel
attr=(u8)(3|KQ_CGB_ATTR_XFLIP_IF(enabled));
if (attr!=35) failures++;
cell(6,11,1,attr); // Green triangle reflected horizontally.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Programm zeigt, wie BG- und OBJ-Paletten dasselbe Muster unabhängig einfärben. Jedes Dreieck ist 8 × 8 Pixel groß: oben ein Pixel links, unten eine volle Zeile. Bei x = 16, 32, 48, 64, 80, 96, 112 ist die BG-Reihe bei y = 24 rot, blau, grün, rot, blau, grün, rot; die OBJ-Reihe bei y = 64 ist blau, grün, rot, blau, grün, rot, blau. Die Spalten verwenden der Reihe nach Einzelfarbe, Komponenten, indizierten Bereich, ganze Palette, absoluten Bereich, kanonischen Registernamen und Registeralias.
Bei y = 88 zeigen sieben 8 × 8-Felder: rotes Dreieck (x = 16), blauen quadratischen Rahmen mit einem Pixel Strichstärke aus Bank 1 (32), horizontal gespiegeltes grünes Dreieck (48), vertikal gespiegeltes rotes Dreieck (64), in beiden Richtungen gespiegeltes blaues Dreieck (80), grünes Dreieck vor einem roten Sprite, das durch Farbindex null sichtbar bleibt (96), sowie ein volles rotes Sprite vor dem BG-Dreieck als Kontrolle ohne BG-Priorität (112). Koordinaten in Pixeln ab der linken oberen Ecke; weiße Freiflächen und schwarzer Text.
FAILED CHECKS 000 bestätigt RGB-Masken, Wahrheitsflags einschließlich Wert 2, normalisierte Palettenindizes, palettenübergreifende Zugriffe, Begrenzung bei Platz 31, Nullzeiger/Nullängen ohne Schreibzugriff und Farbrücklesen bei ausgeschaltetem LCD. Vier Kombinationen werden geprüft: duales ROM auf DMG/CGB, reines DMG-ROM auf DMG und reines CGB-ROM auf CGB. Auf DMG ist CGB MODE 0, Dreiecke sind schwarz, Bank-/Spiegelattribute ändern die Anzeige nicht und die letzten beiden unteren Felder sind schwarze Quadrate. Auf CGB ist CGB MODE 1. Echte Hardware und Palettenzugriffskonflikte bei eingeschaltetem LCD sind nicht geprüft.




Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
kitaqgb/lib/cgb_tile.h:20
KQ_CGB_ATTR_YFLIP_IF
Erzeugt das Flag für vertikale Spiegelung: 0x40 bei enabled ungleich null, sonst 0. Im CGB-Kartenattribut werden die acht Zeilen umgekehrt angezeigt, ohne das gespeicherte Muster zu ändern.
Syntax
#define KQ_CGB_ATTR_YFLIP_IF(enabled) ((u8)((enabled) ? KQ_CGB_ATTR_YFLIP : 0))Parameter
enabledNull deaktiviert das Feld; jeder Wert ungleich null aktiviert es. Auch 2 aktiviert es: geprüft wird der Wahrheitswert, nicht das unterste Bit.
Rückgabewert
Attributfeld oder kombiniertes Attributbyte als u8, mit der oben beschriebenen Bitbelegung.
Bedingungen und Grenzen
Diese Makros berechnen nur u8-Werte, ohne VRAM- oder Registerzugriffe. Jedes Argument erscheint einmal. Übernehmen Sie das Ergebnis mit einer CGB-Attribut-API oder einem ausdrücklichen Schreibzugriff auf die Karte in Bank 1. DMG zeigt keine CGB-Kartenattribute an.
Anwendungsbeispiel
attr=(u8)(1|KQ_CGB_ATTR_YFLIP_IF(enabled));
if (attr!=65) failures++;
cell(8,11,1,attr); // Red triangle reflected vertically.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Programm zeigt, wie BG- und OBJ-Paletten dasselbe Muster unabhängig einfärben. Jedes Dreieck ist 8 × 8 Pixel groß: oben ein Pixel links, unten eine volle Zeile. Bei x = 16, 32, 48, 64, 80, 96, 112 ist die BG-Reihe bei y = 24 rot, blau, grün, rot, blau, grün, rot; die OBJ-Reihe bei y = 64 ist blau, grün, rot, blau, grün, rot, blau. Die Spalten verwenden der Reihe nach Einzelfarbe, Komponenten, indizierten Bereich, ganze Palette, absoluten Bereich, kanonischen Registernamen und Registeralias.
Bei y = 88 zeigen sieben 8 × 8-Felder: rotes Dreieck (x = 16), blauen quadratischen Rahmen mit einem Pixel Strichstärke aus Bank 1 (32), horizontal gespiegeltes grünes Dreieck (48), vertikal gespiegeltes rotes Dreieck (64), in beiden Richtungen gespiegeltes blaues Dreieck (80), grünes Dreieck vor einem roten Sprite, das durch Farbindex null sichtbar bleibt (96), sowie ein volles rotes Sprite vor dem BG-Dreieck als Kontrolle ohne BG-Priorität (112). Koordinaten in Pixeln ab der linken oberen Ecke; weiße Freiflächen und schwarzer Text.
FAILED CHECKS 000 bestätigt RGB-Masken, Wahrheitsflags einschließlich Wert 2, normalisierte Palettenindizes, palettenübergreifende Zugriffe, Begrenzung bei Platz 31, Nullzeiger/Nullängen ohne Schreibzugriff und Farbrücklesen bei ausgeschaltetem LCD. Vier Kombinationen werden geprüft: duales ROM auf DMG/CGB, reines DMG-ROM auf DMG und reines CGB-ROM auf CGB. Auf DMG ist CGB MODE 0, Dreiecke sind schwarz, Bank-/Spiegelattribute ändern die Anzeige nicht und die letzten beiden unteren Felder sind schwarze Quadrate. Auf CGB ist CGB MODE 1. Echte Hardware und Palettenzugriffskonflikte bei eingeschaltetem LCD sind nicht geprüft.




Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
kitaqgb/lib/cgb_tile.h:21
chain.h — Ringpuffer für Positionsverläufe
Verwenden Sie ChainBody für gegliederte Schlangen oder Seile und Chain für einen aufgezeichneten Positionsverlauf. Jedes Körpergelenk speichert seine aktuelle Position und eine von 16 Richtungen; Biegungen wandern pro Aktualisierung um ein Gelenk nach hinten. Die Körperoperationen unterstützen umlaufende Spielfelder, Wachstum durch Duplizieren des Schwanzendes und Korrekturen von bis zu zwei Pixeln je Achse.
chain_wrap_delta
Berechnet die kürzeste vorzeichenbehaftete Verschiebung von der aktuellen Position zu einem Ziel auf einer Achse mit verbundenen Enden. Verwenden Sie dies für Verfolgung oder Distanzvergleiche über einen Feldrand hinweg.
Syntax
s16 chain_wrap_delta(u8 target, u8 current, u16 size);Parameter
targetZielkoordinate, 0..size−1.
currentAktuelle Koordinate, 0..size−1.
sizeLänge der umlaufenden Achse, 1..256: Breite für X, Höhe für Y. Das Argument hat 16 Bit, damit 256 darstellbar ist.
Rückgabewert
Gibt die kürzeste Verschiebung als s16 zurück: positiv zu steigenden, negativ zu fallenden Koordinaten, null bei gleicher Position. Gültige Eingaben ergeben −128..+128. Auf dem Bildschirm sind Verschiebungen nach rechts und unten positiv.
Bedingungen und Grenzen
Binden Sie chain.h ein und kompilieren Sie chain.c genau einmal. Chain oder ChainBody müssen nicht initialisiert werden. Die Funktion berechnet nur eine Verschiebung und ändert weder Koordinatenarrays noch Gelenkanzahl oder Bildschirm.
Die Funktion prüft und normalisiert Eingaben nicht. Übergeben Sie weder size=0 noch size>256 noch Koordinaten ab size. Bilden Sie Koordinaten aus einem größeren System vor dem Aufruf umlaufend auf 0..size−1 ab.
Bei gleich langen Wegen bleibt das Vorzeichen der direkten Differenz target−current erhalten. Bei size=160 liefert 0→80 den Wert +80 und 80→0 den Wert −80. Bei size=1 ist null die einzige gültige Koordinate und auch das Ergebnis ist null.
Anwendungsbeispiel
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.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieses Beispiel zeigt umlaufende Koordinaten. Jeder Pfeil führt von der aktuellen Position zum Ziel. Angezeigt werden +02/−02 beim Überqueren eines Rands bei Breite 160, +80/−80 für ein halbes Feld und +00 bei Breite 1. Die führende Null ist dezimale Stellenfüllung. Das Beispiel zeichnet und bewegt kein Objekt.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Verknüpft drei Gelenkarrays des aufrufenden Codes und setzt die Gelenkanzahl auf null, ohne Speicher zu reservieren.
Syntax
u8 chain_body_init(ChainBody* body, u8* x, u8* y, u8* heading, u8 capacity, u16 width, u16 height);Parameter
bodyZiel-
ChainBody; null wird ignoriert. Übergeben Sie außer bei der Initialisierung einen initialisierten Zustand.xArray der Gelenk-X-Koordinaten.
yArray der Gelenk-Y-Koordinaten.
headingArray der Gelenkrichtungen.
capacityReservierte Array-Länge, 1..255.
widthBreite des umlaufenden Felds, 1..256.
heightHöhe des umlaufenden Felds, 1..256.
Rückgabewert
Gibt bei Erfolg 1 zurück, bei ungültigen Argumenten 0. Ein Fehlschlag bei nicht leerem Körperzeiger setzt capacity und count auf null und deaktiviert Aktualisierungen.
Bedingungen und Grenzen
Binden Sie chain.h ein und kompilieren Sie chain.c genau einmal. ChainBody speichert die aktuelle Position und Richtung jedes Gelenks. Es ist ein eigener Zustandstyp, getrennt vom Positionsverlaufsring Chain.
Stellen Sie drei getrennte beschreibbare Arrays x, y und heading mit je capacity Bytes bereit und halten Sie sie während der Körpernutzung gültig. Index null ist der Kopf und in count enthalten. Ändern Sie nach der Initialisierung weder Speicherzeiger noch Kapazität oder Feldabmessungen.
Richtungen verwenden 16 Sektoren im Uhrzeigersinn: 0=rechts, 4=unten, 8=links, 12=oben. Nur die unteren vier Eingabebits werden verwendet. Bildschirmkoordinaten steigen nach rechts und unten; jede Abmessung beträgt 1..256 Pixel.
Anwendungsbeispiel
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.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Bild zeigt oben einen geraden Körper, in der Mitte eine Aktualisierung nach einer Abwärtskurve und unten vier Aktualisierungen danach. Koordinaten werden in doppelter logischer Größe gezeichnet. Die Biegung wandert vom Kopf rechts nach hinten. CGB und FC zeigen Kopf rot, Körper blau und Schwanz grün; DMG verwendet Schwarz. Vier Ausgleichsaktualisierungen trennen das duplizierte Schwanzende nach dem Wachstum. Es sind drei Ansichten derselben acht Gelenke, kein Körper mit 24 Gelenken.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Erzeugt eine gerade Anfangsanordnung, indem Gelenke hinter dem angegebenen Kopf platziert werden.
Syntax
u8 chain_body_reset(ChainBody* body, u8 count, u8 head_x, u8 head_y, u8 heading);Parameter
bodyZiel-
ChainBody; null wird ignoriert. Übergeben Sie außer bei der Initialisierung einen initialisierten Zustand.countGelenkanzahl einschließlich Kopf, 1..capacity.
head_xKopf-X-Koordinate, auf die Feldbreite umlaufend abgebildet.
head_yKopf-Y-Koordinate, auf die Feldhöhe umlaufend abgebildet.
headingKopfrichtung im System mit 16 Sektoren.
Rückgabewert
Gibt bei Erfolg 1 zurück. Eine Anzahl von null oder über der Kapazität oder ein Nullzeiger liefert 0, ohne die Anordnung zu ändern.
Bedingungen und Grenzen
Binden Sie chain.h ein und kompilieren Sie chain.c genau einmal. ChainBody speichert die aktuelle Position und Richtung jedes Gelenks. Es ist ein eigener Zustandstyp, getrennt vom Positionsverlaufsring Chain.
Stellen Sie drei getrennte beschreibbare Arrays x, y und heading mit je capacity Bytes bereit und halten Sie sie während der Körpernutzung gültig. Index null ist der Kopf und in count enthalten. Ändern Sie nach der Initialisierung weder Speicherzeiger noch Kapazität oder Feldabmessungen.
Richtungen verwenden 16 Sektoren im Uhrzeigersinn: 0=rechts, 4=unten, 8=links, 12=oben. Nur die unteren vier Eingabebits werden verwendet. Bildschirmkoordinaten steigen nach rechts und unten; jede Abmessung beträgt 1..256 Pixel.
Der orthogonale Abstand beträgt vier Pixel. Zwischenrichtungen verwenden Ganzzahlvektoren wie (4,1), (3,3) und (1,4); die euklidische Distanz beträgt daher nicht exakt vier Pixel. Die anfängliche Anordnung kann einen Feldrand überschreiten.
Anwendungsbeispiel
chain_body_reset(&body,7,48,16,0); // Seven joints, facing right.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Bild zeigt oben einen geraden Körper, in der Mitte eine Aktualisierung nach einer Abwärtskurve und unten vier Aktualisierungen danach. Koordinaten werden in doppelter logischer Größe gezeichnet. Die Biegung wandert vom Kopf rechts nach hinten. CGB und FC zeigen Kopf rot, Körper blau und Schwanz grün; DMG verwendet Schwarz. Vier Ausgleichsaktualisierungen trennen das duplizierte Schwanzende nach dem Wachstum. Es sind drei Ansichten derselben acht Gelenke, kein Körper mit 24 Gelenken.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Setzt die Kopfanordnung und zieht jedes Gelenk schrittweise zu einem Anschlusspunkt hinter seinem Vorgänger. Richtungsänderungen wandern pro Aktualisierung um ein Gelenk weiter.
Syntax
void chain_body_step(ChainBody* body, u8 head_x, u8 head_y, u8 heading);Parameter
bodyZiel-
ChainBody; null wird ignoriert. Übergeben Sie außer bei der Initialisierung einen initialisierten Zustand.head_xKopf-X-Koordinate, auf die Feldbreite umlaufend abgebildet.
head_yKopf-Y-Koordinate, auf die Feldhöhe umlaufend abgebildet.
headingKopfrichtung im System mit 16 Sektoren.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Binden Sie chain.h ein und kompilieren Sie chain.c genau einmal. ChainBody speichert die aktuelle Position und Richtung jedes Gelenks. Es ist ein eigener Zustandstyp, getrennt vom Positionsverlaufsring Chain.
Stellen Sie drei getrennte beschreibbare Arrays x, y und heading mit je capacity Bytes bereit und halten Sie sie während der Körpernutzung gültig. Index null ist der Kopf und in count enthalten. Ändern Sie nach der Initialisierung weder Speicherzeiger noch Kapazität oder Feldabmessungen.
Richtungen verwenden 16 Sektoren im Uhrzeigersinn: 0=rechts, 4=unten, 8=links, 12=oben. Nur die unteren vier Eingabebits werden verwendet. Bildschirmkoordinaten steigen nach rechts und unten; jede Abmessung beträgt 1..256 Pixel.
Ermittelt aus der aktualisierten Position des Vorgängers den Zielanschlusspunkt und berechnet dann je Achse die kürzeste umlaufende Verschiebung. Null bewegt nicht; Betrag 1..4 bewegt ein Pixel, ab 5 zwei Pixel. Bei genau einer halben Feldlänge bleibt das ursprüngliche Vorzeichen erhalten.
Gibt die vor der Aktualisierung gespeicherte Richtung jedes Gelenks an das nächste weiter, sodass eine Biegung durch den Körper wandert. Ein leerer Körper bleibt unverändert.
Der aufrufende Code verwaltet Kopfgeschwindigkeit, Beschleunigung, Kollisionen, Zeichnen und Warten. Aktualisieren Sie gewöhnlich zuerst den Kopf und rufen Sie chain_body_step einmal pro Simulationsschritt auf. Dies ist Gelenkverfolgung, kein Starrkörper- oder exakter Längenbedingungslöser.
Anwendungsbeispiel
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.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Bild zeigt oben einen geraden Körper, in der Mitte eine Aktualisierung nach einer Abwärtskurve und unten vier Aktualisierungen danach. Koordinaten werden in doppelter logischer Größe gezeichnet. Die Biegung wandert vom Kopf rechts nach hinten. CGB und FC zeigen Kopf rot, Körper blau und Schwanz grün; DMG verwendet Schwarz. Vier Ausgleichsaktualisierungen trennen das duplizierte Schwanzende nach dem Wachstum. Es sind drei Ansichten derselben acht Gelenke, kein Körper mit 24 Gelenken.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Kopiert aktuelle Position und Richtung des Schwanzendes in den nächsten freien Platz und erhöht die Anzahl um eins.
Syntax
u8 chain_body_grow(ChainBody* body);Parameter
bodyZiel-
ChainBody; null wird ignoriert. Übergeben Sie außer bei der Initialisierung einen initialisierten Zustand.
Rückgabewert
Gibt beim Anhängen eines Gelenks 1 zurück; bei leerem, vollem, deaktiviertem Körper oder Nullzeiger 0.
Bedingungen und Grenzen
Binden Sie chain.h ein und kompilieren Sie chain.c genau einmal. ChainBody speichert die aktuelle Position und Richtung jedes Gelenks. Es ist ein eigener Zustandstyp, getrennt vom Positionsverlaufsring Chain.
Stellen Sie drei getrennte beschreibbare Arrays x, y und heading mit je capacity Bytes bereit und halten Sie sie während der Körpernutzung gültig. Index null ist der Kopf und in count enthalten. Ändern Sie nach der Initialisierung weder Speicherzeiger noch Kapazität oder Feldabmessungen.
Richtungen verwenden 16 Sektoren im Uhrzeigersinn: 0=rechts, 4=unten, 8=links, 12=oben. Nur die unteren vier Eingabebits werden verwendet. Bildschirmkoordinaten steigen nach rechts und unten; jede Abmessung beträgt 1..256 Pixel.
Das neue Schwanzende überlappt zunächst das vorige und trennt sich bei folgenden chain_body_step-Aufrufen. Wachstum allein bewegt weder Kopf noch andere Gelenke.
Anwendungsbeispiel
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.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Bild zeigt oben einen geraden Körper, in der Mitte eine Aktualisierung nach einer Abwärtskurve und unten vier Aktualisierungen danach. Koordinaten werden in doppelter logischer Größe gezeichnet. Die Biegung wandert vom Kopf rechts nach hinten. CGB und FC zeigen Kopf rot, Körper blau und Schwanz grün; DMG verwendet Schwarz. Vier Ausgleichsaktualisierungen trennen das duplizierte Schwanzende nach dem Wachstum. Es sind drei Ansichten derselben acht Gelenke, kein Körper mit 24 Gelenken.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Setzt die Gelenkanzahl auf null und erhält Arrays sowie Feldeinstellungen.
Syntax
void chain_body_clear(ChainBody* body);Parameter
bodyZiel-
ChainBody; null wird ignoriert. Übergeben Sie außer bei der Initialisierung einen initialisierten Zustand.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Binden Sie chain.h ein und kompilieren Sie chain.c genau einmal. ChainBody speichert die aktuelle Position und Richtung jedes Gelenks. Es ist ein eigener Zustandstyp, getrennt vom Positionsverlaufsring Chain.
Stellen Sie drei getrennte beschreibbare Arrays x, y und heading mit je capacity Bytes bereit und halten Sie sie während der Körpernutzung gültig. Index null ist der Kopf und in count enthalten. Ändern Sie nach der Initialisierung weder Speicherzeiger noch Kapazität oder Feldabmessungen.
Richtungen verwenden 16 Sektoren im Uhrzeigersinn: 0=rechts, 4=unten, 8=links, 12=oben. Nur die unteren vier Eingabebits werden verwendet. Bildschirmkoordinaten steigen nach rechts und unten; jede Abmessung beträgt 1..256 Pixel.
Die Array-Bytes werden nicht gelöscht. Beginnen Sie mit chain_body_reset neu; chain_body_grow unmittelbar nach dem Leeren hängt kein Gelenk an.
Anwendungsbeispiel
chain_body_clear(&body); // Forget the pose; the three arrays remain owned by us.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Bild zeigt oben einen geraden Körper, in der Mitte eine Aktualisierung nach einer Abwärtskurve und unten vier Aktualisierungen danach. Koordinaten werden in doppelter logischer Größe gezeichnet. Die Biegung wandert vom Kopf rechts nach hinten. CGB und FC zeigen Kopf rot, Körper blau und Schwanz grün; DMG verwendet Schwarz. Vier Ausgleichsaktualisierungen trennen das duplizierte Schwanzende nach dem Wachstum. Es sind drei Ansichten derselben acht Gelenke, kein Körper mit 24 Gelenken.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Verwirft den aufgezeichneten Verlauf, damit dasselbe Speicherarray erneut verwendet werden kann.
Syntax
void chain_clear(Chain* chain);Parameter
chainZeiger auf das initialisierte
Chain-Objekt.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Setzt Anzahl und head auf null, ohne das Speicherarray zu löschen oder freizugeben. Der Aufrufer verwaltet Chain und das Punktarray und muss beide gültig halten. Die Kapazität darf höchstens 128 betragen, damit die 8-Bit-Indexaddition beim Lesen nicht überläuft.
Die GB-Version benötigt einen gültigen chain-Zeiger.
Anwendungsbeispiel
chain_clear(&trail);result[11]=chain_get_count(&trail);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel leert einen Verlauf mit vier Punkten und prüft, dass die Anzahl danach null ist.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Liest die Anzahl der aktuell im Verlauf verfügbaren Positionen.
Syntax
u8 chain_get_count(const Chain* chain);Parameter
chainZeiger auf das initialisierte
Chain-Objekt.
Rückgabewert
Gibt eine Anzahl zwischen null und der Kapazität zurück, bei Nullzeiger null.
Bedingungen und Grenzen
Der Aufrufer verwaltet sowohl Chain als auch das Punktarray und muss beide gültig halten. Verwenden Sie höchstens 128 Plätze, damit die 8-Bit-Indexaddition beim Lesen nicht überläuft.
Anwendungsbeispiel
result[4]=chain_get_count(&trail);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Nach fünf Einfügungen in vier Plätze bleibt die Anzahl vier. Nach dem Leeren ist sie null; bei Kapazität null bleibt sie stets null.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Liest eine gespeicherte Position anhand ihres Alters im Verlauf.
Syntax
u8 chain_get_segment(const Chain* chain, u8 index, ChainPoint* out);Parameter
chainZeiger auf das initialisierte
Chain-Objekt.indexAlter des Punkts: 0 bezeichnet den neuesten,
count - 1den ältesten noch gespeicherten Punkt.outEigenständiges, beschreibbares
ChainPoint-Objekt für das Ergebnis; ein Nullzeiger führt zum Fehlschlag.
Rückgabewert
Gibt bei Erfolg 1, bei ungültiger Anfrage 0 zurück. Ein nichtnulliger out-Zeiger wird vor der Prüfung auf (0,0) gesetzt.
Bedingungen und Grenzen
out darf keinen Speicher mit dem zugrunde liegenden Array oder mit Chain teilen, da das Nullsetzen der Ausgabe Quelldaten zerstören würde. Der Aufrufer verwaltet Chain und das Punktarray und muss beide gültig halten. Höchstens 128 Plätze verhindern einen Überlauf der 8-Bit-Indexaddition beim Lesen.
Anwendungsbeispiel
result[1]=chain_get_segment(&trail,0,&point);result[2]=point.x;result[3]=point.y;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Index 0 liest den neuesten Punkt (40,24), Index 3 den ältesten (16,8). Der ungültige Index 4 meldet einen Fehler und setzt die Ausgabe auf (0,0).


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Verknüpft Speicher mit einem Ringpuffer für Positionsverläufe und beginnt ohne aufgezeichnete Punkte.
Syntax
void chain_init(Chain* chain, ChainPoint* storage, u8 capacity);Parameter
chainZu initialisierendes, beschreibbares
Chain-Objekt.storageArray mit Platz für
capacityEinträge vom TypChainPoint.capacityAnzahl der Punktplätze. Für einen nutzbaren Verlauf sind 1 bis 128 zulässig; null deaktiviert die Aufzeichnung.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Der Aufrufer verwaltet sowohl Chain als auch das Punktarray und muss beide gültig halten. Verwenden Sie höchstens 128 Plätze, damit die 8-Bit-Indexaddition beim Lesen nicht überläuft.
Die GB-Version benötigt einen gültigen chain-Zeiger.
Anwendungsbeispiel
chain_init(&trail,storage,4);result[0]=chain_get_count(&trail);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel bindet vier Punktplätze ein und prüft, dass die anfängliche Anzahl null ist.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Fügt die neueste Position am Kopf des Verlaufs ein und ersetzt bei vollem Puffer den ältesten Punkt.
Syntax
void chain_push_head(Chain* chain, s16 x, s16 y);Parameter
chainZeiger auf das initialisierte
Chain-Objekt.xX-Koordinate des neuen Punkts mit Vorzeichen.
yY-Koordinate des neuen Punkts mit Vorzeichen.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Bei Nullzeiger oder Kapazität null geschieht nichts. Der Aufrufer verwaltet Chain und das Punktarray und muss beide gültig halten. Die Kapazität darf höchstens 128 betragen, damit die 8-Bit-Indexaddition beim Lesen nicht überläuft.
Anwendungsbeispiel
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);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Nach fünf Einfügungen in vier Plätze ist (40,24) der neueste und (16,8) der älteste noch vorhandene Punkt. Der ursprüngliche Punkt (8,8) wurde ersetzt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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 — Geschosspools, Fächermuster, Treffer und Streiferkennung
Projektilfeld ohne dynamische Speichervergabe für bis zu 96 Schüsse auf 160×128 Pixeln. Bietet Sechzehntelpixelbewegung, Fächer mit 32 Richtungen, Treffer-/Streifereignisse und Kachelzusammensetzung aus vier Quadranten. Die Simulation läuft auf dem GB; die Übertragung mit present_now ist CGB-exklusiv.
danmaku_clear
Deaktiviert alle Projektile und löscht aktive Anzahl, aktuelle Treffer-/Streifereignisse und den Vergabecursor.
Syntax
void danmaku_clear();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Behält Spitzen- und Gesamtzähler bei. Löschen und übertragen Sie die RAM-Karte, um Projektile aus der Anzeige zu entfernen.
Anwendungsbeispiel
danmaku_clear();result[6]=dm_count;result[7]=dm_spawned;result[8]=dm_peak;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
CGB-exklusives Zeichenbeispiel. Erzeugen Sie acht Richtungen bei (80,64), aktualisieren Sie achtmal und zeigen Sie acht rote 3×3-Punkte in radialer Anordnung. Orthogonale Projektile bewegen sich 32 Pixel; Diagonalen verwenden Ganzzahlnäherungen. Geprüft werden außerdem Poolleerung und Erhalt der kumulierten Erzeugungen.

Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Löscht alle 576 Bytes der 32×18-RAM-Kachelkarte.
Syntax
void danmaku_clear_map();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Lässt Projektilzustand und VRAM unverändert. Verwenden Sie pro Frame die Reihenfolge clear_map, Dekoration schreiben, step, übertragen.
Anwendungsbeispiel
danmaku_clear_map();result[11]=dm_map[0];Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
CGB-exklusives Zeichenbeispiel. Erzeugen Sie acht Richtungen bei (80,64), aktualisieren Sie achtmal und zeigen Sie acht rote 3×3-Punkte in radialer Anordnung. Orthogonale Projektile bewegen sich 32 Pixel; Diagonalen verwenden Ganzzahlnäherungen. Geprüft werden außerdem Poolleerung und Erhalt der kumulierten Erzeugungen.

Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Erzeugt einen Fächer mithilfe einer Geschwindigkeitstabelle mit 32 Richtungen und festem Winkelschritt.
Syntax
void danmaku_fan(u8 x, u8 y, u8 direction, u8 step, u8 count, u8 speed);Parameter
xAnfängliches Pixel-X, 0..159.
yAnfängliches Pixel-Y, 0..127.
directionAnfangswinkel, auf fünf Bits maskiert: 0=rechts, 8=unten, 16=links, 24=oben.
stepWinkelzuwachs je Projektil, mit Umlauf über 32 Richtungen.
countAnzahl der Versuche, auf 96 begrenzt.
speedGeschwindigkeit in Sechzehntelpixeln, höchstens 64 beziehungsweise vier Pixel pro Aktualisierung.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Versucht auch bei vollem Pool die verbleibenden Erzeugungen. Ganzzahlige sin/cos-Tabellenwerte führen bei diagonaler Bewegung zu Rundungen.
Anwendungsbeispiel
danmaku_fan(80,64,0,4,8,64);result[9]=dm_count;result[10]=dm_spawned;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
CGB-exklusives Zeichenbeispiel. Erzeugen Sie acht Richtungen bei (80,64), aktualisieren Sie achtmal und zeigen Sie acht rote 3×3-Punkte in radialer Anordnung. Orthogonale Projektile bewegen sich 32 Pixel; Diagonalen verwenden Ganzzahlnäherungen. Geprüft werden außerdem Poolleerung und Erhalt der kumulierten Erzeugungen.

Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Überträgt alle 576 dm_map-Bytes synchron per CGB-GDMA zur Hintergrundkarte $9800.
Syntax
void danmaku_present_now();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Nur für CGB; nicht auf dem DMG aufrufen. Verwenden Sie die Funktion bei ausgeschaltetem LCD oder am VBlank-Anfang. Sie wählt VRAM-Bank null, ohne den bisherigen VBK-Wert wiederherzustellen. Die Anwendung stellt Projektilgrafiken in Kacheln 0..15 bereit.
Anwendungsbeispiel
// CGB general DMA; the LCD is stopped for this complete-map upload.
danmaku_present_now();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
CGB-exklusives Zeichenbeispiel. Erzeugen Sie acht Richtungen bei (80,64), aktualisieren Sie achtmal und zeigen Sie acht rote 3×3-Punkte in radialer Anordnung. Orthogonale Projektile bewegen sich 32 Pixel; Diagonalen verwenden Ganzzahlnäherungen. Geprüft werden außerdem Poolleerung und Erhalt der kumulierten Erzeugungen.

Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Leert den Pool mit 96 Projektilen und setzt Spitzenwert, kumulierte Erzeugungen und Ablehnungen wegen voller Belegung zurück.
Syntax
void danmaku_reset();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Lässt Spielerkoordinaten, Unverwundbarkeit und RAM-Kachelkarte unverändert; richten Sie diese bei Spielbeginn getrennt ein.
Anwendungsbeispiel
danmaku_reset();result[0]=dm_count;result[1]=dm_peak;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
CGB-exklusives Zeichenbeispiel. Erzeugen Sie acht Richtungen bei (80,64), aktualisieren Sie achtmal und zeigen Sie acht rote 3×3-Punkte in radialer Anordnung. Orthogonale Projektile bewegen sich 32 Pixel; Diagonalen verwenden Ganzzahlnäherungen. Geprüft werden außerdem Poolleerung und Erhalt der kumulierten Erzeugungen.

Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Sucht zyklisch nach freien Plätzen und erzeugt ein Projektil mit gewünschter Position und Geschwindigkeit.
Syntax
u8 danmaku_spawn(u8 x, u8 y, s8 vx, s8 vy);Parameter
xAnfängliches Pixel-X, 0..159.
yAnfängliches Pixel-Y, 0..127.
vxVorzeichenbehaftete Q4.4-Geschwindigkeit −128..127; 16 bewegt pro Aktualisierung ein Pixel nach rechts.
vyVorzeichenbehaftete Q4.4-Geschwindigkeit; positive Werte bewegen nach unten.
Rückgabewert
Gibt bei erfolgreicher Vergabe 1 zurück, bei Koordinaten außerhalb oder vollem Pool 0. Anforderungen außerhalb erhöhen dm_rejected nicht.
Bedingungen und Grenzen
Positionen werden in Sechzehntelpixeln gespeichert. Die u16-Gesamtzähler für Erzeugungen und Ablehnungen laufen nach 65535 um. Es wird kein dynamischer Speicher vergeben.
Anwendungsbeispiel
result[2]=danmaku_spawn(40,40,16,0);result[3]=danmaku_spawn(160,40,0,0);result[4]=dm_count;result[5]=dm_rejected;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
CGB-exklusives Zeichenbeispiel. Erzeugen Sie acht Richtungen bei (80,64), aktualisieren Sie achtmal und zeigen Sie acht rote 3×3-Punkte in radialer Anordnung. Orthogonale Projektile bewegen sich 32 Pixel; Diagonalen verwenden Ganzzahlnäherungen. Geprüft werden außerdem Poolleerung und Erhalt der kumulierten Erzeugungen.

Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Bewegt jedes Projektil einmal, entfernt Projektile außerhalb, setzt Projektilkacheln zusammen und erkennt Treffer sowie Streifen.
Syntax
void danmaku_step();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Gezeichnete Mittelpunkte rasten auf Vier-Pixel-Zellen ein. Achsendifferenzen von höchstens acht ergeben das erste Streifen, höchstens drei einen Treffer. Unverwundbarkeit unterdrückt nur Treffer. dm_hit/dm_graze werden bei jedem Aufruf zurückgesetzt; jedes Projektil streift nur einmal. Kachel-IDs 0..15 codieren vier Quadrantenbits; belegte Dekorationskacheln mit IDs ab 16 werden ersetzt.
Anwendungsbeispiel
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;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
CGB-exklusives Zeichenbeispiel. Erzeugen Sie acht Richtungen bei (80,64), aktualisieren Sie achtmal und zeigen Sie acht rote 3×3-Punkte in radialer Anordnung. Orthogonale Projektile bewegen sich 32 Pixel; Diagonalen verwenden Ganzzahlnäherungen. Geprüft werden außerdem Poolleerung und Erhalt der kumulierten Erzeugungen.

Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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-Protokolle und Zusicherungen
Protokolliert Namen, Werte und Frame-Kennungen in einem RAM-Protokoll fester Kapazität. Assertions bewahren Diagnoseinformationen auf und lassen die Ausführung weiterlaufen.
debug_assert_fail
Speichert einen Assertion-Fehlercode und versucht, einen ASSERT-Eintrag anzuhängen.
Syntax
void debug_assert_fail(u16 code);Parameter
codeZu speichernde 16-Bit-Fehlerkennung.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Die Ausführung läuft weiter. Der letzte Assertion-Code wird auch bei vollem Protokoll aktualisiert. Das Protokoll fasst standardmäßig 32 Einträge und verwirft bei voller Belegung neue Einträge. Wenn Sie DEBUG_TRACE_MAX überschreiben, verwenden Sie in allen Übersetzungseinheiten denselben Wert zwischen 1 und 255. Namen werden als Zeiger gespeichert, nicht kopiert; ihr Speicher muss bis zum Ende der Auswertung lesbar bleiben. Zugriffe aus Hauptprogramm und Interrupts müssen Sie selbst gegeneinander absichern.
Anwendungsbeispiel
debug_assert_fail(42);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel speichert Code 42, füllt das Protokoll und speichert dann Code 999. Die Anzahl bleibt 32, der letzte Code wird jedoch zu 999.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Liest den letzten Assertion-Code unabhängig vom verfügbaren Protokollspeicher.
Syntax
u16 debug_get_last_assert();Rückgabewert
Gibt den letzten 16-Bit-Code zurück; nach der Initialisierung ist er null.
Bedingungen und Grenzen
Null ist zugleich der Anfangswert und lässt sich daher nicht von einem mit Code null protokollierten Fehler unterscheiden. Das Lesen löscht den Code nicht.
Anwendungsbeispiel
result[22]=debug_get_last_assert();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel prüft 77 aus dem Assertion-Makro, 999 nach dem Füllen des Protokolls und null nach erneuter Initialisierung.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Liest die Anzahl gültiger Einträge im Trace-Array.
Syntax
u8 debug_get_trace_count();Rückgabewert
Gibt eine Anzahl von null bis DEBUG_TRACE_MAX zurück.
Bedingungen und Grenzen
Das Protokoll fasst standardmäßig 32 Einträge und verwirft bei voller Belegung neue Einträge. Wenn Sie DEBUG_TRACE_MAX überschreiben, verwenden Sie in allen Übersetzungseinheiten denselben Wert zwischen 1 und 255. Namen werden als Zeiger gespeichert, nicht kopiert; ihr Speicher muss bis zum Ende der Auswertung lesbar bleiben. Zugriffe aus Hauptprogramm und Interrupts müssen Sie selbst gegeneinander absichern.
Anwendungsbeispiel
result[1]=debug_get_trace_count();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel prüft die ersten zehn Einträge und nach weiteren Schreibzugriffen die Grenze von 32. Bei voller Belegung läuft der Zähler nicht auf null über.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Liefert eine Referenz auf das interne Array zur Auswertung gespeicherter Namen, Werte und Frame-Kennungen.
Syntax
const DebugTraceEntry* debug_get_trace_log();Rückgabewert
Gibt einen schreibgeschützten Zeiger auf das interne DebugTraceEntry-Array zurück.
Bedingungen und Grenzen
Dies ist keine Kopie. Lesen Sie nur die von debug_get_trace_count() gemeldete Anzahl von Einträgen. Nach der Initialisierung verbliebene alte Bytes sind keine gültigen Datensätze. Das Protokoll fasst standardmäßig 32 Einträge und verwirft bei voller Belegung neue Einträge. Wenn Sie DEBUG_TRACE_MAX überschreiben, verwenden Sie in allen Übersetzungseinheiten denselben Wert zwischen 1 und 255. Namen werden als Zeiger gespeichert, nicht kopiert; ihr Speicher muss bis zum Ende der Auswertung lesbar bleiben. Zugriffe aus Hauptprogramm und Interrupts müssen Sie selbst gegeneinander absichern.
Anwendungsbeispiel
entries=debug_get_trace_log();for(i=0;i<10;i++){result[2+i]=entries[i].value;result[12+i]=entries[i].frame;}Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel liest alle zehn Wert- und Frame-Felder und prüft das führende B der Bezeichnung BEGIN.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Initialisiert die gültige Protokolllänge, die Frame-Kennung und den letzten Assertion-Code.
Syntax
void debug_init();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Die Bytes vorhandener Einträge werden nicht gelöscht. Rufen Sie die Funktion vor dem ersten Protokolleintrag auf. Das Protokoll fasst standardmäßig 32 Einträge und verwirft bei voller Belegung neue Einträge. Wenn Sie DEBUG_TRACE_MAX überschreiben, verwenden Sie in allen Übersetzungseinheiten denselben Wert zwischen 1 und 255. Namen werden als Zeiger gespeichert, nicht kopiert; ihr Speicher muss bis zum Ende der Auswertung lesbar bleiben. Zugriffe aus Hauptprogramm und Interrupts müssen Sie selbst gegeneinander absichern.
Anwendungsbeispiel
debug_init();result[0]=debug_get_trace_count();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel prüft zunächst die Anzahl null, setzt dann ein gefülltes Protokoll zurück und bestätigt, dass Anzahl und Assertion-Code gelöscht sind, während die alten Arraywerte erhalten bleiben.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Schreibt eine benannte Frame-Markierung, um eine Stelle im Ablauf zu kennzeichnen.
Syntax
void debug_mark_frame(const u8* label);Parameter
labelNullterminierte Bezeichnung in Speicher, der bis zur Auswertung lesbar bleiben muss.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Das Protokoll fasst standardmäßig 32 Einträge und verwirft bei voller Belegung neue Einträge. Wenn Sie DEBUG_TRACE_MAX überschreiben, verwenden Sie in allen Übersetzungseinheiten denselben Wert zwischen 1 und 255. Namen werden als Zeiger gespeichert, nicht kopiert; ihr Speicher muss bis zum Ende der Auswertung lesbar bleiben. Zugriffe aus Hauptprogramm und Interrupts müssen Sie selbst gegeneinander absichern.
Anwendungsbeispiel
debug_mark_frame("BEGIN");Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Die Markierung BEGIN speichert den Wert 65535 (0xFFFF) mit der Frame-Kennung 513.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Legt die Frame-Kennung fest, die in nachfolgende Protokolleinträge kopiert wird.
Syntax
void debug_set_frame(u16 frame);Parameter
frame16-Bit-Frame-Nummer für nachfolgende Einträge.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Die Funktion wartet weder auf einen Frame noch erhöht sie die Kennung automatisch. Übergeben Sie ausdrücklich den Frame-Zähler des Spiels. Das Protokoll fasst standardmäßig 32 Einträge und verwirft bei voller Belegung neue Einträge. Wenn Sie DEBUG_TRACE_MAX überschreiben, verwenden Sie in allen Übersetzungseinheiten denselben Wert zwischen 1 und 255. Namen werden als Zeiger gespeichert, nicht kopiert; ihr Speicher muss bis zum Ende der Auswertung lesbar bleiben. Zugriffe aus Hauptprogramm und Interrupts müssen Sie selbst gegeneinander absichern.
Anwendungsbeispiel
debug_set_frame(513);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel setzt die Kennung auf 513, schreibt zehn Einträge und liest zur Kontrolle alle zehn Frame-Felder zurück.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Protokolliert einen benannten 16-Bit-Punktestand oder Zähler.
Syntax
void debug_trace_u16(const u8* name, u16 value);Parameter
nameNullterminierte Bezeichnung in Speicher, der bis zur Auswertung lesbar bleiben muss.
valueZu protokollierender Wert von 0 bis 65535.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Das Protokoll fasst standardmäßig 32 Einträge und verwirft bei voller Belegung neue Einträge. Wenn Sie DEBUG_TRACE_MAX überschreiben, verwenden Sie in allen Übersetzungseinheiten denselben Wert zwischen 1 und 255. Namen werden als Zeiger gespeichert, nicht kopiert; ihr Speicher muss bis zum Ende der Auswertung lesbar bleiben. Zugriffe aus Hauptprogramm und Interrupts müssen Sie selbst gegeneinander absichern.
Anwendungsbeispiel
debug_trace_u16("WORD",4660);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Der Eintrag WORD speichert 4660 (0x1234); das Beispiel liest ihn zur Prüfung beider Bytes zurück.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Protokolliert einen 8-Bit-Zustandswert mit Namen und aktueller Frame-Kennung.
Syntax
void debug_trace_u8(const u8* name, u8 value);Parameter
nameNullterminierte Bezeichnung in Speicher, der bis zur Auswertung lesbar bleiben muss.
valueWert von 0 bis 255, der mit Nullen auf das 16-Bit-Protokollfeld erweitert wird.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Das Protokoll fasst standardmäßig 32 Einträge und verwirft bei voller Belegung neue Einträge. Wenn Sie DEBUG_TRACE_MAX überschreiben, verwenden Sie in allen Übersetzungseinheiten denselben Wert zwischen 1 und 255. Namen werden als Zeiger gespeichert, nicht kopiert; ihr Speicher muss bis zum Ende der Auswertung lesbar bleiben. Zugriffe aus Hauptprogramm und Interrupts müssen Sie selbst gegeneinander absichern.
Anwendungsbeispiel
debug_trace_u8("BYTE",255);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Der Eintrag BYTE speichert 255 und prüft, dass das 16-Bit-Wertfeld im Protokoll ebenfalls 255 enthält.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Als Anweisung verwendbares Makro, das bei falscher Bedingung Assertion-Code 1 protokolliert.
Syntax
#define KITAQGB_ASSERT(cond) do { if (!(cond)) debug_assert_fail((u16)1); } while (0)Parameter
condBedingung, die erfüllt sein soll; null bedeutet einen Fehler.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Die Bedingung wird einmal ausgewertet. Bei wahr wird nichts protokolliert, bei falsch der Fehler aufgezeichnet, ohne die Ausführung anzuhalten. Durch die Form do…while (0) lässt sich das Makro in einem if…else als einzelne Anweisung verwenden.
Anwendungsbeispiel
KITAQGB_ASSERT(1);KITAQGB_ASSERT(0);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Eine wahre und eine falsche Assertion erzeugen genau einen Eintrag mit Code 1.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
kitaqgb/lib/debug.h:45
#define KITAQGB_ASSERT(cond) do { if (!(cond)) debug_assert_fail((u16)1); } while (0)KITAQGB_ASSERT_CODE
Protokolliert den gewählten Assertion-Code nur bei falscher Bedingung.
Syntax
#define KITAQGB_ASSERT_CODE(cond, code) do { if (!(cond)) debug_assert_fail((u16)(code)); } while (0)Parameter
condBedingung, die erfüllt sein soll.
codeCode-Ausdruck, der im Fehlerfall ausgewertet und in 16 Bits umgewandelt wird.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Die Bedingung wird einmal ausgewertet, der Code-Ausdruck nur im Fehlerfall. Nach dem Protokollieren läuft die Ausführung weiter.
Anwendungsbeispiel
KITAQGB_ASSERT_CODE(1,++side_effect);KITAQGB_ASSERT_CODE(0,77);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei wahrer Bedingung wird der Code-Ausdruck ++side_effect nicht ausgewertet; die Variable bleibt null. Eine falsche Bedingung protokolliert Code 77.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
kitaqgb/lib/debug.h:46
#define KITAQGB_ASSERT_CODE(cond, code) do { if (!(cond)) debug_assert_fail((u16)(code)); } while (0)KITAQGB_MARK_FRAME
Wandelt eine Bezeichnung in einen Zeichenkettenzeiger um und fügt eine Frame-Markierung mit dem Wert 0xFFFF hinzu.
Syntax
#define KITAQGB_MARK_FRAME(label) debug_mark_frame((const u8*)(label))Parameter
labelNullterminierte Bezeichnung in Speicher, der bis zur Auswertung lesbar bleiben muss.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Das Protokoll fasst standardmäßig 32 Einträge und verwirft bei voller Belegung neue Einträge. Wenn Sie DEBUG_TRACE_MAX überschreiben, verwenden Sie in allen Übersetzungseinheiten denselben Wert zwischen 1 und 255. Namen werden als Zeiger gespeichert, nicht kopiert; ihr Speicher muss bis zum Ende der Auswertung lesbar bleiben. Zugriffe aus Hauptprogramm und Interrupts müssen Sie selbst gegeneinander absichern.
Anwendungsbeispiel
KITAQGB_MARK_FRAME("END");Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Die Markierung END wird auf den Wert 65535 und die Frame-Kennung 513 geprüft.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
kitaqgb/lib/debug.h:44
#define KITAQGB_MARK_FRAME(label) debug_mark_frame((const u8*)(label))KITAQGB_TRACE
Wandelt einen Wert ausdrücklich in 16 Bits um und protokolliert ihn mit Namen.
Syntax
#define KITAQGB_TRACE(name, value) debug_trace_u16((const u8*)(name), (u16)(value))Parameter
nameNullterminierte Bezeichnung in Speicher, der bis zur Auswertung lesbar bleiben muss.
valueAusdruck, der vor dem Protokollieren in 16 Bits umgewandelt wird.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Das Makro ist immer aktiv; Build-Einstellungen deaktivieren es nicht automatisch. Es protokolliert 16-Bit-Werte genauso wie KITAQGB_TRACE_U16. Das Protokoll fasst standardmäßig 32 Einträge und verwirft bei voller Belegung neue Einträge. Wenn Sie DEBUG_TRACE_MAX überschreiben, verwenden Sie in allen Übersetzungseinheiten denselben Wert zwischen 1 und 255. Namen werden als Zeiger gespeichert, nicht kopiert; ihr Speicher muss bis zum Ende der Auswertung lesbar bleiben. Zugriffe aus Hauptprogramm und Interrupts müssen Sie selbst gegeneinander absichern.
Anwendungsbeispiel
KITAQGB_TRACE("SCORE",600);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel speichert 600 und liest den Wert zur Prüfung aus dem Protokoll zurück.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
kitaqgb/lib/debug.h:43
#define KITAQGB_TRACE(name, value) debug_trace_u16((const u8*)(name), (u16)(value))KITAQGB_TRACE_U16
Wandelt einen Wert ausdrücklich in 16 Bits um und protokolliert ihn mit Namen.
Syntax
#define KITAQGB_TRACE_U16(name, value) debug_trace_u16((const u8*)(name), (u16)(value))Parameter
nameNullterminierte Bezeichnung in Speicher, der bis zur Auswertung lesbar bleiben muss.
valueAusdruck, der vor dem Protokollieren in 16 Bits umgewandelt wird.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Das Makro ist immer aktiv; Build-Einstellungen deaktivieren es nicht automatisch. Das Protokoll fasst standardmäßig 32 Einträge und verwirft bei voller Belegung neue Einträge. Wenn Sie DEBUG_TRACE_MAX überschreiben, verwenden Sie in allen Übersetzungseinheiten denselben Wert zwischen 1 und 255. Namen werden als Zeiger gespeichert, nicht kopiert; ihr Speicher muss bis zum Ende der Auswertung lesbar bleiben. Zugriffe aus Hauptprogramm und Interrupts müssen Sie selbst gegeneinander absichern.
Anwendungsbeispiel
KITAQGB_TRACE_U16("WORD2",500);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel speichert 500 und liest den Wert zur Prüfung aus dem Protokoll zurück.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
kitaqgb/lib/debug.h:42
#define KITAQGB_TRACE_U16(name, value) debug_trace_u16((const u8*)(name), (u16)(value))KITAQGB_TRACE_U8
Wandelt einen Wert ausdrücklich in 8 Bits um und protokolliert ihn mit Namen.
Syntax
#define KITAQGB_TRACE_U8(name, value) debug_trace_u8((const u8*)(name), (u8)(value))Parameter
nameNullterminierte Bezeichnung in Speicher, der bis zur Auswertung lesbar bleiben muss.
valueAusdruck, der vor dem Protokollieren in 8 Bits umgewandelt wird.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Das Makro ist immer aktiv; Build-Einstellungen deaktivieren es nicht automatisch. Das Protokoll fasst standardmäßig 32 Einträge und verwirft bei voller Belegung neue Einträge. Wenn Sie DEBUG_TRACE_MAX überschreiben, verwenden Sie in allen Übersetzungseinheiten denselben Wert zwischen 1 und 255. Namen werden als Zeiger gespeichert, nicht kopiert; ihr Speicher muss bis zum Ende der Auswertung lesbar bleiben. Zugriffe aus Hauptprogramm und Interrupts müssen Sie selbst gegeneinander absichern.
Anwendungsbeispiel
KITAQGB_TRACE_U8("CAST",0x1234);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel speichert 52. Von 0x1234 bleibt nur das niederwertige Byte 0x34 erhalten.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
kitaqgb/lib/debug.h:41
#define KITAQGB_TRACE_U8(name, value) debug_trace_u8((const u8*)(name), (u8)(value))dmg3d.h — Monochrome Drahtgitterdarstellung mit 128×120 Pixeln für DMG
Monochromes 3D-Linienzeichnen. Übergeben Sie Modelleckpunkte, Kanten und Flächen sowie Objektposition, Rotation und Skalierung. Verwenden Sie Initialisierung, Frame-Beginn, Zeichnen und Übertragung in dieser Reihenfolge. Physik ist getrennt. Winkel haben sechzehn Schritte pro Umdrehung; Modellskalierung 256 bedeutet Originalgröße.
Vec3 enthält x/y/z, Edge die Eckpunktindizes a/b und Face die Dreiecksindizes a/b/c. vertices, edges und faces in Model zeigen auf diese Arrays; die jeweilige Anzahl gibt ihre Länge an. edge_faces enthält die Nachbarflächenindizes f0/f1, bei fehlender Fläche FACE_NONE. MODEL_HIDDEN_LINES in flags fordert flächenbasierte Kantenauswahl an. Die vorzeichenbehaftete projizierte Fläche bestimmt die Ausrichtung; die Eckpunktreihenfolge ist daher wichtig.
Object speichert Modellreferenz, Position x/y/z, Winkel rx/ry/rz, scale_q8 und visible. Objekte können ein Modell teilen; Zeichnen kopiert aber keine Tabellen und schaltet deren ROM-Bänke nicht automatisch um. Referenzierte Daten müssen während des gesamten Zeichnens lesbar bleiben. CGB-Object besitzt zusätzlich einen Farbindex.
DMG3D_BeginFrame
Beginnt das Zeichnen eines Frames und deaktiviert die Verdeckungsprüfung.
Syntax
void DMG3D_BeginFrame();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 120. Deaktiviert nur die Verdeckungsfilterung. Staging wird normalerweise während der Übertragung gelöscht; Init liefert den ersten leeren Bereich. Verwirft keinen ungesendeten Frame, löscht keine Maske und setzt weder ausstehende BG-Schreibzugriffe noch Änderungsflags zurück.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet ein ganzzahlig skaliertes Linienmodell aus Eckpunkten und Zwei-Byte-Kantenindexpaaren.
Syntax
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);Parameter
verticesArray von 3D-Eckpunkten.
vertex_countAnzahl der Einträge im Eckpunktarray.
edgesEckpunktindizes je Kante im deklarierten Struct- oder Bytepaar-Format.
edge_countAnzahl der Kanten.
xX-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
yY-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
zZ-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
scaleGanzzahlige Skalierung; null wird als eins behandelt.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 120. Zeichnet per Bytepaar indizierte Kanten nach ganzzahliger Skalierung und Verschiebung; Skalierung null bedeutet eins, ohne Objektrotation oder Flächenfilterung. Projiziert höchstens 24 Eckpunkte. Übergeben Sie höchstens 128 Kantenpaare, da Byte-Offsets nach 255 umbrechen. Ungültige Eckpunkt-IDs und tiefenbedingt verworfene Endpunkte werden übersprungen; Nullarrays werden ignoriert. Koordinatenprodukte und -summen müssen als s16 darstellbar sein.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Eine projizierte waagerechte Linie und ein zusätzlicher 8×8-Block zeigen direkte Übertragungen; ein Quellbyte wechselt beim Verbrauch von 255 auf 0.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet eine vierfach zusammenhängende Bildschirmlinie einschließlich Endpunkten in den Staging-Bereich.
Syntax
void DMG3D_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by);Parameter
axX-Koordinate von Eckpunkt A in Viewport-Pixeln.
ayY-Koordinate von Eckpunkt A in Viewport-Pixeln.
bxX-Koordinate von Eckpunkt B in Viewport-Pixeln.
byY-Koordinate von Eckpunkt B in Viewport-Pixeln.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 120. Bei aktivierter Änderungsübertragung wird das umschließende Tile-Rechteck markiert und danach eine zusammenhängende Staging-Linie gezeichnet. Szenenzeichnen kann sie anhand von fünf Maskenabtastungen verwerfen. Geben Sie Endpunkte im 128×120-Viewport an; niedrige Pixelgrenzprüfungen schneiden das Segment nicht geometrisch zu.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Projiziert zwei Weltendpunkte und zeichnet eine Linie dazwischen.
Syntax
void DMG3D_DrawLine3D(w3ddmg_i16 ax, w3ddmg_i16 ay, w3ddmg_i16 az, w3ddmg_i16 bx, w3ddmg_i16 by, w3ddmg_i16 bz);Parameter
axX-Komponente des Startpunkts in Weltkoordinaten.
ayY-Komponente des Startpunkts in Weltkoordinaten.
azZ-Komponente des Startpunkts in Weltkoordinaten.
bxX-Komponente des Endpunkts in Weltkoordinaten.
byY-Komponente des Endpunkts in Weltkoordinaten.
bzZ-Komponente des Endpunkts in Weltkoordinaten.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 120. Projiziert beide Weltendpunkte und zeichnet nur, wenn beide den Tiefenbereich bestehen. Bildet keine Schnittpunkte eines kreuzenden Segments mit Nah- oder Fernebene; projizierte Endpunkte werden einzeln auf die Bildschirmränder begrenzt.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet ein Eckpunkt-Kanten-Modell an der gewünschten Position und mit der gewünschten Rotation in Originalgröße.
Syntax
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);Parameter
modelModell mit Arrays und Anzahlen für Eckpunkte, Kanten und Flächen; seine Tabellen müssen während des Aufrufs lesbar bleiben.
xX-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
yY-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
zZ-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
rxDrehung um X; sechzehn Schritte ergeben eine volle Umdrehung.
ryDrehung um Y; sechzehn Schritte ergeben eine volle Umdrehung.
rzDrehung um Z; sechzehn Schritte ergeben eine volle Umdrehung.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 120. Zeichnet ein unskaliertes Modell, indem DrawModelScaled mit Skalierung 256 aufgerufen wird.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Modelle in Originalgröße und halber Größe erscheinen über einer Szene aus einem Objektarray mit denselben Skalierungen und zeigen Projektion und Skalierung.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Skaliert ein Modell, dreht es in Y/X/Z-Reihenfolge, verschiebt und projiziert seine Eckpunkte und zeichnet die Kanten.
Syntax
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);Parameter
modelModell mit Arrays und Anzahlen für Eckpunkte, Kanten und Flächen; seine Tabellen müssen während des Aufrufs lesbar bleiben.
xX-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
yY-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
zZ-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
rxDrehung um X; sechzehn Schritte ergeben eine volle Umdrehung.
ryDrehung um Y; sechzehn Schritte ergeben eine volle Umdrehung.
rzDrehung um Z; sechzehn Schritte ergeben eine volle Umdrehung.
scale_q8Skalierung mit 256 als Einheit; nichtpositive Werte bedeuten ebenfalls Originalgröße.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 120. Skaliert bis zu 24 Eckpunkte, dreht Y/X/Z, verschiebt und projiziert sie und durchläuft dann alle edge_count-Einträge mit optionaler Nachbarflächenfilterung. edge_count ist ein Byte-Zähler. Der Flächen-Arbeitspuffer ist auf 16 begrenzt; Kantentabellen müssen alle deklarierten Einträge enthalten. Nichtpositive Skalierung bedeutet 256. Nullzeiger für Modell, Eckpunkte oder Kanten werden ignoriert. Produkte und Verschiebungen müssen in vorzeichenbehaftete 16 Bit passen; Kanten über Tiefengrenzen werden verworfen.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Modelle in Originalgröße und halber Größe erscheinen über einer Szene aus einem Objektarray mit denselben Skalierungen und zeigen Projektion und Skalierung.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet bis zu acht Objekte von nah nach fern; nähere Flächen verdecken spätere Kanten.
Syntax
void DMG3D_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count);Parameter
objectsObjektarray mit Positionen, Rotationen, Skalierungen und Sichtbarkeitsflags.
countAnzahl der übergebenen Arrayeinträge; beachten Sie die Verarbeitungsgrenze der jeweiligen Operation.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 120. Sortiert bis zu acht Objektursprünge nach Kameratiefe von nah nach fern. Zeichnet sichtbare gültige Modelle und markiert Vorderseiten-Begrenzungsrechtecke für spätere Objekte. Der erste sortierte Platz überspringt Maskentests; der letzte benötigt keinen neuen Verdeckungsbereich. Dies ist grobes Linienverwerfen, kein Tiefenpuffer. Null oder leere Eingaben werden ignoriert; Aufruferdaten und aktueller Projektionscache müssen während des Durchlaufs gültig bleiben.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Modelle in Originalgröße und halber Größe erscheinen über einer Szene aus einem Objektarray mit denselben Skalierungen und zeigen Projektion und Skalierung.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Übergibt ausstehende Hintergrund-Schreibzugriffe und vorbereitete Zeichnungen an VRAM.
Syntax
void DMG3D_EndFrame();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 120. Wartet auf den nächsten VBlank und führt BG-Schreibzugriffe aus. Verbraucht dann optional zuerst die Hilfsstreifen, bevor geänderte Tiles oder das gesamte Haupt-Staging übertragen werden. Wegen überlappender Hilfs- und Hauptquellen ist diese Reihenfolge wichtig. STAT wird über Zugriffsfenster hinweg weiter abgefragt; die Aktualisierung muss nicht in einen VBlank passen.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Projiziert nach vorn gerichtete Modelldreiecke und löscht vorbereitete Pixel in ihrem Inneren.
Syntax
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);Parameter
modelModell mit Arrays und Anzahlen für Eckpunkte, Kanten und Flächen; seine Tabellen müssen während des Aufrufs lesbar bleiben.
xX-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
yY-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
zZ-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
rxDrehung um X; sechzehn Schritte ergeben eine volle Umdrehung.
ryDrehung um Y; sechzehn Schritte ergeben eine volle Umdrehung.
rzDrehung um Z; sechzehn Schritte ergeben eine volle Umdrehung.
scale_q8Skalierung mit 256 als Einheit; nichtpositive Werte bedeuten ebenfalls Originalgröße.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 120. Projiziert bis zu 24 Eckpunkte und löscht das Innere nach vorn gerichteter Dreiecke aus dem Staging-Bereich für ein Modell mit Verdeckungsflags und Flächendaten. Nichtpositive Skalierung bedeutet 256, also Originalgröße. Bis zu 16 Flächen werden betrachtet; Flächen über Tiefengrenzen werden übersprungen. Ersetzt auch gemeinsame Projektionscaches, aktualisiert aber kein VRAM.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Projizierte Flächen löschen einen gefüllten Bereich, sodass erhaltene und gelöschte Bereiche sichtbar werden.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Löscht einen waagerechten Span einschließlich Endpunkten in einer vorbereiteten Zeile.
Syntax
void DMG3D_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1);Parameter
yPixel-Y-Koordinate der zu löschenden Zeile.
x0Unterer X-Endpunkt in Viewport-Pixeln; Reihenfolge und Begrenzung richten sich nach den Hinweisen zu dieser Operation.
x1Oberer X-Endpunkt in Viewport-Pixeln; Reihenfolge und Begrenzung richten sich nach den Hinweisen zu dieser Operation.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 120. Ordnet die X-Endpunkte und löscht den vorbereiteten Span einschließlich Endpunkten. Beide müssen in 0..127 liegen; ungültiges Y wird ignoriert. Die Routine begrenzt X nicht automatisch.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Löscht ein Bildschirmdreieck über waagerechte Rasterzeilen-Spans aus dem Staging-Bereich.
Syntax
void DMG3D_EraseTriangle2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by, w3ddmg_u8 cx, w3ddmg_u8 cy);Parameter
axX-Koordinate von Eckpunkt A in Viewport-Pixeln.
ayY-Koordinate von Eckpunkt A in Viewport-Pixeln.
bxX-Koordinate von Eckpunkt B in Viewport-Pixeln.
byY-Koordinate von Eckpunkt B in Viewport-Pixeln.
cxX-Koordinate von Eckpunkt C in Viewport-Pixeln.
cyY-Koordinate von Eckpunkt C in Viewport-Pixeln.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 120. Löscht ein Dreieck aus vorbereiteten Pixeln über ganzzahlige Rasterzeilenschnittpunkte. Geben Sie Viewport-Koordinaten an. Entartete Dreiecke werden ignoriert; Verdeckungsmaske und VRAM bleiben unverändert.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Projizierte Flächen löschen einen gefüllten Bereich, sodass erhaltene und gelöschte Bereiche sichtbar werden.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Initialisiert LCD, Tiles und Hintergrundkarte für einen monochromen Drahtgitter-Viewport.
Syntax
void DMG3D_Init();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 120. Übernimmt den LCD-Zustand, löscht Tile-VRAM und BG-Karte und richtet einen 16×15-Viewport ab Kartentile (3,1) ein. Setzt Scrolling (8,0), BGP=0xB4 und BG-Anzeige. Setzt Kamera, Warteschlangen, Übertragungsmodi, beide Änderungstabellen und Staging zurück. Reservieren Sie 0xD000..0xDFFF und erhalten Sie die WRAM-Einblendung; Hilfsspeicher verwendet dieselben Adressen. Rufen Sie vor dem Zeichnen BeginFrame auf, um den Verdeckungszustand herzustellen.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Projiziert einen Weltpunkt durch die Kamera in Viewport-Koordinaten.
Syntax
w3ddmg_u8 DMG3D_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy);Parameter
xX-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
yY-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
zZ-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
sxGültiger beschreibbarer u8-Zeiger für die projizierte X-Koordinate.
syGültiger beschreibbarer u8-Zeiger für die projizierte Y-Koordinate.
Rückgabewert
Liefert 1 bei erfolgreicher Projektion oder 0 bei verworfener Tiefe.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 120. Projiziert einen Weltpunkt mit der aktuellen Kamera. Ungültige Tiefe liefert null ohne Ausgabeänderung; bei Erfolg werden auf 128×120 begrenzte Koordinaten geschrieben. Beide Ausgabezeiger müssen gültig sein. Koordinatendifferenzen müssen in s16 passen.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Reiht einen Tile-Nummer-Schreibzugriff für eine Hintergrundkartenzelle ein.
Syntax
void DMG3D_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile);Parameter
xX-Tile-Koordinate in der 32×32-Hintergrundkarte.
yY-Tile-Koordinate in der 32×32-Hintergrundkarte.
tileAcht-Bit-Tile-Nummer für die Hintergrundzelle.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 120. Reiht einen Tile-Schreibzugriff auf die 32×32-Karte bei 0x9800 für EndFrame ein. Ungültige Kartenkoordinaten und Anfragen über 48 ausstehende Schreibzugriffe hinaus werden ohne Meldung ignoriert. Diese Warteschlange ist von der allgemeinen vram-Bibliothekswarteschlange getrennt.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Dreht einen Punkt mit den angegebenen Winkeln direkt in seinen Variablen.
Syntax
void DMG3D_RotatePoint(w3ddmg_i16* x, w3ddmg_i16* y, w3ddmg_i16* z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz);Parameter
xSeparater beschreibbarer s16-Zeiger für die X-Komponente.
ySeparater beschreibbarer s16-Zeiger für die Y-Komponente.
zSeparater beschreibbarer s16-Zeiger für die Z-Komponente.
rxDrehung um X; sechzehn Schritte ergeben eine volle Umdrehung.
ryDrehung um Y; sechzehn Schritte ergeben eine volle Umdrehung.
rzDrehung um Z; sechzehn Schritte ergeben eine volle Umdrehung.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 120. Dreht direkt in den Variablen in Y/X/Z-Reihenfolge mit 16 Schritten pro Umdrehung. Ein Nullzeiger für eine Komponente macht den gesamten Aufruf wirkungslos; verwenden Sie getrennte Zeiger. Jede Achsrotation begrenzt ihre Eingaben auf ±220.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Modelle in Originalgröße und halber Größe erscheinen über einer Szene aus einem Objektarray mit denselben Skalierungen und zeigen Projektion und Skalierung.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Wählt, ob EndFrame auch die Hilfsstreifen überträgt.
Syntax
void DMG3D_SetAuxTransfer(w3ddmg_u8 flag);Parameter
flagNull deaktiviert die Übertragungsfunktion; jeder andere Wert aktiviert sie.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 120. Speichert die Hilfsübertragungsfreigabe für EndFrame; jeder Wert ungleich null aktiviert sie. Hier werden keine Daten kopiert oder gelöscht. Hilfsquellbytes teilen sich die Adressen mit dem Haupt-Staging-Bereich.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Die Hilfsübertragung verbraucht einen Teil des Haupt-Staging-Bereichs; dadurch entsteht bei Bildschirmkoordinate (80,24) ein schwarzer 8×8-Block.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Speichert Kameraposition und -ausrichtung für spätere Projektionen.
Syntax
void DMG3D_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 pitch, w3ddmg_u8 yaw, w3ddmg_u8 roll);Parameter
xX-Komponente der Kamera in Weltkoordinaten.
yY-Komponente der Kamera in Weltkoordinaten.
zZ-Komponente der Kamera in Weltkoordinaten.
pitchDrehung um X; sechzehn Schritte ergeben eine volle Umdrehung.
yawDrehung um Y; sechzehn Schritte ergeben eine volle Umdrehung.
rollDrehung um Z; sechzehn Schritte ergeben eine volle Umdrehung.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 120. Speichert Kameraposition und -winkel für späteres Zeichnen; 16 Winkelschritte ergeben eine Umdrehung. Vorhandene Zeichnungen werden nicht neu projiziert und Eingabebereiche nicht geprüft.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Wählt die Übertragung geänderter Tiles für den Haupt-Viewport mit 120 Zeilen.
Syntax
void DMG3D_SetDirtyTransfer(w3ddmg_u8 flag);Parameter
flagNull deaktiviert die Übertragungsfunktion; jeder andere Wert aktiviert sie.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 120. Speichert die Freigabe für Änderungsübertragung und löscht beide Änderungsverläufe sowie den Haupt-Staging-Bereich, selbst bei unverändertem Wert. VRAM bleibt erhalten; beim Aktivieren über einem alten Bild können unmarkierte alte Tiles zurückbleiben. Sorgen Sie daher für einen sauberen angezeigten Ausgangszustand.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Der vorherige Rahmen links oben verschwindet; nur ein neuer Rahmen bei Bildschirmkoordinaten (96,88)..(120,112) bleibt.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Schreibt die Zuordnung der vier Helligkeitsstufen ins monochrome Hintergrund-Palettenregister BGP.
Syntax
void DMG3D_SetPalette(w3ddmg_u8 bgp);Parameter
bgpBGP-Registerwert mit vier Zwei-Bit-Helligkeitszuordnungen.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 120. Schreibt die rohe DMG-BGP-Palettencodierung sofort, ohne Frame-Synchronisierung.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Überträgt sechs Hilfsstreifen sofort und löscht ihre Quellbytes.
Syntax
void DMG3D_TransferAuxNow();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 120. Überträgt und verbraucht die Hilfsquellstreifen sofort, unabhängig von der Hilfsfreigabe. Wartet nicht auf den VBlank-Start und aktualisiert weder Änderungsverlauf noch BG-Warteschlange. Die Quelle überlappt den Haupt-Staging-Bereich; stimmen Sie die Übertragungen aufeinander ab.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Eine projizierte waagerechte Linie und ein zusätzlicher 8×8-Block zeigen direkte Übertragungen; ein Quellbyte wechselt beim Verbrauch von 255 auf 0.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Überträgt den gesamten Haupt-Staging-Bereich sofort und löscht die verbrauchten Quellpixel.
Syntax
void DMG3D_TransferMainNow();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 120. Überträgt und verbraucht den gesamten Haupt-Staging-Bereich sofort, fragt dabei STAT ab, wartet aber nicht auf den nächsten VBlank. Ignoriert Übertragungsfreigaben und erhält Änderungsverläufe sowie BG-Tile-Warteschlange; der Aufrufer koordiniert den Frame-Ablauf.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Eine projizierte waagerechte Linie und ein zusätzlicher 8×8-Block zeigen direkte Übertragungen; ein Quellbyte wechselt beim Verbrauch von 255 auf 0.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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 — Objektpools mit festen Arrays
entity ist ein Objektpool mit einem Array fester Größe für Zustände wie Gegner, Geschosse und Sammelobjekte. Sie belegen einen freien Platz, greifen über dessen ID darauf zu und verwenden den Platz erneut, sobald das Objekt nicht mehr benötigt wird. Es wird kein Heap-Speicher angefordert. Koordinaten- und Geschwindigkeitseinheiten, Bewegung, Kollisionen und Timer-Aktualisierungen legt das Spiel fest.
Binden Sie entity.h ein und kompilieren Sie entity.c genau einmal. Rufen Sie zuerst entity_init auf und prüfen Sie, dass entity_create nicht 0xFF zurückgibt. ENTITY_MAX hat standardmäßig den Wert 16. Die IDs unterstützen 1 bis 255 Plätze; die tatsächlich nutzbare Anzahl hängt jedoch vom verfügbaren RAM ab. Verwenden Sie in allen Übersetzungseinheiten dieselbe Kapazitätsdefinition.
Der von entity_get zurückgegebene Zeiger verweist auf wiederverwendbaren Poolspeicher. Nach der Freigabe kann dieselbe ID ein anderes Objekt bezeichnen. Weder ID noch Zeiger stellen daher eine dauerhafte Identität dar. entity_destroy deaktiviert lediglich den Platz. Der Aufrufer muss Sprites ausblenden oder freigeben und andere Ressourcen aufräumen. Das Feld sprite dient der Verwaltung und aktualisiert OAM nicht automatisch.
entity_update_all und entity_draw_all durchlaufen aktive Plätze in aufsteigender ID-Reihenfolge und rufen fn(id) auf. Implementieren Sie die eigentliche Aktualisierung oder Darstellung im Callback. Ein Null-Callback bewirkt nichts. Wenn ein Callback einen späteren Platz belegt oder freigibt, wirkt sich das bereits auf den laufenden Durchlauf aus. Ein Aktualisierungsdurchlauf vor dem Zeichendurchlauf trennt beide Aufgaben.
entity_clear_all
Gibt alle Entities frei und setzt ihre Felder einschließlich der Markierung für fehlende Sprites zurück.
Syntax
void entity_clear_all();Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Der Pool ist ein festes Array ohne Heap-Allokation. ENTITY_MAX ist standardmäßig 16 und muss in allen Übersetzungseinheiten gleich mit einem Wert von 1 bis 255 definiert sein. IDs beginnen bei null; 0xFF kennzeichnet einen Fehlschlag.
Setzt in allen Plätzen active,type,x,y,vx,vy,state,timer auf null und sprite auf 0xFF. Hardware-Sprites werden dadurch weder verborgen noch freigegeben; ihre Ressourcen müssen separat aufgeräumt werden.
Anwendungsbeispiel
entity_clear_all();
after_clear = entity_count_active();
if (after_clear != 0 || entity_get(reused) != 0) { failures++; }Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das vollständige Programm zeigt den Lebenszyklus eines wiederverwendbaren Platzes. Lesen Sie Zahlen mit ihren Beschriftungen: CREATED 002 nach zwei Belegungen, AFTER FREE 001 nach Freigabe der ersten, REUSED ID 000 bei Wiederverwendung der kleinsten freien ID und AFTER CLEAR 000 nach Leeren des Pools. Geprüft werden auch null-Abfrage nach Freigabe und zurückgesetzte Felder nach Neubelegung. FAILED CHECKS 000 bestätigt die erwarteten Werte.
Der GB-Durchlauf ruft jeden Callback für beide aktiven Entities auf: UPDATE CALLS 002 und DRAW CALLS 002. Der Aktualisierungs-Callback verschiebt beide um ein Tile nach rechts. Der Zeichen-Callback setzt zur Darstellung der Objekte A auf Tile (3,12) und B auf (7,12). Das sind vom Callback gezeichnete Hintergrund-Schrift-Tiles, keine automatisch belegten Sprites.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zählt belegte Entity-Plätze, ohne ihren Zustand zu ändern.
Syntax
u8 entity_count_active();Rückgabewert
Anzahl der Plätze mit einem von null verschiedenen active-Byte, von 0 bis ENTITY_MAX. Das ist die Belegung, nicht die höchste ID oder die Anzahl sichtbarer Sprites.
Bedingungen und Grenzen
Der Pool ist ein festes Array ohne Heap-Allokation. ENTITY_MAX ist standardmäßig 16 und muss in allen Übersetzungseinheiten gleich mit einem Wert von 1 bis 255 definiert sein. IDs beginnen bei null; 0xFF kennzeichnet einen Fehlschlag.
Anwendungsbeispiel
created = entity_count_active();
if (created != 2) { failures++; }Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das vollständige Programm zeigt den Lebenszyklus eines wiederverwendbaren Platzes. Lesen Sie Zahlen mit ihren Beschriftungen: CREATED 002 nach zwei Belegungen, AFTER FREE 001 nach Freigabe der ersten, REUSED ID 000 bei Wiederverwendung der kleinsten freien ID und AFTER CLEAR 000 nach Leeren des Pools. Geprüft werden auch null-Abfrage nach Freigabe und zurückgesetzte Felder nach Neubelegung. FAILED CHECKS 000 bestätigt die erwarteten Werte.
Der GB-Durchlauf ruft jeden Callback für beide aktiven Entities auf: UPDATE CALLS 002 und DRAW CALLS 002. Der Aktualisierungs-Callback verschiebt beide um ein Tile nach rechts. Der Zeichen-Callback setzt zur Darstellung der Objekte A auf Tile (3,12) und B auf (7,12). Das sind vom Callback gezeichnete Hintergrund-Schrift-Tiles, keine automatisch belegten Sprites.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Reserviert eine Entity mit Typ und Position; liefert ihre wiederverwendbare ID oder bei vollem Pool 0xFF.
Syntax
u8 entity_create(u8 type, s16 x, s16 y);Parameter
typeVom Spiel definierte Typkennung von 0 bis 255. Der Pool speichert sie, wählt damit aber weder Verhalten noch Zeichenroutinen aus.
x, yVorzeichenbehaftete 16-Bit-Koordinaten (
-32768–32767). Die Einheit bestimmt das Spiel, etwa Pixel oder Q8.8. Der Pool rechnet keine Einheiten um, begrenzt keine Positionen und wendet Geschwindigkeiten nicht automatisch an.
Rückgabewert
Die kleinste freie Platz-ID (0–ENTITY_MAX-1) oder 0xFF, falls keiner frei ist. Erfolgreiche Belegung setzt active=1, speichert Typ und Position, löscht Geschwindigkeit/Zustand/Timer und setzt sprite=0xFF.
Bedingungen und Grenzen
Der Pool ist ein festes Array ohne Heap-Allokation. ENTITY_MAX ist standardmäßig 16 und muss in allen Übersetzungseinheiten gleich mit einem Wert von 1 bis 255 definiert sein. IDs beginnen bei null; 0xFF kennzeichnet einen Fehlschlag.
Anwendungsbeispiel
first = entity_create(1, 2, 12);
second = entity_create(2, 6, 12);
if (first == 0xFF || second == 0xFF) { failures++; }Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das vollständige Programm zeigt den Lebenszyklus eines wiederverwendbaren Platzes. Lesen Sie Zahlen mit ihren Beschriftungen: CREATED 002 nach zwei Belegungen, AFTER FREE 001 nach Freigabe der ersten, REUSED ID 000 bei Wiederverwendung der kleinsten freien ID und AFTER CLEAR 000 nach Leeren des Pools. Geprüft werden auch null-Abfrage nach Freigabe und zurückgesetzte Felder nach Neubelegung. FAILED CHECKS 000 bestätigt die erwarteten Werte.
Der GB-Durchlauf ruft jeden Callback für beide aktiven Entities auf: UPDATE CALLS 002 und DRAW CALLS 002. Der Aktualisierungs-Callback verschiebt beide um ein Tile nach rechts. Der Zeichen-Callback setzt zur Darstellung der Objekte A auf Tile (3,12) und B auf (7,12). Das sind vom Callback gezeichnete Hintergrund-Schrift-Tiles, keine automatisch belegten Sprites.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Gibt den Platz von Entity id frei; die Nutzdaten werden erst bei erneuter Belegung zurückgesetzt.
Syntax
void entity_destroy(u8 id);Parameter
idWiederverwendbarer Platzindex von 0 bis
ENTITY_MAX-1. Werte außerhalb dieses Bereichs sind ungültig. Das Freigeben einer ungültigen ID bewirkt nichts; die Abfrage liefert null.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Der Pool ist ein festes Array ohne Heap-Allokation. ENTITY_MAX ist standardmäßig 16 und muss in allen Übersetzungseinheiten gleich mit einem Wert von 1 bis 255 definiert sein. IDs beginnen bei null; 0xFF kennzeichnet einen Fehlschlag.
Freigeben löscht nur active, nicht die übrigen Felder, Sprites oder Assets. Spätere Belegung kann dieselbe ID und Adresse für eine andere Entity verwenden. Das Spiel muss die zugehörigen Ressourcen selbst aufräumen.
Anwendungsbeispiel
entity_destroy(first);
after_free = entity_count_active();
if (entity_get(first) != 0 || after_free != 1) { failures++; }Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das vollständige Programm zeigt den Lebenszyklus eines wiederverwendbaren Platzes. Lesen Sie Zahlen mit ihren Beschriftungen: CREATED 002 nach zwei Belegungen, AFTER FREE 001 nach Freigabe der ersten, REUSED ID 000 bei Wiederverwendung der kleinsten freien ID und AFTER CLEAR 000 nach Leeren des Pools. Geprüft werden auch null-Abfrage nach Freigabe und zurückgesetzte Felder nach Neubelegung. FAILED CHECKS 000 bestätigt die erwarteten Werte.
Der GB-Durchlauf ruft jeden Callback für beide aktiven Entities auf: UPDATE CALLS 002 und DRAW CALLS 002. Der Aktualisierungs-Callback verschiebt beide um ein Tile nach rechts. Der Zeichen-Callback setzt zur Darstellung der Objekte A auf Tile (3,12) und B auf (7,12). Das sind vom Callback gezeichnete Hintergrund-Schrift-Tiles, keine automatisch belegten Sprites.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Durchläuft aktive Entities und übergibt jede ID an den Zeichen-Callback. Der Durchlauf entspricht entity_update_all; ohne vom Callback eingereichte Zeichendaten werden keine Sprites oder Pixel gezeichnet.
Syntax
void entity_draw_all(EntityFn fn);Parameter
fnFunktionszeiger mit Signatur
void fn(u8 id). Er erhält eine Platz-ID; auf Felder greifen Sie überentity_get(id)zu. Null ist zulässig und führt zu keinen Aufrufen.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Der Pool ist ein festes Array ohne Heap-Allokation. ENTITY_MAX ist standardmäßig 16 und muss in allen Übersetzungseinheiten gleich mit einem Wert von 1 bis 255 definiert sein. IDs beginnen bei null; 0xFF kennzeichnet einen Fehlschlag.
Der Durchlauf prüft die Aktivität erst beim Erreichen eines Platzes. Ein Callback kann spätere Plätze deaktivieren und damit überspringen lassen oder aktivieren und noch im selben Durchlauf besuchen lassen. Es wird kein Schnappschuss der anfänglichen Belegung verwendet.
Anwendungsbeispiel
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++; }Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das vollständige Programm zeigt den Lebenszyklus eines wiederverwendbaren Platzes. Lesen Sie Zahlen mit ihren Beschriftungen: CREATED 002 nach zwei Belegungen, AFTER FREE 001 nach Freigabe der ersten, REUSED ID 000 bei Wiederverwendung der kleinsten freien ID und AFTER CLEAR 000 nach Leeren des Pools. Geprüft werden auch null-Abfrage nach Freigabe und zurückgesetzte Felder nach Neubelegung. FAILED CHECKS 000 bestätigt die erwarteten Werte.
Der GB-Durchlauf ruft jeden Callback für beide aktiven Entities auf: UPDATE CALLS 002 und DRAW CALLS 002. Der Aktualisierungs-Callback verschiebt beide um ein Tile nach rechts. Der Zeichen-Callback setzt zur Darstellung der Objekte A auf Tile (3,12) und B auf (7,12). Das sind vom Callback gezeichnete Hintergrund-Schrift-Tiles, keine automatisch belegten Sprites.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Liefert einen Zeiger auf die aktive Entity oder null bei ungültiger bzw. freier ID. Der Speicherplatz wird wiederverwendet.
Syntax
Entity* entity_get(u8 id);Parameter
idWiederverwendbarer Platzindex von 0 bis
ENTITY_MAX-1. Werte außerhalb dieses Bereichs sind ungültig. Das Freigeben einer ungültigen ID bewirkt nichts; die Abfrage liefert null.
Rückgabewert
Schreibbarer Zeiger auf den aktiven Pool-Platz oder null bei ungültiger bzw. inaktiver ID. Der Speicher gehört dem Pool; geben Sie ihn nicht selbst frei und verwenden Sie den Zeiger nicht als dauerhafte Identität über Freigabe und Neubelegung hinweg.
Bedingungen und Grenzen
Der Pool ist ein festes Array ohne Heap-Allokation. ENTITY_MAX ist standardmäßig 16 und muss in allen Übersetzungseinheiten gleich mit einem Wert von 1 bis 255 definiert sein. IDs beginnen bei null; 0xFF kennzeichnet einen Fehlschlag.
Freigeben löscht nur active, nicht die übrigen Felder, Sprites oder Assets. Spätere Belegung kann dieselbe ID und Adresse für eine andere Entity verwenden. Das Spiel muss die zugehörigen Ressourcen selbst aufräumen.
Anwendungsbeispiel
current_entity = entity_get(first);
if (current_entity != 0) { current_entity->vx = 5; }
else { failures++; }Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das vollständige Programm zeigt den Lebenszyklus eines wiederverwendbaren Platzes. Lesen Sie Zahlen mit ihren Beschriftungen: CREATED 002 nach zwei Belegungen, AFTER FREE 001 nach Freigabe der ersten, REUSED ID 000 bei Wiederverwendung der kleinsten freien ID und AFTER CLEAR 000 nach Leeren des Pools. Geprüft werden auch null-Abfrage nach Freigabe und zurückgesetzte Felder nach Neubelegung. FAILED CHECKS 000 bestätigt die erwarteten Werte.
Der GB-Durchlauf ruft jeden Callback für beide aktiven Entities auf: UPDATE CALLS 002 und DRAW CALLS 002. Der Aktualisierungs-Callback verschiebt beide um ein Tile nach rechts. Der Zeichen-Callback setzt zur Darstellung der Objekte A auf Tile (3,12) und B auf (7,12). Das sind vom Callback gezeichnete Hintergrund-Schrift-Tiles, keine automatisch belegten Sprites.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Initialisiert alle Plätze im Entity-Pool.
Syntax
void entity_init();Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Der Pool ist ein festes Array ohne Heap-Allokation. ENTITY_MAX ist standardmäßig 16 und muss in allen Übersetzungseinheiten gleich mit einem Wert von 1 bis 255 definiert sein. IDs beginnen bei null; 0xFF kennzeichnet einen Fehlschlag.
Setzt in allen Plätzen active,type,x,y,vx,vy,state,timer auf null und sprite auf 0xFF. Hardware-Sprites werden dadurch weder verborgen noch freigegeben; ihre Ressourcen müssen separat aufgeräumt werden.
Anwendungsbeispiel
entity_init();
if (entity_count_active() != 0) { failures++; }Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das vollständige Programm zeigt den Lebenszyklus eines wiederverwendbaren Platzes. Lesen Sie Zahlen mit ihren Beschriftungen: CREATED 002 nach zwei Belegungen, AFTER FREE 001 nach Freigabe der ersten, REUSED ID 000 bei Wiederverwendung der kleinsten freien ID und AFTER CLEAR 000 nach Leeren des Pools. Geprüft werden auch null-Abfrage nach Freigabe und zurückgesetzte Felder nach Neubelegung. FAILED CHECKS 000 bestätigt die erwarteten Werte.
Der GB-Durchlauf ruft jeden Callback für beide aktiven Entities auf: UPDATE CALLS 002 und DRAW CALLS 002. Der Aktualisierungs-Callback verschiebt beide um ein Tile nach rechts. Der Zeichen-Callback setzt zur Darstellung der Objekte A auf Tile (3,12) und B auf (7,12). Das sind vom Callback gezeichnete Hintergrund-Schrift-Tiles, keine automatisch belegten Sprites.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Durchläuft aktive Plätze nach aufsteigender ID und ruft für jeden einmal fn(id) auf. Bewegung, Kollisionen oder Timer implementiert der Callback; der Pool stellt diese Logik nicht bereit. Ein null-Callback bewirkt nichts.
Syntax
void entity_update_all(EntityFn fn);Parameter
fnFunktionszeiger mit Signatur
void fn(u8 id). Er erhält eine Platz-ID; auf Felder greifen Sie überentity_get(id)zu. Null ist zulässig und führt zu keinen Aufrufen.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Der Pool ist ein festes Array ohne Heap-Allokation. ENTITY_MAX ist standardmäßig 16 und muss in allen Übersetzungseinheiten gleich mit einem Wert von 1 bis 255 definiert sein. IDs beginnen bei null; 0xFF kennzeichnet einen Fehlschlag.
Der Durchlauf prüft die Aktivität erst beim Erreichen eines Platzes. Ein Callback kann spätere Plätze deaktivieren und damit überspringen lassen oder aktivieren und noch im selben Durchlauf besuchen lassen. Es wird kein Schnappschuss der anfänglichen Belegung verwendet.
Anwendungsbeispiel
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++; }Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das vollständige Programm zeigt den Lebenszyklus eines wiederverwendbaren Platzes. Lesen Sie Zahlen mit ihren Beschriftungen: CREATED 002 nach zwei Belegungen, AFTER FREE 001 nach Freigabe der ersten, REUSED ID 000 bei Wiederverwendung der kleinsten freien ID und AFTER CLEAR 000 nach Leeren des Pools. Geprüft werden auch null-Abfrage nach Freigabe und zurückgesetzte Felder nach Neubelegung. FAILED CHECKS 000 bestätigt die erwarteten Werte.
Der GB-Durchlauf ruft jeden Callback für beide aktiven Entities auf: UPDATE CALLS 002 und DRAW CALLS 002. Der Aktualisierungs-Callback verschiebt beide um ein Tile nach rechts. Der Zeichen-Callback setzt zur Darstellung der Objekte A auf Tile (3,12) und B auf (7,12). Das sind vom Callback gezeichnete Hintergrund-Schrift-Tiles, keine automatisch belegten Sprites.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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-Festkommaarithmetik und Rechtecke
Q8.8-Arithmetik stellt gebrochene Koordinaten und Geschwindigkeiten mit Ganzzahlen dar und ergänzt sie um Kollisionsprüfungen für Rechtecke und Punkte. Beachten Sie die Genauigkeit und Wertebereiche jeder Operation.
fix_div
Dividiert Q8.8-Werte nach einer Verringerung der Operandengenauigkeit.
Syntax
fix8 fix_div(fix8 a, fix8 b);Parameter
aLinker Operand im Q8.8-Format.
bRechter Operand im Q8.8-Format.
Rückgabewert
Gibt einen Q8.8-Quotienten zurück, bei b == 0 hingegen null.
Bedingungen und Grenzen
Berechnet wird ((a >> 4) * 256) / (b >> 4). Ein von null verschiedener Divisor darf durch die Verschiebung nicht null werden; übergeben Sie daher keine positiven Rohwerte von 1 bis 15. Auch der skalierte Zähler muss in 16 Bits passen.
Anwendungsbeispiel
result[3]=fix_div(768,512);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
3,0 geteilt durch 2,0 ergibt 1,5 (Rohwert 384). Ein eigener Test prüft den ausdrücklich vorgesehenen Rückgabewert bei Divisor null.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Wandelt eine ganzzahlige Koordinate oder Geschwindigkeit in Q8.8 um, damit nachfolgende Berechnungen Nachkommastellen erhalten können.
Syntax
fix8 fix_from_int(s16 n);Parameter
nDie umzuwandelnde ganze Zahl im Bereich −128 bis 127.
Rückgabewert
Gibt den Rohwert n × 256 zurück.
Bedingungen und Grenzen
fix8 ist ein vorzeichenbehaftetes Q8.8-Format: Der Rohwert 256 steht für 1,0. Zwischenwerte und Ergebnisse müssen im 16-Bit-Wertebereich bleiben.
Anwendungsbeispiel
result[0]=fix_from_int(-3);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel wandelt −3 um. Die Anzeige −00768 entspricht dem Q8.8-Rohwert −768.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Interpoliert mit einem 8-Bit-Gewicht von einem Q8.8-Wert in Richtung eines anderen.
Syntax
fix8 fix_lerp(fix8 a, fix8 b, u8 t_q8);Parameter
aLinker Operand im Q8.8-Format.
bRechter Operand im Q8.8-Format.
t_q8Interpolationsgewicht von 0 bis 255.
Rückgabewert
Gibt den näherungsweise interpolierten Q8.8-Wert zurück.
Bedingungen und Grenzen
Differenz und Gewicht werden jeweils um vier Bits nach rechts geschoben. Dadurch gibt es nur 16 Gewichtsstufen; selbst 255 muss den Endwert nicht erreichen. b - a und das Endergebnis müssen im 16-Bit-Bereich bleiben.
Anwendungsbeispiel
result[4]=fix_lerp(0,1024,128);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Zwischen 0 und 4,0 ergibt Gewicht 128 den Wert 2,0 (Rohwert 512). Gewicht 255 liefert 3,75 (Rohwert 960) und zeigt damit, dass der Endwert nicht erreicht wird.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Multipliziert zwei Q8.8-Werte mit einem rechenarmen Näherungsverfahren.
Syntax
fix8 fix_mul(fix8 a, fix8 b);Parameter
aLinker Operand im Q8.8-Format.
bRechter Operand im Q8.8-Format.
Rückgabewert
Gibt das Produkt im Q8.8-Format zurück.
Bedingungen und Grenzen
Vor der Multiplikation wird jeder Operand um vier Bits nach rechts geschoben; seine vier niederwertigsten Bits gehen verloren. Das ist ungenauer als ein vollständiges 16-mal-16-Bit-Produkt. fix8 ist vorzeichenbehaftetes Q8.8, wobei der Rohwert 256 für 1,0 steht. Zwischenwerte und Ergebnisse müssen im 16-Bit-Bereich bleiben.
Anwendungsbeispiel
result[2]=fix_mul(384,512);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
1,5 mal 2,0 ergibt 3,0 (Rohwert 768). Das Programm prüft auch die Quantisierung: Rohwert 271 mal Rohwert 271 ergibt 256.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Gewinnt eine ganzzahlige Koordinate aus Q8.8, indem die Nachkommabits verworfen werden. Negative Werte werden gegen minus unendlich abgerundet.
Syntax
s16 fix_to_int(fix8 x);Parameter
xDer in eine ganze Zahl umzuwandelnde Q8.8-Wert.
Rückgabewert
Gibt eine vorzeichenbehaftete ganze Zahl zurück.
Bedingungen und Grenzen
fix8 ist ein vorzeichenbehaftetes Q8.8-Format: Der Rohwert 256 steht für 1,0. Zwischenwerte und Ergebnisse müssen im 16-Bit-Wertebereich bleiben.
Anwendungsbeispiel
result[1]=fix_to_int(-384);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Der Rohwert −384 (−1,5) ergibt −2 und wird als −00002 angezeigt. Ein Grenzwerttest bestätigt außerdem, dass der Rohwert −1 zu −1 wird.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Ermittelt den Betrag eines vorzeichenbehafteten 16-Bit-Werts.
Syntax
s16 kq_abs_s16(s16 v);Parameter
vVorzeichenbehafteter 16-Bit-Wert, dessen Betrag benötigt wird.
Rückgabewert
Gibt einen nichtnegativen Betrag zurück, mit Ausnahme des nicht darstellbaren Betrags von −32768.
Bedingungen und Grenzen
Der positive Betrag 32768 passt nicht in s16. Schließen Sie −32768 aus, wenn das Ergebnis nichtnegativ sein muss.
Anwendungsbeispiel
result[0]=kq_abs_s16(-123);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel wandelt −123 in 123 um, etwa zur Bestimmung des Betrags einer Koordinatendifferenz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Begrenzt eine Koordinate oder Geschwindigkeit auf ein Intervall einschließlich seiner Grenzen.
Syntax
s16 kq_clamp_s16(s16 v, s16 lo, s16 hi);Parameter
vZu begrenzender Wert mit Vorzeichen.
loEinschließlich geltende Untergrenze.
hiEinschließlich geltende Obergrenze.
Rückgabewert
Gibt unterhalb des Intervalls lo, oberhalb hi und innerhalb v zurück.
Bedingungen und Grenzen
Geben Sie ein gültiges Intervall mit lo <= hi an.
Anwendungsbeispiel
result[3]=kq_clamp_s16(25,-10,10);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Begrenzen von 25 auf −10…10 ergibt 10. Geprüft werden auch −11→−10 an der unteren Grenze und 3→3 innerhalb des Intervalls.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Wählt den größeren von zwei vorzeichenbehafteten 16-Bit-Werten.
Syntax
s16 kq_max_s16(s16 a, s16 b);Parameter
aErster zu vergleichender Wert mit Vorzeichen.
bZweiter zu vergleichender Wert mit Vorzeichen.
Rückgabewert
Gibt den ausgewählten Operanden zurück.
Bedingungen und Grenzen
Der Vergleich berücksichtigt das Vorzeichen. Bei gleichen Operanden wird dieser gemeinsame Wert zurückgegeben; beide Eingaben bleiben unverändert.
Anwendungsbeispiel
result[2]=kq_max_s16(-7,4);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Der Vergleich von −7 und 4 ergibt 4. Negative Ergebnisse werden mit Minuszeichen angezeigt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Wählt den kleineren von zwei vorzeichenbehafteten 16-Bit-Werten.
Syntax
s16 kq_min_s16(s16 a, s16 b);Parameter
aErster zu vergleichender Wert mit Vorzeichen.
bZweiter zu vergleichender Wert mit Vorzeichen.
Rückgabewert
Gibt den ausgewählten Operanden zurück.
Bedingungen und Grenzen
Der Vergleich berücksichtigt das Vorzeichen. Bei gleichen Operanden wird dieser gemeinsame Wert zurückgegeben; beide Eingaben bleiben unverändert.
Anwendungsbeispiel
result[1]=kq_min_s16(-7,4);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Der Vergleich von −7 und 4 ergibt -7. Negative Ergebnisse werden mit Minuszeichen angezeigt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Prüft, ob ein Punkt im Rechteck liegt; linke und obere Kante sind eingeschlossen.
Syntax
u8 kq_point_in_rect(s16 x, s16 y, KQRect r);Parameter
xX-Koordinate des Punkts im Koordinatensystem des Rechtecks.
yY-Koordinate des Punkts.
rZu prüfendes Rechteck, als Wert übergeben.
Rückgabewert
Gibt innen 1 und außen 0 zurück.
Bedingungen und Grenzen
Verwenden Sie positive Abmessungen; Koordinate plus Größe muss als s16 darstellbar bleiben. Rechte und untere Kante sind ausgeschlossen. Rechtecke mit Fläche null werden nicht ausdrücklich abgewiesen.
Anwendungsbeispiel
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));
}}Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Jede Koordinateneinheit entspricht einer Kachel. Rechteck A bei (1,1) und B bei (5,4) sind jeweils 8×6 groß. Nur von A belegte Zellen zeigen A, nur von B belegte zeigen B, und die 4×3 große Überlappung zeigt zwölf O-Zellen. Die rechte Kante von A bei x=9 zählt nicht dazu. Auf dem CGB ist A rot, B blau und O grün.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Prüft, ob sich zwei achsenparallele Rechtecke mit positiver Fläche überschneiden.
Syntax
u8 kq_rect_intersect(KQRect a, KQRect b);Parameter
aErstes Rechteck, als Wert übergeben:
x, ygeben die linke obere Ecke an,w, hseine Breite und Höhe.bZweites Rechteck im selben Koordinatensystem wie A.
Rückgabewert
Gibt bei Überschneidung 1 zurück, bei Trennung oder bloßer Kantenberührung 0.
Bedingungen und Grenzen
Verwenden Sie positive Abmessungen; Koordinate plus Größe muss als s16 darstellbar bleiben. Rechte und untere Kante sind ausgeschlossen. Rechtecke mit Fläche null werden nicht ausdrücklich abgewiesen.
Anwendungsbeispiel
result[0]=kq_rect_intersect(a,b);result[2]=kq_rect_intersect(a,touch);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Jede Koordinateneinheit entspricht einer Kachel. Rechteck A bei (1,1) und B bei (5,4) sind jeweils 8×6 groß. Nur von A belegte Zellen zeigen A, nur von B belegte zeigen B, und die 4×3 große Überlappung zeigt zwölf O-Zellen. Die rechte Kante von A bei x=9 zählt nicht dazu. Auf dem CGB ist A rot, B blau und O grün.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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 — Tastenzustand, Drücken, Loslassen und Wiederholung
Verwende input_down für fortlaufende Bewegung, input_pressed für einmalige Aktionen, input_released für Aktionen beim Loslassen und input_repeat für Menüs mit Tastenwiederholung. Einmal initialisieren, einmal pro Eingabetakt aktualisieren, danach beliebig oft abfragen. btn_down, btn_pressed, btn_released und btn_repeat sind Aliase dieser vier Abfragen.
Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.
Die Intervalle zählen Updates, keine Millisekunden. Ein neuer Tastendruck erzeugt sofort einen Impuls. Bei INPUT_REPEAT_DELAY=18 und INPUT_REPEAT_RATE=5 folgt der nächste nach 19 Updates, weitere jeweils nach 6. Jede Taste hat einen eigenen Zähler. Die Makros müssen auch beim Kompilieren von input.c entsprechend gesetzt sein; nur den Header des aufrufenden Codes zu ändern, konfiguriert die Bibliothek nicht um.
btn_down
btn_down ist ein Alias für input_down. Prüft, ob mindestens eine der ausgewählten Tasten gerade gehalten wird.
Prüft, ob eine durch mask gewählte Taste gerade gehalten wird.
Syntax
u8 btn_down(u8 mask);Parameter
maskEine
BTN_*-Maske oder mehrere mit|verknüpfte Masken. Eine einzige passende Taste genügt;BTN_A | BTN_Bverlangt nicht beide zugleich. Maske 0 liefert immer 0. Alle gehaltenen Tasten prüfst du mit(input_current() & mask) == mask.
Rückgabewert
Genau 1, wenn mindestens eine gewählte Taste die abgefragte Bedingung erfüllt, sonst 0. Der Rückgabewert ist keine Tastenmaske.
Bedingungen und Grenzen
Der Header definiert ein objektartiges Makro, das zum Implementierungsnamen expandiert. Argumente, Rückgabewerte und Zustandszugriffe entsprechen dem Ziel; der Alias fügt keinen eigenen Zustand oder Verarbeitungsschritt hinzu. Verwenden Sie wie im vollständigen Beispiel und Buildbefehl input.h/input.c für Eingaben oder system.h/system.c für Framedienste.
Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.
Abfragen lesen den letzten input_update()-Zustand, ohne erneut abzufragen, ein Ereignis zu verbrauchen oder einen Zähler weiterzuführen. Mehrfache Abfragen im selben Takt liefern dasselbe Ergebnis. Bei zweimaligem input_update() mit gehaltener Taste ist das neue Druckereignis im zweiten Aufruf gelöscht.
Anwendungsbeispiel
if (btn_down(BTN_A)!=0) held_ticks++;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieses Programm zeigt den Unterschied zwischen einer gehaltenen Taste, einem neuen Tastendruck, dem Loslassen und der automatischen Wiederholung. Halten Sie A für 40 Aktualisierungen gedrückt und lassen Sie die Taste dann los. FIRST DOWN, FIRST PRESS und FIRST REPEAT sind 1; FIRST CURRENT ist 16. HELD TICKS ist 40, PRESS COUNT ist 1 und REPEAT COUNT ist 5. Beim Loslassen ist RELEASE 1, LAST CURRENT 0 und LAST PREVIOUS 16. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Zähler; das Programm prüft die Wiederholungsabstände anhand der tatsächlich beobachteten Dauer.


Vollständiges Beispielprogramm
Build-Befehl
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-cacheImplementierung und Quelltext
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 ist ein Alias für input_pressed. Prüft, ob bei der letzten Eingabeaktualisierung mindestens eine ausgewählte Taste neu gedrückt wurde.
Prüft, ob eine maskierte Taste bei der letzten Eingabeaktualisierung neu gedrückt wurde.
Syntax
u8 btn_pressed(u8 mask);Parameter
maskEine
BTN_*-Maske oder mehrere mit|verknüpfte Masken. Eine einzige passende Taste genügt;BTN_A | BTN_Bverlangt nicht beide zugleich. Maske 0 liefert immer 0. Alle gehaltenen Tasten prüfst du mit(input_current() & mask) == mask.
Rückgabewert
Genau 1, wenn mindestens eine gewählte Taste die abgefragte Bedingung erfüllt, sonst 0. Der Rückgabewert ist keine Tastenmaske.
Bedingungen und Grenzen
Der Header definiert ein objektartiges Makro, das zum Implementierungsnamen expandiert. Argumente, Rückgabewerte und Zustandszugriffe entsprechen dem Ziel; der Alias fügt keinen eigenen Zustand oder Verarbeitungsschritt hinzu. Verwenden Sie wie im vollständigen Beispiel und Buildbefehl input.h/input.c für Eingaben oder system.h/system.c für Framedienste.
Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.
Abfragen lesen den letzten input_update()-Zustand, ohne erneut abzufragen, ein Ereignis zu verbrauchen oder einen Zähler weiterzuführen. Mehrfache Abfragen im selben Takt liefern dasselbe Ergebnis. Bei zweimaligem input_update() mit gehaltener Taste ist das neue Druckereignis im zweiten Aufruf gelöscht.
Anwendungsbeispiel
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++;
}Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieses Programm zeigt den Unterschied zwischen einer gehaltenen Taste, einem neuen Tastendruck, dem Loslassen und der automatischen Wiederholung. Halten Sie A für 40 Aktualisierungen gedrückt und lassen Sie die Taste dann los. FIRST DOWN, FIRST PRESS und FIRST REPEAT sind 1; FIRST CURRENT ist 16. HELD TICKS ist 40, PRESS COUNT ist 1 und REPEAT COUNT ist 5. Beim Loslassen ist RELEASE 1, LAST CURRENT 0 und LAST PREVIOUS 16. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Zähler; das Programm prüft die Wiederholungsabstände anhand der tatsächlich beobachteten Dauer.


Vollständiges Beispielprogramm
Build-Befehl
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-cacheImplementierung und Quelltext
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 ist ein Alias für input_released. Prüft, ob bei der letzten Eingabeaktualisierung mindestens eine ausgewählte Taste losgelassen wurde.
Prüft, ob eine maskierte Taste bei der letzten Eingabeaktualisierung losgelassen wurde.
Syntax
u8 btn_released(u8 mask);Parameter
maskEine
BTN_*-Maske oder mehrere mit|verknüpfte Masken. Eine einzige passende Taste genügt;BTN_A | BTN_Bverlangt nicht beide zugleich. Maske 0 liefert immer 0. Alle gehaltenen Tasten prüfst du mit(input_current() & mask) == mask.
Rückgabewert
Genau 1, wenn mindestens eine gewählte Taste die abgefragte Bedingung erfüllt, sonst 0. Der Rückgabewert ist keine Tastenmaske.
Bedingungen und Grenzen
Der Header definiert ein objektartiges Makro, das zum Implementierungsnamen expandiert. Argumente, Rückgabewerte und Zustandszugriffe entsprechen dem Ziel; der Alias fügt keinen eigenen Zustand oder Verarbeitungsschritt hinzu. Verwenden Sie wie im vollständigen Beispiel und Buildbefehl input.h/input.c für Eingaben oder system.h/system.c für Framedienste.
Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.
Abfragen lesen den letzten input_update()-Zustand, ohne erneut abzufragen, ein Ereignis zu verbrauchen oder einen Zähler weiterzuführen. Mehrfache Abfragen im selben Takt liefern dasselbe Ergebnis. Bei zweimaligem input_update() mit gehaltener Taste ist das neue Druckereignis im zweiten Aufruf gelöscht.
Anwendungsbeispiel
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;
}Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieses Programm zeigt den Unterschied zwischen einer gehaltenen Taste, einem neuen Tastendruck, dem Loslassen und der automatischen Wiederholung. Halten Sie A für 40 Aktualisierungen gedrückt und lassen Sie die Taste dann los. FIRST DOWN, FIRST PRESS und FIRST REPEAT sind 1; FIRST CURRENT ist 16. HELD TICKS ist 40, PRESS COUNT ist 1 und REPEAT COUNT ist 5. Beim Loslassen ist RELEASE 1, LAST CURRENT 0 und LAST PREVIOUS 16. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Zähler; das Programm prüft die Wiederholungsabstände anhand der tatsächlich beobachteten Dauer.


Vollständiges Beispielprogramm
Build-Befehl
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-cacheImplementierung und Quelltext
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 ist ein Alias für input_repeat. Prüft auf den ersten Tastendruck oder einen vorgesehenen Wiederholungsimpuls bei gehaltener Taste.
Prüft auf erstmaligen Tastendruck oder einen Wiederholungsimpuls einer maskierten Taste.
Syntax
u8 btn_repeat(u8 mask);Parameter
maskEine
BTN_*-Maske oder mehrere mit|verknüpfte Masken. Eine einzige passende Taste genügt;BTN_A | BTN_Bverlangt nicht beide zugleich. Maske 0 liefert immer 0. Alle gehaltenen Tasten prüfst du mit(input_current() & mask) == mask.
Rückgabewert
Genau 1, wenn mindestens eine gewählte Taste die abgefragte Bedingung erfüllt, sonst 0. Der Rückgabewert ist keine Tastenmaske.
Bedingungen und Grenzen
Der Header definiert ein objektartiges Makro, das zum Implementierungsnamen expandiert. Argumente, Rückgabewerte und Zustandszugriffe entsprechen dem Ziel; der Alias fügt keinen eigenen Zustand oder Verarbeitungsschritt hinzu. Verwenden Sie wie im vollständigen Beispiel und Buildbefehl input.h/input.c für Eingaben oder system.h/system.c für Framedienste.
Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.
Abfragen lesen den letzten input_update()-Zustand, ohne erneut abzufragen, ein Ereignis zu verbrauchen oder einen Zähler weiterzuführen. Mehrfache Abfragen im selben Takt liefern dasselbe Ergebnis. Bei zweimaligem input_update() mit gehaltener Taste ist das neue Druckereignis im zweiten Aufruf gelöscht.
Die Intervalle zählen Updates, keine Millisekunden. Ein neuer Tastendruck erzeugt sofort einen Impuls. Bei INPUT_REPEAT_DELAY=18 und INPUT_REPEAT_RATE=5 folgt der nächste nach 19 Updates, weitere jeweils nach 6. Jede Taste hat einen eigenen Zähler. Die Makros müssen auch beim Kompilieren von input.c entsprechend gesetzt sein; nur den Header des aufrufenden Codes zu ändern, konfiguriert die Bibliothek nicht um.
Anwendungsbeispiel
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.
}Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieses Programm zeigt den Unterschied zwischen einer gehaltenen Taste, einem neuen Tastendruck, dem Loslassen und der automatischen Wiederholung. Halten Sie A für 40 Aktualisierungen gedrückt und lassen Sie die Taste dann los. FIRST DOWN, FIRST PRESS und FIRST REPEAT sind 1; FIRST CURRENT ist 16. HELD TICKS ist 40, PRESS COUNT ist 1 und REPEAT COUNT ist 5. Beim Loslassen ist RELEASE 1, LAST CURRENT 0 und LAST PREVIOUS 16. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Zähler; das Programm prüft die Wiederholungsabstände anhand der tatsächlich beobachteten Dauer.


Vollständiges Beispielprogramm
Build-Befehl
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-cacheImplementierung und Quelltext
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
Liefert die vollständige Maske gehaltener Tasten der letzten Aktualisierung.
Syntax
u8 input_current();Rückgabewert
Eine 8-Bit-Maske im gemeinsamen BTN_*-Format. Mehrere Tasten können zugleich gesetzt sein; 0 bedeutet keine.
Bedingungen und Grenzen
Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.
Abfragen lesen den letzten input_update()-Zustand, ohne erneut abzufragen, ein Ereignis zu verbrauchen oder einen Zähler weiterzuführen. Mehrfache Abfragen im selben Takt liefern dasselbe Ergebnis. Bei zweimaligem input_update() mit gehaltener Taste ist das neue Druckereignis im zweiten Aufruf gelöscht.
Anwendungsbeispiel
first_current=input_current(); // Only A held: BTN_A, or decimal 16.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieses Programm zeigt den Unterschied zwischen einer gehaltenen Taste, einem neuen Tastendruck, dem Loslassen und der automatischen Wiederholung. Halten Sie A für 40 Aktualisierungen gedrückt und lassen Sie die Taste dann los. FIRST DOWN, FIRST PRESS und FIRST REPEAT sind 1; FIRST CURRENT ist 16. HELD TICKS ist 40, PRESS COUNT ist 1 und REPEAT COUNT ist 5. Beim Loslassen ist RELEASE 1, LAST CURRENT 0 und LAST PREVIOUS 16. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Zähler; das Programm prüft die Wiederholungsabstände anhand der tatsächlich beobachteten Dauer.


Vollständiges Beispielprogramm
Build-Befehl
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-cacheImplementierung und Quelltext
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
Prüft, ob eine durch mask gewählte Taste gerade gehalten wird.
Syntax
u8 input_down(u8 mask);Parameter
maskEine
BTN_*-Maske oder mehrere mit|verknüpfte Masken. Eine einzige passende Taste genügt;BTN_A | BTN_Bverlangt nicht beide zugleich. Maske 0 liefert immer 0. Alle gehaltenen Tasten prüfst du mit(input_current() & mask) == mask.
Rückgabewert
Genau 1, wenn mindestens eine gewählte Taste die abgefragte Bedingung erfüllt, sonst 0. Der Rückgabewert ist keine Tastenmaske.
Bedingungen und Grenzen
Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.
Abfragen lesen den letzten input_update()-Zustand, ohne erneut abzufragen, ein Ereignis zu verbrauchen oder einen Zähler weiterzuführen. Mehrfache Abfragen im selben Takt liefern dasselbe Ergebnis. Bei zweimaligem input_update() mit gehaltener Taste ist das neue Druckereignis im zweiten Aufruf gelöscht.
Anwendungsbeispiel
if (input_down(BTN_A)!=0) held_ticks++;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieses Programm zeigt den Unterschied zwischen einer gehaltenen Taste, einem neuen Tastendruck, dem Loslassen und der automatischen Wiederholung. Halten Sie A für 40 Aktualisierungen gedrückt und lassen Sie die Taste dann los. FIRST DOWN, FIRST PRESS und FIRST REPEAT sind 1; FIRST CURRENT ist 16. HELD TICKS ist 40, PRESS COUNT ist 1 und REPEAT COUNT ist 5. Beim Loslassen ist RELEASE 1, LAST CURRENT 0 und LAST PREVIOUS 16. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Zähler; das Programm prüft die Wiederholungsabstände anhand der tatsächlich beobachteten Dauer.


Vollständiges Beispielprogramm
Build-Befehl
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-cacheImplementierung und Quelltext
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
Setzt die Masken für aktuellen und vorherigen Zustand, neue Tastendrücke, Loslassen und Wiederholung auf 0 und alle acht Wiederholungszähler auf INPUT_REPEAT_DELAY. Liest den Controller nicht. Eine beim ersten anschließenden Update gehaltene Taste gilt als neu gedrückt.
Syntax
void input_init();Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.
Die Intervalle zählen Updates, keine Millisekunden. Ein neuer Tastendruck erzeugt sofort einen Impuls. Bei INPUT_REPEAT_DELAY=18 und INPUT_REPEAT_RATE=5 folgt der nächste nach 19 Updates, weitere jeweils nach 6. Jede Taste hat einen eigenen Zähler. Die Makros müssen auch beim Kompilieren von input.c entsprechend gesetzt sein; nur den Header des aufrufenden Codes zu ändern, konfiguriert die Bibliothek nicht um.
Anwendungsbeispiel
input_init();
if (input_current()!=0 || input_previous()!=0) failures++;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieses Programm zeigt den Unterschied zwischen einer gehaltenen Taste, einem neuen Tastendruck, dem Loslassen und der automatischen Wiederholung. Halten Sie A für 40 Aktualisierungen gedrückt und lassen Sie die Taste dann los. FIRST DOWN, FIRST PRESS und FIRST REPEAT sind 1; FIRST CURRENT ist 16. HELD TICKS ist 40, PRESS COUNT ist 1 und REPEAT COUNT ist 5. Beim Loslassen ist RELEASE 1, LAST CURRENT 0 und LAST PREVIOUS 16. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Zähler; das Programm prüft die Wiederholungsabstände anhand der tatsächlich beobachteten Dauer.


Vollständiges Beispielprogramm
Build-Befehl
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-cacheImplementierung und Quelltext
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
Prüft, ob eine maskierte Taste bei der letzten Eingabeaktualisierung neu gedrückt wurde.
Syntax
u8 input_pressed(u8 mask);Parameter
maskEine
BTN_*-Maske oder mehrere mit|verknüpfte Masken. Eine einzige passende Taste genügt;BTN_A | BTN_Bverlangt nicht beide zugleich. Maske 0 liefert immer 0. Alle gehaltenen Tasten prüfst du mit(input_current() & mask) == mask.
Rückgabewert
Genau 1, wenn mindestens eine gewählte Taste die abgefragte Bedingung erfüllt, sonst 0. Der Rückgabewert ist keine Tastenmaske.
Bedingungen und Grenzen
Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.
Abfragen lesen den letzten input_update()-Zustand, ohne erneut abzufragen, ein Ereignis zu verbrauchen oder einen Zähler weiterzuführen. Mehrfache Abfragen im selben Takt liefern dasselbe Ergebnis. Bei zweimaligem input_update() mit gehaltener Taste ist das neue Druckereignis im zweiten Aufruf gelöscht.
Anwendungsbeispiel
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++;
}Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieses Programm zeigt den Unterschied zwischen einer gehaltenen Taste, einem neuen Tastendruck, dem Loslassen und der automatischen Wiederholung. Halten Sie A für 40 Aktualisierungen gedrückt und lassen Sie die Taste dann los. FIRST DOWN, FIRST PRESS und FIRST REPEAT sind 1; FIRST CURRENT ist 16. HELD TICKS ist 40, PRESS COUNT ist 1 und REPEAT COUNT ist 5. Beim Loslassen ist RELEASE 1, LAST CURRENT 0 und LAST PREVIOUS 16. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Zähler; das Programm prüft die Wiederholungsabstände anhand der tatsächlich beobachteten Dauer.


Vollständiges Beispielprogramm
Build-Befehl
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-cacheImplementierung und Quelltext
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
Liefert die gespeicherte Tastenmaske vor der letzten Eingabeaktualisierung.
Syntax
u8 input_previous();Rückgabewert
Eine 8-Bit-Maske im gemeinsamen BTN_*-Format. Mehrere Tasten können zugleich gesetzt sein; 0 bedeutet keine.
Bedingungen und Grenzen
Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.
Abfragen lesen den letzten input_update()-Zustand, ohne erneut abzufragen, ein Ereignis zu verbrauchen oder einen Zähler weiterzuführen. Mehrfache Abfragen im selben Takt liefern dasselbe Ergebnis. Bei zweimaligem input_update() mit gehaltener Taste ist das neue Druckereignis im zweiten Aufruf gelöscht.
Anwendungsbeispiel
first_previous=input_previous(); // No buttons in the preceding sample: 0.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieses Programm zeigt den Unterschied zwischen einer gehaltenen Taste, einem neuen Tastendruck, dem Loslassen und der automatischen Wiederholung. Halten Sie A für 40 Aktualisierungen gedrückt und lassen Sie die Taste dann los. FIRST DOWN, FIRST PRESS und FIRST REPEAT sind 1; FIRST CURRENT ist 16. HELD TICKS ist 40, PRESS COUNT ist 1 und REPEAT COUNT ist 5. Beim Loslassen ist RELEASE 1, LAST CURRENT 0 und LAST PREVIOUS 16. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Zähler; das Programm prüft die Wiederholungsabstände anhand der tatsächlich beobachteten Dauer.


Vollständiges Beispielprogramm
Build-Befehl
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-cacheImplementierung und Quelltext
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
Prüft, ob eine maskierte Taste bei der letzten Eingabeaktualisierung losgelassen wurde.
Syntax
u8 input_released(u8 mask);Parameter
maskEine
BTN_*-Maske oder mehrere mit|verknüpfte Masken. Eine einzige passende Taste genügt;BTN_A | BTN_Bverlangt nicht beide zugleich. Maske 0 liefert immer 0. Alle gehaltenen Tasten prüfst du mit(input_current() & mask) == mask.
Rückgabewert
Genau 1, wenn mindestens eine gewählte Taste die abgefragte Bedingung erfüllt, sonst 0. Der Rückgabewert ist keine Tastenmaske.
Bedingungen und Grenzen
Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.
Abfragen lesen den letzten input_update()-Zustand, ohne erneut abzufragen, ein Ereignis zu verbrauchen oder einen Zähler weiterzuführen. Mehrfache Abfragen im selben Takt liefern dasselbe Ergebnis. Bei zweimaligem input_update() mit gehaltener Taste ist das neue Druckereignis im zweiten Aufruf gelöscht.
Anwendungsbeispiel
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;
}Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieses Programm zeigt den Unterschied zwischen einer gehaltenen Taste, einem neuen Tastendruck, dem Loslassen und der automatischen Wiederholung. Halten Sie A für 40 Aktualisierungen gedrückt und lassen Sie die Taste dann los. FIRST DOWN, FIRST PRESS und FIRST REPEAT sind 1; FIRST CURRENT ist 16. HELD TICKS ist 40, PRESS COUNT ist 1 und REPEAT COUNT ist 5. Beim Loslassen ist RELEASE 1, LAST CURRENT 0 und LAST PREVIOUS 16. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Zähler; das Programm prüft die Wiederholungsabstände anhand der tatsächlich beobachteten Dauer.


Vollständiges Beispielprogramm
Build-Befehl
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-cacheImplementierung und Quelltext
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
Prüft auf erstmaligen Tastendruck oder einen Wiederholungsimpuls einer maskierten Taste.
Syntax
u8 input_repeat(u8 mask);Parameter
maskEine
BTN_*-Maske oder mehrere mit|verknüpfte Masken. Eine einzige passende Taste genügt;BTN_A | BTN_Bverlangt nicht beide zugleich. Maske 0 liefert immer 0. Alle gehaltenen Tasten prüfst du mit(input_current() & mask) == mask.
Rückgabewert
Genau 1, wenn mindestens eine gewählte Taste die abgefragte Bedingung erfüllt, sonst 0. Der Rückgabewert ist keine Tastenmaske.
Bedingungen und Grenzen
Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.
Abfragen lesen den letzten input_update()-Zustand, ohne erneut abzufragen, ein Ereignis zu verbrauchen oder einen Zähler weiterzuführen. Mehrfache Abfragen im selben Takt liefern dasselbe Ergebnis. Bei zweimaligem input_update() mit gehaltener Taste ist das neue Druckereignis im zweiten Aufruf gelöscht.
Die Intervalle zählen Updates, keine Millisekunden. Ein neuer Tastendruck erzeugt sofort einen Impuls. Bei INPUT_REPEAT_DELAY=18 und INPUT_REPEAT_RATE=5 folgt der nächste nach 19 Updates, weitere jeweils nach 6. Jede Taste hat einen eigenen Zähler. Die Makros müssen auch beim Kompilieren von input.c entsprechend gesetzt sein; nur den Header des aufrufenden Codes zu ändern, konfiguriert die Bibliothek nicht um.
Anwendungsbeispiel
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.
}Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieses Programm zeigt den Unterschied zwischen einer gehaltenen Taste, einem neuen Tastendruck, dem Loslassen und der automatischen Wiederholung. Halten Sie A für 40 Aktualisierungen gedrückt und lassen Sie die Taste dann los. FIRST DOWN, FIRST PRESS und FIRST REPEAT sind 1; FIRST CURRENT ist 16. HELD TICKS ist 40, PRESS COUNT ist 1 und REPEAT COUNT ist 5. Beim Loslassen ist RELEASE 1, LAST CURRENT 0 und LAST PREVIOUS 16. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Zähler; das Programm prüft die Wiederholungsabstände anhand der tatsächlich beobachteten Dauer.


Vollständiges Beispielprogramm
Build-Befehl
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-cacheImplementierung und Quelltext
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
Speichert die aktuelle Maske als vorherigen Zustand, liest die Game-Boy-Tasten mit __readpadex, ermittelt losgelassene Tasten und führt jeden unabhängigen Wiederholungszähler um einen Schritt weiter. Einmal pro Eingabetakt aufrufen, danach den gespeicherten Zustand abfragen.
Syntax
void input_update();Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.
Die Intervalle zählen Updates, keine Millisekunden. Ein neuer Tastendruck erzeugt sofort einen Impuls. Bei INPUT_REPEAT_DELAY=18 und INPUT_REPEAT_RATE=5 folgt der nächste nach 19 Updates, weitere jeweils nach 6. Jede Taste hat einen eigenen Zähler. Die Makros müssen auch beim Kompilieren von input.c entsprechend gesetzt sein; nur den Header des aufrufenden Codes zu ändern, konfiguriert die Bibliothek nicht um.
Anwendungsbeispiel
input_update(); // One update per input tick, followed by any number of queries.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieses Programm zeigt den Unterschied zwischen einer gehaltenen Taste, einem neuen Tastendruck, dem Loslassen und der automatischen Wiederholung. Halten Sie A für 40 Aktualisierungen gedrückt und lassen Sie die Taste dann los. FIRST DOWN, FIRST PRESS und FIRST REPEAT sind 1; FIRST CURRENT ist 16. HELD TICKS ist 40, PRESS COUNT ist 1 und REPEAT COUNT ist 5. Beim Loslassen ist RELEASE 1, LAST CURRENT 0 und LAST PREVIOUS 16. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Zähler; das Programm prüft die Wiederholungsabstände anhand der tatsächlich beobachteten Dauer.


Vollständiges Beispielprogramm
Build-Befehl
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-cacheImplementierung und Quelltext
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 — Serielle Kommunikation und logische Pakete
Die Bibliothek bietet drei Ebenen: Byteaustausch, Pakete mit bis zu 24 Bytes und Warteschlangen pro Gegenstelle. Beginnen Sie mit BYTE MASTER/SLAVE, danach PACKET und LINK4, um Taktzuständigkeit und Empfangsbereitschaft kennenzulernen. Binden Sie die Hardwareregister-Einheit, link.c und link_packet.c je genau einmal in ein Programm ein. gb_link_example.h stellt diese Reihenfolge bereit.
Link4 verwaltet den logischen Hostplatz 0 und Gegenstellenplätze 1 bis 3. SelectPeer sendet keinen Befehl zum Umschalten physischer Leitungen. KOKURAs link4-Topologie folgt der ausgewählten Gegenstelle anhand der Compilermetadaten. Verwenden Sie LinkDmg07 für das Protokoll des echten DMG-07-Adapters.
Fragen Sie beide Endpunkte fortlaufend ab. Ein Timeout zählt 90 Aufrufe ohne Fortschritt, keine Hardwareframes. Das Senden von 0xFF allein zur Taktversorgung eines ACK verlängert die Frist nicht; höchstens drei Sendeversuche sind erlaubt. Wiederholungen können Duplikate liefern. Ergänzen Sie Kennungen auf Anwendungsebene, wenn ein Befehl genau einmal ausgeführt werden muss.
Link4_BeginTransferTo
Wählt ein Ziel und startet anschließend einen Byteaustausch.
Syntax
u8 __stackcall Link4_BeginTransferTo(u8 peer_slot, u8 out);Parameter
peer_slotKonfigurierter entfernter Platz: vom Host aus 1 bis slot_count−1, von einer Gegenstelle aus 0.
outAusgehender Acht-Bit-Wert.
Rückgabewert
Gibt den ersten Auswahl- oder Startfehler zurück, bei Erfolg 0.
Bedingungen und Grenzen
Link4 verwaltet den logischen Hostplatz 0 und Gegenstellenplätze 1 bis 3. SelectPeer sendet keinen Befehl zum Umschalten physischer Leitungen. KOKURAs link4-Topologie folgt der ausgewählten Gegenstelle anhand der Compilermetadaten. Verwenden Sie LinkDmg07 für das Protokoll des echten DMG-07-Adapters.
Fehlercodes: 0=kein Fehler, 1=belegt, 2=Timeout, 3=Empfangsüberlauf, 4=ungültige Konfiguration/Protokoll, 5=ACK-Timeout mit einer Antwort wie bei einer getrennten Verbindung. Start- und Konfigurationsaufrufe melden Erfolg mit 0, Empfangs- und Entnahmeaufrufe mit 1. Erfolgreiche Aufrufe löschen keinen gespeicherten Fehler.
Link4 kopiert jedes empfangene Byte sowohl in den allgemeinen Ring als auch in einen Ring pro Gegenstelle. Das Lesen eines Rings leert den anderen nicht. Die Paketabfrage verbraucht den allgemeinen Ring. Verwerfen Sie auch regelmäßig ungenutzte Rohbytes in den Gegenstellenringen, um Überläufe zu vermeiden.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[6+slot]=Link4_BeginTransferTo(slot,16+slot);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Verbinden Sie alle vier ROMs über KOKURAs link4-Topologie. Der Host empfängt 161/162/163 von Gegenstellen 1/2/3 und zeigt LAST PEER=3. Danach sendet er die Befehle 65/66/67 mit Nutzdaten 7/42/255. Prüfen Sie diese Werte auch auf jedem Gegenstellenbildschirm.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Liest die dem letzten abgeschlossenen Byte zugeordnete Gegenstelle.
Syntax
u8 Link4_GetLastRxPeer();Rückgabewert
Der Host liefert die ausgewählte Gegenstelle, eine Gegenstelle 0; vor dem ersten Empfang wird 255 geliefert.
Bedingungen und Grenzen
Link4 verwaltet den logischen Hostplatz 0 und Gegenstellenplätze 1 bis 3. SelectPeer sendet keinen Befehl zum Umschalten physischer Leitungen. KOKURAs link4-Topologie folgt der ausgewählten Gegenstelle anhand der Compilermetadaten. Verwenden Sie LinkDmg07 für das Protokoll des echten DMG-07-Adapters.
Diese Funktionen lesen Konfiguration und Verlauf. Sie erkennen keine physischen Verbindungen, fragen nicht alle Gegenstellen ab und warten nicht auf Transferabschluss.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[19]=Link4_GetLastRxPeer();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Verbinden Sie alle vier ROMs über KOKURAs link4-Topologie. Der Host empfängt 161/162/163 von Gegenstellen 1/2/3 und zeigt LAST PEER=3. Danach sendet er die Befehle 65/66/67 mit Nutzdaten 7/42/255. Prüfen Sie diese Werte auch auf jedem Gegenstellenbildschirm.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Liest das beim Start des letzten Bytetransfers gespeicherte Ziel.
Syntax
u8 Link4_GetLastTxPeer();Rückgabewert
Gibt das gespeicherte Ziel zurück, vor dem ersten Start 255.
Bedingungen und Grenzen
Link4 verwaltet den logischen Hostplatz 0 und Gegenstellenplätze 1 bis 3. SelectPeer sendet keinen Befehl zum Umschalten physischer Leitungen. KOKURAs link4-Topologie folgt der ausgewählten Gegenstelle anhand der Compilermetadaten. Verwenden Sie LinkDmg07 für das Protokoll des echten DMG-07-Adapters.
Diese Funktionen lesen Konfiguration und Verlauf. Sie erkennen keine physischen Verbindungen, fragen nicht alle Gegenstellen ab und warten nicht auf Transferabschluss.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[20]=Link4_GetLastTxPeer();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Verbinden Sie alle vier ROMs über KOKURAs link4-Topologie. Der Host empfängt 161/162/163 von Gegenstellen 1/2/3 und zeigt LAST PEER=3. Danach sendet er die Befehle 65/66/67 mit Nutzdaten 7/42/255. Prüfen Sie diese Werte auch auf jedem Gegenstellenbildschirm.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Liest den für dieses Gerät konfigurierten Platz.
Syntax
u8 Link4_GetLocalSlot();Rückgabewert
Host ist 0, Gegenstellen sind 1 bis 3. Nicht konfiguriert ergibt ebenfalls 0.
Bedingungen und Grenzen
Link4 verwaltet den logischen Hostplatz 0 und Gegenstellenplätze 1 bis 3. SelectPeer sendet keinen Befehl zum Umschalten physischer Leitungen. KOKURAs link4-Topologie folgt der ausgewählten Gegenstelle anhand der Compilermetadaten. Verwenden Sie LinkDmg07 für das Protokoll des echten DMG-07-Adapters.
Diese Funktionen lesen Konfiguration und Verlauf. Sie erkennen keine physischen Verbindungen, fragen nicht alle Gegenstellen ab und warten nicht auf Transferabschluss.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[2]=Link4_GetLocalSlot();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Verbinden Sie alle vier ROMs über KOKURAs link4-Topologie. Der Host empfängt 161/162/163 von Gegenstellen 1/2/3 und zeigt LAST PEER=3. Danach sendet er die Befehle 65/66/67 mit Nutzdaten 7/42/255. Prüfen Sie diese Werte auch auf jedem Gegenstellenbildschirm.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Liest die konfigurierte logische Rolle.
Syntax
u8 Link4_GetMode();Rückgabewert
0=nicht konfiguriert, 1=Host, 2=Gegenstelle.
Bedingungen und Grenzen
Link4 verwaltet den logischen Hostplatz 0 und Gegenstellenplätze 1 bis 3. SelectPeer sendet keinen Befehl zum Umschalten physischer Leitungen. KOKURAs link4-Topologie folgt der ausgewählten Gegenstelle anhand der Compilermetadaten. Verwenden Sie LinkDmg07 für das Protokoll des echten DMG-07-Adapters.
Diese Funktionen lesen Konfiguration und Verlauf. Sie erkennen keine physischen Verbindungen, fragen nicht alle Gegenstellen ab und warten nicht auf Transferabschluss.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[1]=Link4_GetMode();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Verbinden Sie alle vier ROMs über KOKURAs link4-Topologie. Der Host empfängt 161/162/163 von Gegenstellen 1/2/3 und zeigt LAST PEER=3. Danach sendet er die Befehle 65/66/67 mit Nutzdaten 7/42/255. Prüfen Sie diese Werte auch auf jedem Gegenstellenbildschirm.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Liest das aktuell ausgewählte logische Ziel.
Syntax
u8 Link4_GetSelectedPeer();Rückgabewert
Der Host liefert seine ausgewählte Gegenstelle, eine Gegenstelle 0 und der unkonfigurierte Zustand 255.
Bedingungen und Grenzen
Link4 verwaltet den logischen Hostplatz 0 und Gegenstellenplätze 1 bis 3. SelectPeer sendet keinen Befehl zum Umschalten physischer Leitungen. KOKURAs link4-Topologie folgt der ausgewählten Gegenstelle anhand der Compilermetadaten. Verwenden Sie LinkDmg07 für das Protokoll des echten DMG-07-Adapters.
Diese Funktionen lesen Konfiguration und Verlauf. Sie erkennen keine physischen Verbindungen, fragen nicht alle Gegenstellen ab und warten nicht auf Transferabschluss.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[4]=Link4_GetSelectedPeer();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Verbinden Sie alle vier ROMs über KOKURAs link4-Topologie. Der Host empfängt 161/162/163 von Gegenstellen 1/2/3 und zeigt LAST PEER=3. Danach sendet er die Befehle 65/66/67 mit Nutzdaten 7/42/255. Prüfen Sie diese Werte auch auf jedem Gegenstellenbildschirm.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Liest die konfigurierte Gesamtzahl der Plätze.
Syntax
u8 Link4_GetSlotCount();Rückgabewert
Gültige Konfigurationen liefern 2 bis 4, nicht konfiguriert liefert 0.
Bedingungen und Grenzen
Link4 verwaltet den logischen Hostplatz 0 und Gegenstellenplätze 1 bis 3. SelectPeer sendet keinen Befehl zum Umschalten physischer Leitungen. KOKURAs link4-Topologie folgt der ausgewählten Gegenstelle anhand der Compilermetadaten. Verwenden Sie LinkDmg07 für das Protokoll des echten DMG-07-Adapters.
Diese Funktionen lesen Konfiguration und Verlauf. Sie erkennen keine physischen Verbindungen, fragen nicht alle Gegenstellen ab und warten nicht auf Transferabschluss.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[3]=Link4_GetSlotCount();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Verbinden Sie alle vier ROMs über KOKURAs link4-Topologie. Der Host empfängt 161/162/163 von Gegenstellen 1/2/3 und zeigt LAST PEER=3. Danach sendet er die Befehle 65/66/67 mit Nutzdaten 7/42/255. Prüfen Sie diese Werte auch auf jedem Gegenstellenbildschirm.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Prüft ungelesene Daten im Empfangsring einer Gegenstelle.
Syntax
u8 __stackcall Link4_HasByteFrom(u8 peer_slot);Parameter
peer_slotKonfigurierter entfernter Platz: vom Host aus 1 bis slot_count−1, von einer Gegenstelle aus 0.
Rückgabewert
Gibt bei wartenden Daten 1 zurück, bei leerem Ring oder ungültiger Gegenstelle 0.
Bedingungen und Grenzen
Der Empfangsring mit acht Einträgen fasst sieben Bytes. Ein voller Ring verwirft das neue Byte und speichert Fehler 3. Ein empfangenes Nullbyte ist gültige Nutzlast.
Link4 kopiert jedes empfangene Byte sowohl in den allgemeinen Ring als auch in einen Ring pro Gegenstelle. Das Lesen eines Rings leert den anderen nicht. Die Paketabfrage verbraucht den allgemeinen Ring. Verwerfen Sie auch regelmäßig ungenutzte Rohbytes in den Gegenstellenringen, um Überläufe zu vermeiden.
Diese Abfrage liest die Hardware nicht aus; eine ungültige Gegenstelle ändert den gespeicherten Fehler nicht.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[9+slot]=Link4_HasByteFrom(slot);value=0;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Verbinden Sie alle vier ROMs über KOKURAs link4-Topologie. Der Host empfängt 161/162/163 von Gegenstellen 1/2/3 und zeigt LAST PEER=3. Danach sendet er die Befehle 65/66/67 mit Nutzdaten 7/42/255. Prüfen Sie diese Werte auch auf jedem Gegenstellenbildschirm.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Prüft den Briefkasten vollständiger Pakete eines entfernten Platzes.
Syntax
u8 __stackcall Link4_HasPacketFrom(u8 peer_slot);Parameter
peer_slotKonfigurierter entfernter Platz: vom Host aus 1 bis slot_count−1, von einer Gegenstelle aus 0.
Rückgabewert
Gibt bei einem ungelesenen Paket 1 zurück, bei leerem Briefkasten oder ungültiger Gegenstelle 0.
Bedingungen und Grenzen
Link4 verwaltet den logischen Hostplatz 0 und Gegenstellenplätze 1 bis 3. SelectPeer sendet keinen Befehl zum Umschalten physischer Leitungen. KOKURAs link4-Topologie folgt der ausgewählten Gegenstelle anhand der Compilermetadaten. Verwenden Sie LinkDmg07 für das Protokoll des echten DMG-07-Adapters.
Ein Paket enthält 0xA5, Befehl, Länge, 0 bis 24 Nutzdatenbytes und eine XOR-Prüfsumme. Die Antwort ist 0x79 (ACK, angenommen) oder 0x1F (NAK, abgewiesen). Die Prüfsumme verknüpft Befehl, Länge und Nutzdaten per XOR. Jedes Gerät hat einen gemeinsamen Paketbriefkasten; Link4 besitzt zusätzlich einen pro Gegenstelle.
Diese Abfrage liest die Hardware nicht aus; eine ungültige Gegenstelle ändert den gespeicherten Fehler nicht.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[9]=Link4_HasPacketFrom(0);result[10]=Link4_ReadPacketFrom(0,&cmd,&len,data);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Als Gegenstelle 1 von vier Plätzen sind HOST BYTE=17, COMMAND=65, LENGTH=3 und PAYLOAD 2=42 zu erwarten. CONSUMED=0 ist das Hostbriefkasten-Flag nach der Entnahme.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Initialisiert einen logischen Host mit zwei bis vier Plätzen und wählt Gegenstelle 1.
Syntax
u8 __stackcall Link4_InitHost(u8 slot_count);Parameter
slot_countAnzahl der Plätze einschließlich Host, 2 bis 4.
Rückgabewert
Gibt bei gültiger Konfiguration 0 zurück, bei ungültiger Platzanzahl 4.
Bedingungen und Grenzen
Die Initialisierung verwirft Bytewarteschlangen, Pakete, Gegenstellenauswahl und Fehler und deaktiviert Übertragung sowie serielle IRQ-Quelle. Ein laufender Austausch bleibt nicht erhalten.
Link4 verwaltet den logischen Hostplatz 0 und Gegenstellenplätze 1 bis 3. SelectPeer sendet keinen Befehl zum Umschalten physischer Leitungen. KOKURAs link4-Topologie folgt der ausgewählten Gegenstelle anhand der Compilermetadaten. Verwenden Sie LinkDmg07 für das Protokoll des echten DMG-07-Adapters.
Interne kritische Abschnitte verfolgen ihre Software-Verschachtelungstiefe. Beim Verlassen des äußersten Abschnitts werden CPU-Interrupts aktiviert. Gehen Sie daher nicht davon aus, dass ein zuvor deaktivierter IME-Zustand erhalten bleibt.
Die Initialisierung erfolgt vor der Prüfung. Auch ein fehlgeschlagener Aufruf verwirft die bisherige Topologie und ungelesene Daten.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[0]=Link4_InitHost(4);result[1]=Link4_GetMode();result[2]=Link4_GetLocalSlot();result[3]=Link4_GetSlotCount();result[4]=Link4_GetSelectedPeer();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Verbinden Sie alle vier ROMs über KOKURAs link4-Topologie. Der Host empfängt 161/162/163 von Gegenstellen 1/2/3 und zeigt LAST PEER=3. Danach sendet er die Befehle 65/66/67 mit Nutzdaten 7/42/255. Prüfen Sie diese Werte auch auf jedem Gegenstellenbildschirm.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Initialisiert eine Gegenstelle mit externem Takt und wählt Hostplatz 0.
Syntax
u8 __stackcall Link4_InitPeer(u8 local_slot, u8 slot_count);Parameter
local_slotLokaler Platz, 1 bis slot_count−1.
slot_countGesamtzahl der Plätze einschließlich Host, 2 bis 4.
Rückgabewert
Gibt bei gültiger Konfiguration 0 zurück, bei ungültiger Platzanzahl oder ungültigem lokalen Platz 4.
Bedingungen und Grenzen
Die Initialisierung verwirft Bytewarteschlangen, Pakete, Gegenstellenauswahl und Fehler und deaktiviert Übertragung sowie serielle IRQ-Quelle. Ein laufender Austausch bleibt nicht erhalten.
Link4 verwaltet den logischen Hostplatz 0 und Gegenstellenplätze 1 bis 3. SelectPeer sendet keinen Befehl zum Umschalten physischer Leitungen. KOKURAs link4-Topologie folgt der ausgewählten Gegenstelle anhand der Compilermetadaten. Verwenden Sie LinkDmg07 für das Protokoll des echten DMG-07-Adapters.
Interne kritische Abschnitte verfolgen ihre Software-Verschachtelungstiefe. Beim Verlassen des äußersten Abschnitts werden CPU-Interrupts aktiviert. Gehen Sie daher nicht davon aus, dass ein zuvor deaktivierter IME-Zustand erhalten bleibt.
Die Initialisierung erfolgt vor der Prüfung. Auch ein fehlgeschlagener Aufruf verwirft die bisherige Topologie und ungelesene Daten.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[0]=Link4_InitPeer(1,4);result[1]=Link4_GetMode();result[2]=Link4_GetLocalSlot();result[3]=Link4_GetSlotCount();result[4]=Link4_GetSelectedPeer();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Als Gegenstelle 1 von vier Plätzen sind HOST BYTE=17, COMMAND=65, LENGTH=3 und PAYLOAD 2=42 zu erwarten. CONSUMED=0 ist das Hostbriefkasten-Flag nach der Entnahme.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Führt die gemeinsame Paketverarbeitung für die aktuell gewählte Gegenstelle einmal weiter.
Syntax
void Link4_PollPacket();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Link4 verwaltet den logischen Hostplatz 0 und Gegenstellenplätze 1 bis 3. SelectPeer sendet keinen Befehl zum Umschalten physischer Leitungen. KOKURAs link4-Topologie folgt der ausgewählten Gegenstelle anhand der Compilermetadaten. Verwenden Sie LinkDmg07 für das Protokoll des echten DMG-07-Adapters.
Ein Paket enthält 0xA5, Befehl, Länge, 0 bis 24 Nutzdatenbytes und eine XOR-Prüfsumme. Die Antwort ist 0x79 (ACK, angenommen) oder 0x1F (NAK, abgewiesen). Die Prüfsumme verknüpft Befehl, Länge und Nutzdaten per XOR. Jedes Gerät hat einen gemeinsamen Paketbriefkasten; Link4 besitzt zusätzlich einen pro Gegenstelle.
Fragen Sie beide Endpunkte fortlaufend ab. Ein Timeout zählt 90 Aufrufe ohne Fortschritt, keine Hardwareframes. Das Senden von 0xFF allein zur Taktversorgung eines ACK verlängert die Frist nicht; höchstens drei Sendeversuche sind erlaubt. Wiederholungen können Duplikate liefern. Ergänzen Sie Kennungen auf Anwendungsebene, wenn ein Befehl genau einmal ausgeführt werden muss.
Link4 kopiert jedes empfangene Byte sowohl in den allgemeinen Ring als auch in einen Ring pro Gegenstelle. Das Lesen eines Rings leert den anderen nicht. Die Paketabfrage verbraucht den allgemeinen Ring. Verwerfen Sie auch regelmäßig ungenutzte Rohbytes in den Gegenstellenringen, um Überläufe zu vermeiden.
Wechselt nicht zyklisch durch alle Plätze. Ändern Sie die Gegenstelle erst nach Abschluss des Austauschs, wenn eine Auswahl erlaubt ist.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
for(i=0;i<50;i++){Link4_PollPacket();while(Link4_TryReadByteFrom(slot,0)){}m_wait();}Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Verbinden Sie alle vier ROMs über KOKURAs link4-Topologie. Der Host empfängt 161/162/163 von Gegenstellen 1/2/3 und zeigt LAST PEER=3. Danach sendet er die Befehle 65/66/67 mit Nutzdaten 7/42/255. Prüfen Sie diese Werte auch auf jedem Gegenstellenbildschirm.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Kopiert ein Paket einer bestimmten Gegenstelle und entnimmt es aus deren Briefkasten.
Syntax
u8 __stackcall Link4_ReadPacketFrom(u8 peer_slot, u8 *cmd, u8 *len, u8 *dst);Parameter
peer_slotKonfigurierter entfernter Platz: vom Host aus 1 bis slot_count−1, von einer Gegenstelle aus 0.
cmdBeschreibbares Befehlsbyte; null lässt diese Ausgabe aus.
lenBeschreibbares Längenbyte von 0 bis 24; null lässt diese Ausgabe aus.
dstBeschreibbarer Nutzdatenpuffer mit Platz für 24 Bytes; null verwirft die Nutzdaten.
Rückgabewert
Gibt bei Entnahme 1 zurück, bei leerem Briefkasten oder ungültiger Gegenstelle 0.
Bedingungen und Grenzen
Es gibt keinen Parameter für die Zielkapazität. Stellen Sie bei Verwendung von dst 24 beschreibbare Bytes bereit. cmd, len und dst dürfen unabhängig voneinander null sein. Koordinieren Sie Prüfung und Entnahme des Briefkasteninhalts so, dass anderer Code oder Interrupts nicht gleichzeitig darauf zugreifen.
Leert den gemeinsamen Briefkasten nur, wenn er auf das Paket derselben Gegenstelle verweist. Ungelesene Pakete anderer Gegenstellen bleiben verfügbar.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[9]=Link4_HasPacketFrom(0);result[10]=Link4_ReadPacketFrom(0,&cmd,&len,data);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Als Gegenstelle 1 von vier Plätzen sind HOST BYTE=17, COMMAND=65, LENGTH=3 und PAYLOAD 2=42 zu erwarten. CONSUMED=0 ist das Hostbriefkasten-Flag nach der Entnahme.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Prüft auf Abschluss und ändert das logische Ziel nur im Ruhezustand.
Syntax
u8 __stackcall Link4_SelectPeer(u8 peer_slot);Parameter
peer_slotKonfigurierter entfernter Platz: vom Host aus 1 bis slot_count−1, von einer Gegenstelle aus 0.
Rückgabewert
Gibt bei Auswahl 0 zurück, bei belegtem Byte-, Paket- oder ACK-Zustand 1 und bei fehlender Konfiguration oder ungültiger Gegenstelle 4.
Bedingungen und Grenzen
Link4 verwaltet den logischen Hostplatz 0 und Gegenstellenplätze 1 bis 3. SelectPeer sendet keinen Befehl zum Umschalten physischer Leitungen. KOKURAs link4-Topologie folgt der ausgewählten Gegenstelle anhand der Compilermetadaten. Verwenden Sie LinkDmg07 für das Protokoll des echten DMG-07-Adapters.
Fehlercodes: 0=kein Fehler, 1=belegt, 2=Timeout, 3=Empfangsüberlauf, 4=ungültige Konfiguration/Protokoll, 5=ACK-Timeout mit einer Antwort wie bei einer getrennten Verbindung. Start- und Konfigurationsaufrufe melden Erfolg mit 0, Empfangs- und Entnahmeaufrufe mit 1. Erfolgreiche Aufrufe löschen keinen gespeicherten Fehler.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[25]=Link4_SelectPeer(1);result[26]=Link_LastError();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Verbinden Sie alle vier ROMs über KOKURAs link4-Topologie. Der Host empfängt 161/162/163 von Gegenstellen 1/2/3 und zeigt LAST PEER=3. Danach sendet er die Befehle 65/66/67 mit Nutzdaten 7/42/255. Prüfen Sie diese Werte auch auf jedem Gegenstellenbildschirm.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Wählt eine logische Gegenstelle, kopiert das Paket und plant dessen Versand ein.
Syntax
u8 __stackcall Link4_SendPacketTo(u8 peer_slot, const u8 *data, u8 len, u8 cmd);Parameter
peer_slotKonfigurierter entfernter Platz: vom Host aus 1 bis slot_count−1, von einer Gegenstelle aus 0.
dataÜber len Bytes lesbare Quelle; nur bei len gleich null darf sie null sein.
lenNutzdatenlänge in Bytes von 0 bis 24.
cmdVon der Anwendung definierter Acht-Bit-Befehl.
Rückgabewert
Gibt den ersten Auswahl- oder Einreihungsfehler zurück. 0 bedeutet angenommen.
Bedingungen und Grenzen
Link4 verwaltet den logischen Hostplatz 0 und Gegenstellenplätze 1 bis 3. SelectPeer sendet keinen Befehl zum Umschalten physischer Leitungen. KOKURAs link4-Topologie folgt der ausgewählten Gegenstelle anhand der Compilermetadaten. Verwenden Sie LinkDmg07 für das Protokoll des echten DMG-07-Adapters.
Fehlercodes: 0=kein Fehler, 1=belegt, 2=Timeout, 3=Empfangsüberlauf, 4=ungültige Konfiguration/Protokoll, 5=ACK-Timeout mit einer Antwort wie bei einer getrennten Verbindung. Start- und Konfigurationsaufrufe melden Erfolg mit 0, Empfangs- und Entnahmeaufrufe mit 1. Erfolgreiche Aufrufe löschen keinen gespeicherten Fehler.
Ein Paket enthält 0xA5, Befehl, Länge, 0 bis 24 Nutzdatenbytes und eine XOR-Prüfsumme. Die Antwort ist 0x79 (ACK, angenommen) oder 0x1F (NAK, abgewiesen). Die Prüfsumme verknüpft Befehl, Länge und Nutzdaten per XOR. Jedes Gerät hat einen gemeinsamen Paketbriefkasten; Link4 besitzt zusätzlich einen pro Gegenstelle.
Fragen Sie beide Endpunkte fortlaufend ab. Ein Timeout zählt 90 Aufrufe ohne Fortschritt, keine Hardwareframes. Das Senden von 0xFF allein zur Taktversorgung eines ACK verlängert die Frist nicht; höchstens drei Sendeversuche sind erlaubt. Wiederholungen können Duplikate liefern. Ergänzen Sie Kennungen auf Anwendungsebene, wenn ein Befehl genau einmal ausgeführt werden muss.
Link4 kopiert jedes empfangene Byte sowohl in den allgemeinen Ring als auch in einen Ring pro Gegenstelle. Das Lesen eines Rings leert den anderen nicht. Die Paketabfrage verbraucht den allgemeinen Ring. Verwerfen Sie auch regelmäßig ungenutzte Rohbytes in den Gegenstellenringen, um Überläufe zu vermeiden.
Die Auswahl erfolgt vor der Nutzdatenprüfung. Auch bei abgewiesenen Nutzdaten kann das neue Ziel ausgewählt bleiben.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[21+slot]=Link4_SendPacketTo(slot,data,3,64+slot);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Verbinden Sie alle vier ROMs über KOKURAs link4-Topologie. Der Host empfängt 161/162/163 von Gegenstellen 1/2/3 und zeigt LAST PEER=3. Danach sendet er die Befehle 65/66/67 mit Nutzdaten 7/42/255. Prüfen Sie diese Werte auch auf jedem Gegenstellenbildschirm.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Prüft entfernte Plätze in aufsteigender Reihenfolge und entnimmt das erste verfügbare Byte.
Syntax
u8 __stackcall Link4_TryReadByteAny(u8 *peer_slot, u8 *out);Parameter
peer_slotBeschreibbares Byte für den Herkunftsplatz; null lässt diese Ausgabe aus.
outBeschreibbares Byteziel; bei null wird das Byte verworfen.
Rückgabewert
Gibt bei Empfang 1 zurück, sonst 0.
Bedingungen und Grenzen
Der Empfangsring mit acht Einträgen fasst sieben Bytes. Ein voller Ring verwirft das neue Byte und speichert Fehler 3. Ein empfangenes Nullbyte ist gültige Nutzlast.
Link4 kopiert jedes empfangene Byte sowohl in den allgemeinen Ring als auch in einen Ring pro Gegenstelle. Das Lesen eines Rings leert den anderen nicht. Die Paketabfrage verbraucht den allgemeinen Ring. Verwerfen Sie auch regelmäßig ungenutzte Rohbytes in den Gegenstellenringen, um Überläufe zu vermeiden.
Interne kritische Abschnitte verfolgen ihre Software-Verschachtelungstiefe. Beim Verlassen des äußersten Abschnitts werden CPU-Interrupts aktiviert. Gehen Sie daher nicht davon aus, dass ein zuvor deaktivierter IME-Zustand erhalten bleibt.
Überspringt den lokalen Platz. Niedrigere Plätze mit ständig wartenden Daten haben Vorrang. Verwenden Sie bei gewünschter gleichmäßiger Rundumverteilung einzelne Gegenstellen-Leseaufrufe.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
else {other=255;Link4_TryReadByteAny(&other,&value);result[12+slot]=other;}Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Verbinden Sie alle vier ROMs über KOKURAs link4-Topologie. Der Host empfängt 161/162/163 von Gegenstellen 1/2/3 und zeigt LAST PEER=3. Danach sendet er die Befehle 65/66/67 mit Nutzdaten 7/42/255. Prüfen Sie diese Werte auch auf jedem Gegenstellenbildschirm.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Entnimmt ein Byte aus dem Empfangsring einer bestimmten Gegenstelle.
Syntax
u8 __stackcall Link4_TryReadByteFrom(u8 peer_slot, u8 *out);Parameter
peer_slotKonfigurierter entfernter Platz: vom Host aus 1 bis slot_count−1, von einer Gegenstelle aus 0.
outBeschreibbares Byteziel; bei null wird das Byte verworfen.
Rückgabewert
Gibt bei Entnahme 1 zurück. Bei leerem Ring oder ungültiger Gegenstelle wird 0 zurückgegeben und out bleibt erhalten.
Bedingungen und Grenzen
Der Empfangsring mit acht Einträgen fasst sieben Bytes. Ein voller Ring verwirft das neue Byte und speichert Fehler 3. Ein empfangenes Nullbyte ist gültige Nutzlast.
Link4 kopiert jedes empfangene Byte sowohl in den allgemeinen Ring als auch in einen Ring pro Gegenstelle. Das Lesen eines Rings leert den anderen nicht. Die Paketabfrage verbraucht den allgemeinen Ring. Verwerfen Sie auch regelmäßig ungenutzte Rohbytes in den Gegenstellenringen, um Überläufe zu vermeiden.
Interne kritische Abschnitte verfolgen ihre Software-Verschachtelungstiefe. Beim Verlassen des äußersten Abschnitts werden CPU-Interrupts aktiviert. Gehen Sie daher nicht davon aus, dass ein zuvor deaktivierter IME-Zustand erhalten bleibt.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
if(slot==1)result[13]=Link4_TryReadByteFrom(slot,&value);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Verbinden Sie alle vier ROMs über KOKURAs link4-Topologie. Der Host empfängt 161/162/163 von Gegenstellen 1/2/3 und zeigt LAST PEER=3. Danach sendet er die Befehle 65/66/67 mit Nutzdaten 7/42/255. Prüfen Sie diese Werte auch auf jedem Gegenstellenbildschirm.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Lädt SB und startet einen Vollduplex-Byteaustausch oder versetzt ihn in Bereitschaft.
Syntax
u8 __stackcall Link_BeginTransfer(u8 out);Parameter
outAusgehender Acht-Bit-Wert. Jeder Austausch sendet ein Byte, auch wenn nur der Empfang benötigt wird.
Rückgabewert
Gibt bei Start oder Bereitschaft 0 zurück, bei bereits belegter Verbindung 1.
Bedingungen und Grenzen
Jedes Gerät besitzt einen gemeinsamen Verbindungszustand. Der Byteaustausch erfolgt im Vollduplexbetrieb: Eine Seite liefert den internen Takt, die andere nutzt externe Takte. Normale Geschwindigkeit benötigt 512 Takte pro Bit, CGB-Schnellbetrieb 16.
Fehlercodes: 0=kein Fehler, 1=belegt, 2=Timeout, 3=Empfangsüberlauf, 4=ungültige Konfiguration/Protokoll, 5=ACK-Timeout mit einer Antwort wie bei einer getrennten Verbindung. Start- und Konfigurationsaufrufe melden Erfolg mit 0, Empfangs- und Entnahmeaufrufe mit 1. Erfolgreiche Aufrufe löschen keinen gespeicherten Fehler.
Ein Endpunkt mit externem Takt wartet auf Takte der Gegenseite. Eine Abweisung wegen Belegung ersetzt das bereits übertragene Byte nicht.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
lesson_delay(12);result[0]=Link_BeginTransfer(42);value=0;result[1]=Link_WaitByte(8,&value);result[2]=value;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Verbinden Sie sich mit BYTE SLAVE. Senden Sie 42, empfangen Sie 99 und tauschen Sie anschließend in beide Richtungen null aus. RECEIVED=1, PEER BYTE=99, ZERO READY=1 und ZERO BYTE=0 unterscheiden gültige Nulldaten von fehlenden Daten. Zwei CGB-Instanzen nutzen beim zweiten Austausch den schnellen Takt.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Stoppt den aktiven oder auf externen Takt wartenden Bytetransfer.
Syntax
void Link_Cancel();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Interne kritische Abschnitte verfolgen ihre Software-Verschachtelungstiefe. Beim Verlassen des äußersten Abschnitts werden CPU-Interrupts aktiviert. Gehen Sie daher nicht davon aus, dass ein zuvor deaktivierter IME-Zustand erhalten bleibt.
Schreibt SC=0 und löscht Belegt- und serielle Anforderungszustände. Empfangene Bytes, Paketzustand und Fehler bleiben bestehen. Initialisieren Sie beim vollständigen Protokollneustart zusätzlich neu.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
Link_Cancel();result[12]=Link_IsBusy();result[13]=(SC&128)!=0;Link_ClearError();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Prüft Initialisierung, Abweisung bei Belegung, Timeout mit externem Takt und Ringkapazität. Erwartet werden BUSY ERROR=1, TIMEOUT=2, OPEN RX=255, OVERFLOW=3 und QUEUE BYTES=7. Nach IRQ REQUEST=1 ruft die Lektion den Handlerkörper ausdrücklich auf, während die serielle IRQ-Quelle maskiert bleibt.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Löscht nur den gespeicherten Fehler.
Syntax
void Link_ClearError();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Fehlercodes: 0=kein Fehler, 1=belegt, 2=Timeout, 3=Empfangsüberlauf, 4=ungültige Konfiguration/Protokoll, 5=ACK-Timeout mit einer Antwort wie bei einer getrennten Verbindung. Start- und Konfigurationsaufrufe melden Erfolg mit 0, Empfangs- und Entnahmeaufrufe mit 1. Erfolgreiche Aufrufe löschen keinen gespeicherten Fehler.
Transfers, Warteschlangen und Paketzustand bleiben unverändert. Stoppen Sie den Bytetransfer mit Link_Cancel oder initialisieren Sie erneut, um den gesamten Zustand zu verwerfen.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
Link_ClearError();result[8]=Link_LastError();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Prüft Initialisierung, Abweisung bei Belegung, Timeout mit externem Takt und Ringkapazität. Erwartet werden BUSY ERROR=1, TIMEOUT=2, OPEN RX=255, OVERFLOW=3 und QUEUE BYTES=7. Nach IRQ REQUEST=1 ruft die Lektion den Handlerkörper ausdrücklich auf, während die serielle IRQ-Quelle maskiert bleibt.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Prüft, ob der allgemeine Empfangsring ungelesene Daten enthält.
Syntax
u8 Link_HasByte();Rückgabewert
Gibt bei Daten in der Warteschlange 1 zurück, sonst 0.
Bedingungen und Grenzen
Der Empfangsring mit acht Einträgen fasst sieben Bytes. Ein voller Ring verwirft das neue Byte und speichert Fehler 3. Ein empfangenes Nullbyte ist gültige Nutzlast.
Fragt die Hardware nicht ab. Übernehmen Sie den abgeschlossenen Transfer zuerst über Link_Poll oder den seriellen Handler.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[1]=Link_HasByte();value=77;result[2]=Link_TryReadByte(&value);result[3]=value;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
BYTE MASTER liefert den Takt. Erwartet werden PEER BYTE=42, ZERO READY=1 und ZERO BYTE=0. EMPTY READ ergibt danach ebenfalls null. Deshalb ist die Bereitschaftsanzeige oder der Rückgabewert von TryRead nötig, um eine leere Warteschlange zu erkennen.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Prüft den gemeinsamen Briefkasten vollständig empfangener Pakete.
Syntax
u8 Link_HasPacket();Rückgabewert
Gibt bei einem ungelesenen Paket 1 zurück, sonst 0.
Bedingungen und Grenzen
Ein Paket enthält 0xA5, Befehl, Länge, 0 bis 24 Nutzdatenbytes und eine XOR-Prüfsumme. Die Antwort ist 0x79 (ACK, angenommen) oder 0x1F (NAK, abgewiesen). Die Prüfsumme verknüpft Befehl, Länge und Nutzdaten per XOR. Jedes Gerät hat einen gemeinsamen Paketbriefkasten; Link4 besitzt zusätzlich einen pro Gegenstelle.
Liest ein Flag, ohne das Protokoll weiterzuführen. Zeigt nicht an, ob der Sender sein ACK empfangen hat.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[0]=Link_HasPacket();cmd=0;len=0;result[1]=Link_ReadPacket(&cmd,&len,data);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Verbinden Sie sich mit PACKET MASTER und prüfen Sie COMMAND=49, LENGTH=3 und Nutzdaten 7/42/255. CONSUMED=0 nach ReadPacket bedeutet, dass der Briefkasten jetzt leer ist.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Setzt den gemeinsamen Verbindungszustand auf den Standard mit externem Takt zurück.
Syntax
void Link_InitCommon();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Jedes Gerät besitzt einen gemeinsamen Verbindungszustand. Der Byteaustausch erfolgt im Vollduplexbetrieb: Eine Seite liefert den internen Takt, die andere nutzt externe Takte. Normale Geschwindigkeit benötigt 512 Takte pro Bit, CGB-Schnellbetrieb 16.
Die Initialisierung verwirft Bytewarteschlangen, Pakete, Gegenstellenauswahl und Fehler und deaktiviert Übertragung sowie serielle IRQ-Quelle. Ein laufender Austausch bleibt nicht erhalten.
Interne kritische Abschnitte verfolgen ihre Software-Verschachtelungstiefe. Beim Verlassen des äußersten Abschnitts werden CPU-Interrupts aktiviert. Gehen Sie daher nicht davon aus, dass ein zuvor deaktivierter IME-Zustand erhalten bleibt.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
Link_InitCommon();result[0]=Link_IsBusy();result[1]=Link_HasByte();result[2]=Link_LastError();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Prüft Initialisierung, Abweisung bei Belegung, Timeout mit externem Takt und Ringkapazität. Erwartet werden BUSY ERROR=1, TIMEOUT=2, OPEN RX=255, OVERFLOW=3 und QUEUE BYTES=7. Nach IRQ REQUEST=1 ruft die Lektion den Handlerkörper ausdrücklich auf, während die serielle IRQ-Quelle maskiert bleibt.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Setzt den Zustand zurück und macht dieses Gerät zur Taktquelle.
Syntax
void Link_InitMaster();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Jedes Gerät besitzt einen gemeinsamen Verbindungszustand. Der Byteaustausch erfolgt im Vollduplexbetrieb: Eine Seite liefert den internen Takt, die andere nutzt externe Takte. Normale Geschwindigkeit benötigt 512 Takte pro Bit, CGB-Schnellbetrieb 16.
Die Initialisierung verwirft Bytewarteschlangen, Pakete, Gegenstellenauswahl und Fehler und deaktiviert Übertragung sowie serielle IRQ-Quelle. Ein laufender Austausch bleibt nicht erhalten.
Interne kritische Abschnitte verfolgen ihre Software-Verschachtelungstiefe. Beim Verlassen des äußersten Abschnitts werden CPU-Interrupts aktiviert. Gehen Sie daher nicht davon aus, dass ein zuvor deaktivierter IME-Zustand erhalten bleibt.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
Link_InitMaster();Link_SetUseInterrupt(0);Link_SetFastClock(0);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Verbinden Sie sich mit BYTE SLAVE. Senden Sie 42, empfangen Sie 99 und tauschen Sie anschließend in beide Richtungen null aus. RECEIVED=1, PEER BYTE=99, ZERO READY=1 und ZERO BYTE=0 unterscheiden gültige Nulldaten von fehlenden Daten. Zwei CGB-Instanzen nutzen beim zweiten Austausch den schnellen Takt.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Setzt den Zustand zurück und wählt Kommunikation mit externem Takt.
Syntax
void Link_InitSlave();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Jedes Gerät besitzt einen gemeinsamen Verbindungszustand. Der Byteaustausch erfolgt im Vollduplexbetrieb: Eine Seite liefert den internen Takt, die andere nutzt externe Takte. Normale Geschwindigkeit benötigt 512 Takte pro Bit, CGB-Schnellbetrieb 16.
Die Initialisierung verwirft Bytewarteschlangen, Pakete, Gegenstellenauswahl und Fehler und deaktiviert Übertragung sowie serielle IRQ-Quelle. Ein laufender Austausch bleibt nicht erhalten.
Interne kritische Abschnitte verfolgen ihre Software-Verschachtelungstiefe. Beim Verlassen des äußersten Abschnitts werden CPU-Interrupts aktiviert. Gehen Sie daher nicht davon aus, dass ein zuvor deaktivierter IME-Zustand erhalten bleibt.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
Link_InitSlave();result[0]=Link_BeginTransfer(99);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
BYTE MASTER liefert den Takt. Erwartet werden PEER BYTE=42, ZERO READY=1 und ZERO BYTE=0. EMPTY READ ergibt danach ebenfalls null. Deshalb ist die Bereitschaftsanzeige oder der Rückgabewert von TryRead nötig, um eine leere Warteschlange zu erkennen.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Prüft einmal auf Abschluss und meldet danach, ob noch ein Austausch aktiv ist.
Syntax
u8 Link_IsBusy();Rückgabewert
Gibt bei Belegung 1 zurück, sonst 0.
Bedingungen und Grenzen
Der Empfangsring mit acht Einträgen fasst sieben Bytes. Ein voller Ring verwirft das neue Byte und speichert Fehler 3. Ein empfangenes Nullbyte ist gültige Nutzlast.
Dies ist keine passive Abfrage: Ein fertig empfangenes SB-Byte wird eingereiht, wodurch sich Datenbereitschaft und Fehlerzustand ändern können.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[3]=Link_IsBusy();result[4]=Link_HasByte();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Verbinden Sie sich mit BYTE SLAVE. Senden Sie 42, empfangen Sie 99 und tauschen Sie anschließend in beide Richtungen null aus. RECEIVED=1, PEER BYTE=99, ZERO READY=1 und ZERO BYTE=0 unterscheiden gültige Nulldaten von fehlenden Daten. Zwei CGB-Instanzen nutzen beim zweiten Austausch den schnellen Takt.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Liest den zuletzt gespeicherten Verbindungsfehler, ohne ihn zu löschen.
Syntax
u8 Link_LastError();Rückgabewert
Gibt den aktuellen Fehlercode von 0 bis 5 zurück.
Bedingungen und Grenzen
Fehlercodes: 0=kein Fehler, 1=belegt, 2=Timeout, 3=Empfangsüberlauf, 4=ungültige Konfiguration/Protokoll, 5=ACK-Timeout mit einer Antwort wie bei einer getrennten Verbindung. Start- und Konfigurationsaufrufe melden Erfolg mit 0, Empfangs- und Entnahmeaufrufe mit 1. Erfolgreiche Aufrufe löschen keinen gespeicherten Fehler.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[2]=Link_LastError();Link_ClearError();result[3]=Link_LastError();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Senden Sie Befehl 49 mit Nutzdaten 7/42/255 und ändern Sie danach das Quellarray. QUEUED=0 nimmt den Versand an, SECOND SEND=1 weist einen zweiten Start ab. Der Belegtfehler bleibt bis ClearError gespeichert. PAYLOAD 2=42 auf der Empfangsseite belegt, dass die Bibliothek eine eigene Kopie der eingereihten Nutzdaten hält.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Übernimmt ein abgeschlossenes Byte aus einem Handler, der eine serielle Anforderung erkannt hat.
Syntax
void Link_OnSerialIRQ();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Der Empfangsring mit acht Einträgen fasst sieben Bytes. Ein voller Ring verwirft das neue Byte und speichert Fehler 3. Ein empfangenes Nullbyte ist gültige Nutzlast.
Interne kritische Abschnitte verfolgen ihre Software-Verschachtelungstiefe. Beim Verlassen des äußersten Abschnitts werden CPU-Interrupts aktiviert. Gehen Sie daher nicht davon aus, dass ein zuvor deaktivierter IME-Zustand erhalten bleibt.
Die Funktion prüft SC nicht auf Abschluss. Rufen Sie sie bei aktivem seriellen Transfer nicht aus einem sachfremden Timerinterrupt auf. Das Beispiel führt sie nach einer echten IF.serial-Anforderung ausdrücklich aus, während die serielle CPU-IRQ-Quelle maskiert ist. Geprüft wird der Funktionskörper, nicht die Vektorinstallation.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
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;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Prüft Initialisierung, Abweisung bei Belegung, Timeout mit externem Takt und Ringkapazität. Erwartet werden BUSY ERROR=1, TIMEOUT=2, OPEN RX=255, OVERFLOW=3 und QUEUE BYTES=7. Nach IRQ REQUEST=1 ruft die Lektion den Handlerkörper ausdrücklich auf, während die serielle IRQ-Quelle maskiert bleibt.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Übernimmt einen laufenden Transfer erst nach dem Löschen des Startbits in SC und reiht das empfangene Byte ein.
Syntax
void Link_Poll();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Der Empfangsring mit acht Einträgen fasst sieben Bytes. Ein voller Ring verwirft das neue Byte und speichert Fehler 3. Ein empfangenes Nullbyte ist gültige Nutzlast.
Der Aufruf blockiert nicht. Bei inaktivem Softwarezustand tut er nichts; eine Timeoutfunktion ist nicht enthalten.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
for(i=0;i<24;i++){Link_Poll();if(Link_HasByte())break;m_wait();}Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
BYTE MASTER liefert den Takt. Erwartet werden PEER BYTE=42, ZERO READY=1 und ZERO BYTE=0. EMPTY READ ergibt danach ebenfalls null. Deshalb ist die Bereitschaftsanzeige oder der Rückgabewert von TryRead nötig, um eine leere Warteschlange zu erkennen.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Verarbeitet empfangene Bytes, startet das nächste ausgehende Byte oder ACK und führt Timeout- und Wiederholungszustände weiter.
Syntax
void Link_PollPacket();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Ein Paket enthält 0xA5, Befehl, Länge, 0 bis 24 Nutzdatenbytes und eine XOR-Prüfsumme. Die Antwort ist 0x79 (ACK, angenommen) oder 0x1F (NAK, abgewiesen). Die Prüfsumme verknüpft Befehl, Länge und Nutzdaten per XOR. Jedes Gerät hat einen gemeinsamen Paketbriefkasten; Link4 besitzt zusätzlich einen pro Gegenstelle.
Fragen Sie beide Endpunkte fortlaufend ab. Ein Timeout zählt 90 Aufrufe ohne Fortschritt, keine Hardwareframes. Das Senden von 0xFF allein zur Taktversorgung eines ACK verlängert die Frist nicht; höchstens drei Sendeversuche sind erlaubt. Wiederholungen können Duplikate liefern. Ergänzen Sie Kennungen auf Anwendungsebene, wenn ein Befehl genau einmal ausgeführt werden muss.
Rohe Leseaufrufe wie ReadByte verbrauchen denselben allgemeinen Ring und können Teile eines Pakets entnehmen. Mischen Sie keine Rohlesezugriffe mit Paketempfang.
Link4 kopiert jedes empfangene Byte sowohl in den allgemeinen Ring als auch in einen Ring pro Gegenstelle. Das Lesen eines Rings leert den anderen nicht. Die Paketabfrage verbraucht den allgemeinen Ring. Verwerfen Sie auch regelmäßig ungenutzte Rohbytes in den Gegenstellenringen, um Überläufe zu vermeiden.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
Link_InitSlave();for(i=0;i<120;i++){Link_PollPacket();m_wait();}Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Verbinden Sie sich mit PACKET MASTER und prüfen Sie COMMAND=49, LENGTH=3 und Nutzdaten 7/42/255. CONSUMED=0 nach ReadPacket bedeutet, dass der Briefkasten jetzt leer ist.


Vollständiges Beispielprogramm
Build-Befehl
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.pngAnwendungsbeispiel
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();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Senden Sie ohne angeschlossene Gegenstelle. Bytetransfers enden mit internem Takt, aber es kommt kein ACK. Nach den Wiederholungen gilt NO ACK ERROR=5. Cancel hinterlässt CANCEL BUSY=0.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Gibt ein aus dem allgemeinen Empfangsring entnommenes Byte zurück.
Syntax
u8 Link_ReadByte();Rückgabewert
Gibt das empfangene Byte zurück; bei leerer Warteschlange ebenfalls null.
Bedingungen und Grenzen
Der Empfangsring mit acht Einträgen fasst sieben Bytes. Ein voller Ring verwirft das neue Byte und speichert Fehler 3. Ein empfangenes Nullbyte ist gültige Nutzlast.
Interne kritische Abschnitte verfolgen ihre Software-Verschachtelungstiefe. Beim Verlassen des äußersten Abschnitts werden CPU-Interrupts aktiviert. Gehen Sie daher nicht davon aus, dass ein zuvor deaktivierter IME-Zustand erhalten bleibt.
Der Rückgabewert allein unterscheidet kein empfangenes Nullbyte von einer leeren Warteschlange. Nutzen Sie das Erfolgsflag von TryReadByte oder prüfen Sie vor dem Lesen mit HasByte.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[6]=Link_HasByte();result[7]=Link_ReadByte();result[8]=Link_ReadByte();result[9]=Link_LastError();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
BYTE MASTER liefert den Takt. Erwartet werden PEER BYTE=42, ZERO READY=1 und ZERO BYTE=0. EMPTY READ ergibt danach ebenfalls null. Deshalb ist die Bereitschaftsanzeige oder der Rückgabewert von TryRead nötig, um eine leere Warteschlange zu erkennen.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Kopiert ein vollständiges Paket und entnimmt es aus dem gemeinsamen Briefkasten.
Syntax
u8 __stackcall Link_ReadPacket(u8 *cmd, u8 *len, u8 *dst);Parameter
cmdBeschreibbares Befehlsbyte; null lässt diese Ausgabe aus.
lenBeschreibbares Längenbyte von 0 bis 24; null lässt diese Ausgabe aus.
dstBeschreibbarer Nutzdatenpuffer mit Platz für 24 Bytes; null verwirft die Nutzdaten.
Rückgabewert
Gibt bei Entnahme 1 zurück, bei leerem Briefkasten 0. Leere Lesezugriffe lassen die Ausgaben unverändert.
Bedingungen und Grenzen
Es gibt keinen Parameter für die Zielkapazität. Stellen Sie bei Verwendung von dst 24 beschreibbare Bytes bereit. cmd, len und dst dürfen unabhängig voneinander null sein. Koordinieren Sie Prüfung und Entnahme des Briefkasteninhalts so, dass anderer Code oder Interrupts nicht gleichzeitig darauf zugreifen.
Im Link4-Modus wird auch der zu diesem gemeinsamen Paket gehörende Gegenstellenbriefkasten geleert. Andere Gegenstellenbriefkästen bleiben verfügbar.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[0]=Link_HasPacket();cmd=0;len=0;result[1]=Link_ReadPacket(&cmd,&len,data);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Verbinden Sie sich mit PACKET MASTER und prüfen Sie COMMAND=49, LENGTH=3 und Nutzdaten 7/42/255. CONSUMED=0 nach ReadPacket bedeutet, dass der Briefkasten jetzt leer ist.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Kopiert die Nutzdaten in eigenen Speicher und plant den Paketversand ein.
Syntax
u8 __stackcall Link_SendPacket(const u8 *data, u8 len, u8 cmd);Parameter
dataÜber len Bytes lesbare Quelle; nur bei len gleich null darf sie null sein.
lenNutzdatenlänge in Bytes von 0 bis 24.
cmdVon der Anwendung definierter Acht-Bit-Befehl.
Rückgabewert
Gibt bei Annahme 0 zurück, bei belegtem Paketzustand 1 und bei ungültiger Länge oder ungültigem Zeiger 4.
Bedingungen und Grenzen
Fehlercodes: 0=kein Fehler, 1=belegt, 2=Timeout, 3=Empfangsüberlauf, 4=ungültige Konfiguration/Protokoll, 5=ACK-Timeout mit einer Antwort wie bei einer getrennten Verbindung. Start- und Konfigurationsaufrufe melden Erfolg mit 0, Empfangs- und Entnahmeaufrufe mit 1. Erfolgreiche Aufrufe löschen keinen gespeicherten Fehler.
Ein Paket enthält 0xA5, Befehl, Länge, 0 bis 24 Nutzdatenbytes und eine XOR-Prüfsumme. Die Antwort ist 0x79 (ACK, angenommen) oder 0x1F (NAK, abgewiesen). Die Prüfsumme verknüpft Befehl, Länge und Nutzdaten per XOR. Jedes Gerät hat einen gemeinsamen Paketbriefkasten; Link4 besitzt zusätzlich einen pro Gegenstelle.
Fragen Sie beide Endpunkte fortlaufend ab. Ein Timeout zählt 90 Aufrufe ohne Fortschritt, keine Hardwareframes. Das Senden von 0xFF allein zur Taktversorgung eines ACK verlängert die Frist nicht; höchstens drei Sendeversuche sind erlaubt. Wiederholungen können Duplikate liefern. Ergänzen Sie Kennungen auf Anwendungsebene, wenn ein Befehl genau einmal ausgeführt werden muss.
Null bedeutet eingereiht, nicht von der Gegenstelle empfangen oder bestätigt. Nach der Annahme darf das Quellarray wiederverwendet werden.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[0]=Link_SendPacket(data,3,0x31);data[1]=0;result[1]=Link_SendPacket(data,3,0x32);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Senden Sie Befehl 49 mit Nutzdaten 7/42/255 und ändern Sie danach das Quellarray. QUEUED=0 nimmt den Versand an, SECOND SEND=1 weist einen zweiten Start ab. Der Belegtfehler bleibt bis ClearError gespeichert. PAYLOAD 2=42 auf der Empfangsseite belegt, dass die Bibliothek eine eigene Kopie der eingereihten Nutzdaten hält.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Wählt, ob künftige Transfers mit internem Takt das CGB-Schnelltaktbit verwenden.
Syntax
void __stackcall Link_SetFastClock(u8 on);Parameter
onNull fordert normale, jeder andere Wert schnelle Übertragung an.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Jedes Gerät besitzt einen gemeinsamen Verbindungszustand. Der Byteaustausch erfolgt im Vollduplexbetrieb: Eine Seite liefert den internen Takt, die andere nutzt externe Takte. Normale Geschwindigkeit benötigt 512 Takte pro Bit, CGB-Schnellbetrieb 16.
Ändert keine laufende Übertragung. Transfers mit externem Takt ignorieren diese Einstellung. Hardwareunterstützung wird nicht geprüft. Betreiben Sie beide Beispielendpunkte in zueinander passenden Hardwaremodi.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
lesson_delay(12);Link_SetFastClock(__cgb_is_cgb());result[5]=Link_BeginTransfer(0);value=77;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Verbinden Sie sich mit BYTE SLAVE. Senden Sie 42, empfangen Sie 99 und tauschen Sie anschließend in beide Richtungen null aus. RECEIVED=1, PEER BYTE=99, ZERO READY=1 und ZERO BYTE=0 unterscheiden gültige Nulldaten von fehlenden Daten. Zwei CGB-Instanzen nutzen beim zweiten Austausch den schnellen Takt.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Setzt das Freigabebit des seriellen Interrupts und löscht eine ausstehende serielle Anforderung.
Syntax
void __stackcall Link_SetUseInterrupt(u8 on);Parameter
onNull deaktiviert; jeder andere Wert aktiviert.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Interne kritische Abschnitte verfolgen ihre Software-Verschachtelungstiefe. Beim Verlassen des äußersten Abschnitts werden CPU-Interrupts aktiviert. Gehen Sie daher nicht davon aus, dass ein zuvor deaktivierter IME-Zustand erhalten bleibt.
Installieren Sie den Handler für Vektor 0058h separat; die Bibliothek registriert keinen. Das Beispiel maskiert die Quelle vor der Übertragung erneut und prüft keinen CPU-Interrupt-Einstiegscode.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
Link_SetUseInterrupt(1);result[3]=(IE_REG&8)!=0;Link_SetUseInterrupt(0);result[4]=(IE_REG&8)!=0;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Prüft Initialisierung, Abweisung bei Belegung, Timeout mit externem Takt und Ringkapazität. Erwartet werden BUSY ERROR=1, TIMEOUT=2, OPEN RX=255, OVERFLOW=3 und QUEUE BYTES=7. Nach IRQ REQUEST=1 ruft die Lektion den Handlerkörper ausdrücklich auf, während die serielle IRQ-Quelle maskiert bleibt.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Entnimmt dem allgemeinen Empfangsring ohne Warten ein Byte.
Syntax
u8 __stackcall Link_TryReadByte(u8 *out);Parameter
outBeschreibbares Byteziel; bei null wird das Byte verworfen.
Rückgabewert
Gibt bei Entnahme 1 zurück, bei leerem Ring 0. Ein leerer Lesezugriff lässt out unverändert.
Bedingungen und Grenzen
Der Empfangsring mit acht Einträgen fasst sieben Bytes. Ein voller Ring verwirft das neue Byte und speichert Fehler 3. Ein empfangenes Nullbyte ist gültige Nutzlast.
Interne kritische Abschnitte verfolgen ihre Software-Verschachtelungstiefe. Beim Verlassen des äußersten Abschnitts werden CPU-Interrupts aktiviert. Gehen Sie daher nicht davon aus, dass ein zuvor deaktivierter IME-Zustand erhalten bleibt.
Link4 kopiert jedes empfangene Byte sowohl in den allgemeinen Ring als auch in einen Ring pro Gegenstelle. Das Lesen eines Rings leert den anderen nicht. Die Paketabfrage verbraucht den allgemeinen Ring. Verwerfen Sie auch regelmäßig ungenutzte Rohbytes in den Gegenstellenringen, um Überläufe zu vermeiden.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[1]=Link_HasByte();value=77;result[2]=Link_TryReadByte(&value);result[3]=value;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
BYTE MASTER liefert den Takt. Erwartet werden PEER BYTE=42, ZERO READY=1 und ZERO BYTE=0. EMPTY READ ergibt danach ebenfalls null. Deshalb ist die Bereitschaftsanzeige oder der Rückgabewert von TryRead nötig, um eine leere Warteschlange zu erkennen.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Fragt sofort ab und wartet danach mit einer VBlank-basierten Grenze auf ein Byte.
Syntax
u8 __stackcall Link_WaitByte(u16 timeout_frames, u8 *out);Parameter
timeout_framesMaximale Anzahl von VBlank-Wartevorgängen. Auch null führt die erste Abfrage und den ersten Leseversuch aus.
outEin beschreibbares Byte ist erforderlich. Null liefert sofort null zurück, ohne den gespeicherten Fehler zu ändern.
Rückgabewert
Gibt bei Empfang 1 zurück, bei Timeout oder Null-Ausgabe 0.
Bedingungen und Grenzen
Der Empfangsring mit acht Einträgen fasst sieben Bytes. Ein voller Ring verwirft das neue Byte und speichert Fehler 3. Ein empfangenes Nullbyte ist gültige Nutzlast.
Verwenden Sie die Funktion bei laufendem LCD. Ein Timeout speichert Fehler 2 und lässt out unverändert. Der Transfer selbst wird nicht abgebrochen. Rufen Sie Cancel auf, wenn Sie ihn aufgeben.
Die Bilder stammen aus KOKURA. Beispiele mit mehreren Endpunkten prüfen Werte in verbundenen Emulatorinstanzen und nehmen Bilder aus deren abschließend gespeicherten Zuständen auf. Diese Prüfungen belegen kein Verhalten echter Kabel oder Vier-Spieler-Adapter.
Führen Sie diese PowerShell-Befehle im gemeinsamen übergeordneten Ordner von kitaqgb, kokura und kitaq-docs aus. Bauen Sie alle beteiligten ROMs vor dem Start der verbundenen Sitzung. Belassen Sie bei Link4 die erzeugten Symbolmetadaten neben den ROMs. Ersetzen Sie für DMG-Läufe überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
value=77;result[9]=Link_WaitByte(2,&value);result[10]=value;result[11]=Link_LastError();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Prüft Initialisierung, Abweisung bei Belegung, Timeout mit externem Takt und Ringkapazität. Erwartet werden BUSY ERROR=1, TIMEOUT=2, OPEN RX=255, OVERFLOW=3 und QUEUE BYTES=7. Nach IRQ REQUEST=1 ruft die Lektion den Handlerkörper ausdrücklich auf, während die serielle IRQ-Quelle maskiert bleibt.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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-Kommunikation mit externem Takt
DMG-07 verteilt ein Byte jeder Konsole an alle vier Spieler. Diese Bibliothek verwaltet Erkennung, Start durch Spieler 1, verzögerte Paketrundsendungen und ausgerichtete Neustartsteuerung. EXCHANGE erklärt Vier-Konsolen-Austausch, NO ADAPTER Zeitüberschreitungen, OVERFLOW ungelesene Daten und RESTART Wiederherstellung.
Die Bibliothek nummeriert Spieler 1..4; null bedeutet noch nicht erkannt. Verbindungsbits 0..3 entsprechen Spielern 1..4. Die Slotwerte von KOKURA --link-session sind 0..3, eine von der ROM-API getrennte Nummerierung.
Dieser Treiber beansprucht den seriellen Port. Führen Sie gewöhnliches Link oder Link4 nicht gleichzeitig aus; binden Sie link_hwregs_gb.c und link_dmg07.c je einmal ein. Der Adapter liefert externe Takte; der Treiber wählt nicht den schnellen CGB-Seriellmodus.
Rufen Sie Poll über den ganzen Frame wiederholt und TickFrame genau einmal pro Frame auf. Ein Poll pro VBlank kann den Port zwischen Adapterbytes nicht neu vorbereiten. d_poll im gemeinsamen Header erkennt den Eintritt in LY >= 144 und ruft TickFrame einmal auf. Serialisieren Sie beide Operationen, statt ISR und Hauptschleife konkurrieren zu lassen.
Bei SIZE=1 liefert jede Konsole ein Byte; die Vier-Byte-Rundsendung folgt Spielern 1..4. Die erste wird verworfen. Spätere Rundsendungen enthalten die Beiträge des vorigen Pakets. Vier Bytes mit ausschließlich 0xFF sind als Neustartsignal reserviert.
LinkDmg07_ClearError
Setzt den letzten Fehlercode auf null zurück.
Syntax
void LinkDmg07_ClearError();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
SilenceFrames und Diagnosezähler sättigen bei 255. Init setzt alle zurück; gewöhnliche Protokollneustarts erhalten die Diagnosezähler. ClearError löscht nur den Fehlercode.
Erhält Empfangsdaten, Phase, Verbindungsinformationen und Timeout-Markierung. Dieser Aufruf allein verbindet nicht neu und setzt den Empfang nicht fort.
Die Bilder stammen aus KOKURAs DMG-07-Modell. Jede Konsole läuft unabhängig; gesendete und empfangene Werte werden verglichen. Elektrisches Verhalten und Timing physischer Adapter und Kabel sind ungeprüft. CGB-Bilder zeigen Zahlen blau.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Vier-Konsolen-Beispiele starten dieselbe ROM in vier Sitzungen. Ersetzen Sie für DMG-Prüfungen überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
LinkDmg07_ClearError();result[21]=LinkDmg07_LastError();result[22]=LinkDmg07_GetErrorCount();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Lassen Sie das erste gültige Paket bis zum nächsten ungelesen. Erwartet werden SENT SEQ=3, PACKET SEQ=2 und ERROR=6; gelesen werden die neuesten 33/34/35/36. ClearError setzt CLEAR ERROR auf null, während ErrorCount eins bleibt.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Verbraucht und löscht eine abgeschlossene Erkennungsmeldung.
Syntax
u8 LinkDmg07_ConsumePingStatus();Rückgabewert
Gibt bei Verbrauch 1 zurück, sonst 0.
Bedingungen und Grenzen
Löscht nur die Meldung und erhält Slot, Maske und LastStatus. Weitere Aufrufe liefern bis zur nächsten Meldung null.
Die Bilder stammen aus KOKURAs DMG-07-Modell. Jede Konsole läuft unabhängig; gesendete und empfangene Werte werden verglichen. Elektrisches Verhalten und Timing physischer Adapter und Kabel sind ungeprüft. CGB-Bilder zeigen Zahlen blau.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Vier-Konsolen-Beispiele starten dieselbe ROM in vier Sitzungen. Ersetzen Sie für DMG-Prüfungen überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[3]=LinkDmg07_ConsumePingStatus();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Starten Sie dieselbe ROM auf vier Konsolen; jede sendet 32 plus ihre Spielernummer. Alle empfangen PLAYER 1..4 = 33/34/35/36. Die erste gültige Rundsendung hält SENT SEQ=2 und PACKET SEQ=1 fest und zeigt die Verzögerung um ein Paket. Das Bild friert diese Beobachtung ein; ein Spiel fragt anschließend weiter ab.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Liest die Vier-Bit-Spielermenge des zuletzt akzeptierten Status.
Syntax
u8 LinkDmg07_GetConnectedMask();Rückgabewert
Bits 0..3 melden verbundene Spieler. Nicht erkannt ist null; vier verbundene Spieler ergeben 15.
Bedingungen und Grenzen
Die Bibliothek nummeriert Spieler 1..4; null bedeutet noch nicht erkannt. Verbindungsbits 0..3 entsprechen Spielern 1..4. Die Slotwerte von KOKURA --link-session sind 0..3, eine von der ROM-API getrennte Nummerierung.
Gibt den gespeicherten Erkennungsstatus zurück, ohne physische Verkabelung zu prüfen. Während des Transfers gilt die zuletzt akzeptierte Meldung.
Die Bilder stammen aus KOKURAs DMG-07-Modell. Jede Konsole läuft unabhängig; gesendete und empfangene Werte werden verglichen. Elektrisches Verhalten und Timing physischer Adapter und Kabel sind ungeprüft. CGB-Bilder zeigen Zahlen blau.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Vier-Konsolen-Beispiele starten dieselbe ROM in vier Sitzungen. Ersetzen Sie für DMG-Prüfungen überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[1]=LinkDmg07_GetConnectedMask();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Starten Sie dieselbe ROM auf vier Konsolen; jede sendet 32 plus ihre Spielernummer. Alle empfangen PLAYER 1..4 = 33/34/35/36. Die erste gültige Rundsendung hält SENT SEQ=2 und PACKET SEQ=1 fest und zeigt die Verzögerung um ein Paket. Das Bild friert diese Beobachtung ein; ein Spiel fragt anschließend weiter ab.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Liest erfasste Verlustereignisse: Stille nach Adaptererkennung oder aus dem Erkennungsstatus verschwundene Spieler.
Syntax
u8 LinkDmg07_GetDisconnectCount();Rückgabewert
Gibt 0..255 Ereignisse zurück, nicht die Anzahl verlorener Spieler.
Bedingungen und Grenzen
SilenceFrames und Diagnosezähler sättigen bei 255. Init setzt alle zurück; gewöhnliche Protokollneustarts erhalten die Diagnosezähler. ClearError löscht nur den Fehlercode.
Fristablauf vor der ersten Adaptererkennung erhöht ihn nicht. Mehrere bei einer Statusänderung verschwundene Spieler zählen als ein Ereignis.
Die Bilder stammen aus KOKURAs DMG-07-Modell. Jede Konsole läuft unabhängig; gesendete und empfangene Werte werden verglichen. Elektrisches Verhalten und Timing physischer Adapter und Kabel sind ungeprüft. CGB-Bilder zeigen Zahlen blau.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Vier-Konsolen-Beispiele starten dieselbe ROM in vier Sitzungen. Ersetzen Sie für DMG-Prüfungen überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[8]=LinkDmg07_GetDisconnectCount();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Führen Sie das Beispiel ohne Adapter aus. Erwartet werden PLAYER=0, START ERROR=2, SILENT FRAME=12, TIMEOUTS=1 und ERROR=4. DISCONNECTS bleibt null, weil noch kein Adapter erkannt wurde. Leeres Lesen erhält EMPTY BUFFER=77; ClearError ergibt CLEARED=0.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Liest die Anzahl empfangener Protokollfehler und überschriebener ungelesener Pakete.
Syntax
u8 LinkDmg07_GetErrorCount();Rückgabewert
Gibt 0..255 zurück. Anforderungsvalidierungs-/Zustandsfehler und Timeouts sind nicht enthalten.
Bedingungen und Grenzen
SilenceFrames und Diagnosezähler sättigen bei 255. Init setzt alle zurück; gewöhnliche Protokollneustarts erhalten die Diagnosezähler. ClearError löscht nur den Fehlercode.
Das Empfangsfach speichert nur das neueste Paket. Der Abschluss eines weiteren Pakets überschreibt ungelesene Daten, merkt Fehler 6 und erhöht ErrorCount. Der Adapter wartet nicht auf das Auslesen durch die Anwendung.
Die Bilder stammen aus KOKURAs DMG-07-Modell. Jede Konsole läuft unabhängig; gesendete und empfangene Werte werden verglichen. Elektrisches Verhalten und Timing physischer Adapter und Kabel sind ungeprüft. CGB-Bilder zeigen Zahlen blau.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Vier-Konsolen-Beispiele starten dieselbe ROM in vier Sitzungen. Ersetzen Sie für DMG-Prüfungen überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[19]=LinkDmg07_GetErrorCount();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Lassen Sie das erste gültige Paket bis zum nächsten ungelesen. Erwartet werden SENT SEQ=3, PACKET SEQ=2 und ERROR=6; gelesen werden die neuesten 33/34/35/36. ClearError setzt CLEAR ERROR auf null, während ErrorCount eins bleibt.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Liest das zuletzt geprüfte rohe Adapterstatusbyte.
Syntax
u8 LinkDmg07_GetLastStatus();Rückgabewert
Das obere Nibble enthält die Verbindungsmaske, die unteren drei Bits die lokale Spielernummer. Anfangswert null.
Bedingungen und Grenzen
Die Bibliothek nummeriert Spieler 1..4; null bedeutet noch nicht erkannt. Verbindungsbits 0..3 entsprechen Spielern 1..4. Die Slotwerte von KOKURA --link-session sind 0..3, eine von der ROM-API getrennte Nummerierung.
Lehnt Statuswerte mit gesetztem Bit 3, Spielernummer null oder über vier sowie nach Erkennung geänderter lokaler Nummer ab. Die Ablehnung merkt Fehler 5, ohne den Wert als LastStatus zu speichern.
Die Bilder stammen aus KOKURAs DMG-07-Modell. Jede Konsole läuft unabhängig; gesendete und empfangene Werte werden verglichen. Elektrisches Verhalten und Timing physischer Adapter und Kabel sind ungeprüft. CGB-Bilder zeigen Zahlen blau.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Vier-Konsolen-Beispiele starten dieselbe ROM in vier Sitzungen. Ersetzen Sie für DMG-Prüfungen überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[2]=LinkDmg07_GetLastStatus();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Starten Sie dieselbe ROM auf vier Konsolen; jede sendet 32 plus ihre Spielernummer. Alle empfangen PLAYER 1..4 = 33/34/35/36. Die erste gültige Rundsendung hält SENT SEQ=2 und PACKET SEQ=1 fest und zeigt die Verzögerung um ein Paket. Das Bild friert diese Beobachtung ein; ein Spiel fragt anschließend weiter ab.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Liest die aus dem Adapterstatus ermittelte Spielernummer dieser Konsole.
Syntax
u8 LinkDmg07_GetLocalSlot();Rückgabewert
Gibt nach Erkennung 1..4 zurück, davor oder unmittelbar nach einem Erkennungsreset null.
Bedingungen und Grenzen
Die Bibliothek nummeriert Spieler 1..4; null bedeutet noch nicht erkannt. Verbindungsbits 0..3 entsprechen Spielern 1..4. Die Slotwerte von KOKURA --link-session sind 0..3, eine von der ROM-API getrennte Nummerierung.
Die Bilder stammen aus KOKURAs DMG-07-Modell. Jede Konsole läuft unabhängig; gesendete und empfangene Werte werden verglichen. Elektrisches Verhalten und Timing physischer Adapter und Kabel sind ungeprüft. CGB-Bilder zeigen Zahlen blau.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Vier-Konsolen-Beispiele starten dieselbe ROM in vier Sitzungen. Ersetzen Sie für DMG-Prüfungen überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
slot=LinkDmg07_GetLocalSlot();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Starten Sie dieselbe ROM auf vier Konsolen; jede sendet 32 plus ihre Spielernummer. Alle empfangen PLAYER 1..4 = 33/34/35/36. Die erste gültige Rundsendung hält SENT SEQ=2 und PACKET SEQ=1 fest und zeigt die Verzögerung um ein Paket. Das Bild friert diese Beobachtung ein; ein Spiel fragt anschließend weiter ab.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Liest die dem zuletzt bereitgestellten Paket zugewiesene Sequenz.
Syntax
u8 LinkDmg07_GetPacketSequence();Rückgabewert
Gibt die 8-Bit-Paketsequenz zurück, ohne die Bereitschaft zu ändern.
Bedingungen und Grenzen
Sequenznummern laufen von 255 auf null um. Bei der Bereitstellung des Pakets ist PacketSequence gleich SentSequence minus eins. Spätere Sendestarts erhöhen SentSequence; später abgefragte Werte müssen daher nicht um eins differieren.
Das Empfangsfach speichert nur das neueste Paket. Der Abschluss eines weiteren Pakets überschreibt ungelesene Daten, merkt Fehler 6 und erhöht ErrorCount. Der Adapter wartet nicht auf das Auslesen durch die Anwendung.
Die Bilder stammen aus KOKURAs DMG-07-Modell. Jede Konsole läuft unabhängig; gesendete und empfangene Werte werden verglichen. Elektrisches Verhalten und Timing physischer Adapter und Kabel sind ungeprüft. CGB-Bilder zeigen Zahlen blau.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Vier-Konsolen-Beispiele starten dieselbe ROM in vier Sitzungen. Ersetzen Sie für DMG-Prüfungen überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[7]=LinkDmg07_GetPacketSequence();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Starten Sie dieselbe ROM auf vier Konsolen; jede sendet 32 plus ihre Spielernummer. Alle empfangen PLAYER 1..4 = 33/34/35/36. Die erste gültige Rundsendung hält SENT SEQ=2 und PACKET SEQ=1 fest und zeigt die Verzögerung um ein Paket. Das Bild friert diese Beobachtung ein; ein Spiel fragt anschließend weiter ab.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Liest das Byte eines Spielers aus dem gespeicherten Paket.
Syntax
u8 __stackcall LinkDmg07_GetPacketSlot(u8 player_slot);Parameter
player_slotPhysische Spielernummer, 1..4.
Rückgabewert
Gibt das gespeicherte Byte von Spieler 1..4 zurück, bei ungültiger Nummer null.
Bedingungen und Grenzen
Die Bibliothek nummeriert Spieler 1..4; null bedeutet noch nicht erkannt. Verbindungsbits 0..3 entsprechen Spielern 1..4. Die Slotwerte von KOKURA --link-session sind 0..3, eine von der ROM-API getrennte Nummerierung.
Prüft und verbraucht keine Bereitschaft. Liefert direkt nach Initialisierung null und eventuell erhaltene Bytes nach Verbrauch oder Erkennungsreset. Nicht als Neudatenprüfung verwenden.
Die Bilder stammen aus KOKURAs DMG-07-Modell. Jede Konsole läuft unabhängig; gesendete und empfangene Werte werden verglichen. Elektrisches Verhalten und Timing physischer Adapter und Kabel sind ungeprüft. CGB-Bilder zeigen Zahlen blau.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Vier-Konsolen-Beispiele starten dieselbe ROM in vier Sitzungen. Ersetzen Sie für DMG-Prüfungen überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[16]=LinkDmg07_GetPacketSlot(4);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Starten Sie dieselbe ROM auf vier Konsolen; jede sendet 32 plus ihre Spielernummer. Alle empfangen PLAYER 1..4 = 33/34/35/36. Die erste gültige Rundsendung hält SENT SEQ=2 und PACKET SEQ=1 fest und zeigt die Verzögerung um ein Paket. Das Bild friert diese Beobachtung ein; ein Spiel fragt anschließend weiter ab.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Liest die aktuelle Erkennungs-, Startanforderungs-, Bestätigungs- oder Transferphase.
Syntax
u8 LinkDmg07_GetPhase();Rückgabewert
0=PING, 1=REQUEST_AA, 2=WAIT_CC, 3=TRANSFER.
Bedingungen und Grenzen
Fragt nicht ab und wartet nicht. Die Annahme einer Startanforderung reicht für TRANSFER nicht aus; vier aufeinanderfolgende 0xCC-Bytes sind erforderlich.
Die Bilder stammen aus KOKURAs DMG-07-Modell. Jede Konsole läuft unabhängig; gesendete und empfangene Werte werden verglichen. Elektrisches Verhalten und Timing physischer Adapter und Kabel sind ungeprüft. CGB-Bilder zeigen Zahlen blau.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Vier-Konsolen-Beispiele starten dieselbe ROM in vier Sitzungen. Ersetzen Sie für DMG-Prüfungen überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[8]=LinkDmg07_GetPhase();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Starten Sie dieselbe ROM auf vier Konsolen; jede sendet 32 plus ihre Spielernummer. Alle empfangen PLAYER 1..4 = 33/34/35/36. Die erste gültige Rundsendung hält SENT SEQ=2 und PACKET SEQ=1 fest und zeigt die Verzögerung um ein Paket. Das Bild friert diese Beobachtung ein; ein Spiel fragt anschließend weiter ab.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Liest, ob Neustartsteuerung fehlt, vorgemerkt ist oder gesendet wird.
Syntax
u8 LinkDmg07_GetRestartState();Rückgabewert
0=keine, 1=Warten auf Grenze, 2=Steuerverkehr wird gesendet.
Bedingungen und Grenzen
Getrennt von der Kommunikationsphase. Null allein belegt keine aufgebaute oder nutzbare Verbindung.
Die Bilder stammen aus KOKURAs DMG-07-Modell. Jede Konsole läuft unabhängig; gesendete und empfangene Werte werden verglichen. Elektrisches Verhalten und Timing physischer Adapter und Kabel sind ungeprüft. CGB-Bilder zeigen Zahlen blau.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Vier-Konsolen-Beispiele starten dieselbe ROM in vier Sitzungen. Ersetzen Sie für DMG-Prüfungen überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[4]=LinkDmg07_GetRestartState();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Spieler 2 fordert Neustart an. Seine Konsole erfasst PENDING=1 und SENT FF=1. Alle vier zeigen DATA VALID=1, RESET PHASE=0, SLOT AFTER=0 und RESET PRIME=0. Der Treiber erhält den laufenden Austausch, bis ihn das Adaptersignal zur Erkennung zurückführt.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Liest die Anzahl der tatsächlich ausgetakteten Anwendungsbytes.
Syntax
u8 LinkDmg07_GetSentSequence();Rückgabewert
Gibt die 8-Bit-Sendesequenz zurück. Zählt den ersten Beitrag, aber keinen Neustartsteuerverkehr.
Bedingungen und Grenzen
Sequenznummern laufen von 255 auf null um. Bei der Bereitstellung des Pakets ist PacketSequence gleich SentSequence minus eins. Spätere Sendestarts erhöhen SentSequence; später abgefragte Werte müssen daher nicht um eins differieren.
Bei SIZE=1 liefert jede Konsole ein Byte; die Vier-Byte-Rundsendung folgt Spielern 1..4. Die erste wird verworfen. Spätere Rundsendungen enthalten die Beiträge des vorigen Pakets. Vier Bytes mit ausschließlich 0xFF sind als Neustartsignal reserviert.
Die Bilder stammen aus KOKURAs DMG-07-Modell. Jede Konsole läuft unabhängig; gesendete und empfangene Werte werden verglichen. Elektrisches Verhalten und Timing physischer Adapter und Kabel sind ungeprüft. CGB-Bilder zeigen Zahlen blau.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Vier-Konsolen-Beispiele starten dieselbe ROM in vier Sitzungen. Ersetzen Sie für DMG-Prüfungen überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[6]=LinkDmg07_GetSentSequence();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Starten Sie dieselbe ROM auf vier Konsolen; jede sendet 32 plus ihre Spielernummer. Alle empfangen PLAYER 1..4 = 33/34/35/36. Die erste gültige Rundsendung hält SENT SEQ=2 und PACKET SEQ=1 fest und zeigt die Verzögerung um ein Paket. Das Bild friert diese Beobachtung ein; ein Spiel fragt anschließend weiter ab.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Liest die seit dem letzten verarbeiteten seriellen Abschluss gezählten Frames.
Syntax
u8 LinkDmg07_GetSilenceFrames();Rückgabewert
0..255; ein verarbeiteter Abschluss setzt zurück, jeder TickFrame erhöht den Wert.
Bedingungen und Grenzen
Rufen Sie Poll über den ganzen Frame wiederholt und TickFrame genau einmal pro Frame auf. Ein Poll pro VBlank kann den Port zwischen Adapterbytes nicht neu vorbereiten. d_poll im gemeinsamen Header erkennt den Eintritt in LY >= 144 und ruft TickFrame einmal auf. Serialisieren Sie beide Operationen, statt ISR und Hauptschleife konkurrieren zu lassen.
SilenceFrames und Diagnosezähler sättigen bei 255. Init setzt alle zurück; gewöhnliche Protokollneustarts erhalten die Diagnosezähler. ClearError löscht nur den Fehlercode.
Die Bilder stammen aus KOKURAs DMG-07-Modell. Jede Konsole läuft unabhängig; gesendete und empfangene Werte werden verglichen. Elektrisches Verhalten und Timing physischer Adapter und Kabel sind ungeprüft. CGB-Bilder zeigen Zahlen blau.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Vier-Konsolen-Beispiele starten dieselbe ROM in vier Sitzungen. Ersetzen Sie für DMG-Prüfungen überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[6]=LinkDmg07_GetSilenceFrames();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Führen Sie das Beispiel ohne Adapter aus. Erwartet werden PLAYER=0, START ERROR=2, SILENT FRAME=12, TIMEOUTS=1 und ERROR=4. DISCONNECTS bleibt null, weil noch kein Adapter erkannt wurde. Leeres Lesen erhält EMPTY BUFFER=77; ClearError ergibt CLEARED=0.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Liest die Anzahl abgelaufener Ruhe- oder Handshake-Fristen.
Syntax
u8 LinkDmg07_GetTimeoutCount();Rückgabewert
Gibt einen Gesamtwert von 0..255 zurück.
Bedingungen und Grenzen
SilenceFrames und Diagnosezähler sättigen bei 255. Init setzt alle zurück; gewöhnliche Protokollneustarts erhalten die Diagnosezähler. ClearError löscht nur den Fehlercode.
Zählt dieselbe Ruhephase vor Wiederaufnahme nicht in jedem Frame erneut. ClearError erhält diese Unterdrückungsmarkierung und den Gesamtzähler.
Die Bilder stammen aus KOKURAs DMG-07-Modell. Jede Konsole läuft unabhängig; gesendete und empfangene Werte werden verglichen. Elektrisches Verhalten und Timing physischer Adapter und Kabel sind ungeprüft. CGB-Bilder zeigen Zahlen blau.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Vier-Konsolen-Beispiele starten dieselbe ROM in vier Sitzungen. Ersetzen Sie für DMG-Prüfungen überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[7]=LinkDmg07_GetTimeoutCount();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Führen Sie das Beispiel ohne Adapter aus. Erwartet werden PLAYER=0, START ERROR=2, SILENT FRAME=12, TIMEOUTS=1 und ERROR=4. DISCONNECTS bleibt null, weil noch kein Adapter erkannt wurde. Leeres Lesen erhält EMPTY BUFFER=77; ClearError ergibt CLEARED=0.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Prüft auf ein abgeschlossenes ungelesenes Vier-Byte-Datenpaket.
Syntax
u8 LinkDmg07_HasPacket();Rückgabewert
Gibt bei ungelesenen Daten 1 zurück, sonst 0.
Bedingungen und Grenzen
Bei SIZE=1 liefert jede Konsole ein Byte; die Vier-Byte-Rundsendung folgt Spielern 1..4. Die erste wird verworfen. Spätere Rundsendungen enthalten die Beiträge des vorigen Pakets. Vier Bytes mit ausschließlich 0xFF sind als Neustartsignal reserviert.
Das Empfangsfach speichert nur das neueste Paket. Der Abschluss eines weiteren Pakets überschreibt ungelesene Daten, merkt Fehler 6 und erhöht ErrorCount. Der Adapter wartet nicht auf das Auslesen durch die Anwendung.
Die Bilder stammen aus KOKURAs DMG-07-Modell. Jede Konsole läuft unabhängig; gesendete und empfangene Werte werden verglichen. Elektrisches Verhalten und Timing physischer Adapter und Kabel sind ungeprüft. CGB-Bilder zeigen Zahlen blau.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Vier-Konsolen-Beispiele starten dieselbe ROM in vier Sitzungen. Ersetzen Sie für DMG-Prüfungen überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[15]=LinkDmg07_HasPacket();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Starten Sie dieselbe ROM auf vier Konsolen; jede sendet 32 plus ihre Spielernummer. Alle empfangen PLAYER 1..4 = 33/34/35/36. Die erste gültige Rundsendung hält SENT SEQ=2 und PACKET SEQ=1 fest und zeigt die Verzögerung um ein Paket. Das Bild friert diese Beobachtung ein; ein Spiel fragt anschließend weiter ab.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Prüft, ob ein abgeschlossener Vier-Byte-Erkennungsaustausch auf Bestätigung wartet.
Syntax
u8 LinkDmg07_HasPingStatus();Rückgabewert
Gibt bei unverbrauchter Meldung 1 zurück, sonst 0.
Bedingungen und Grenzen
Liest nur ein Flag. Ein Erkennungsaustausch kann trotz abgelehntem Statusbyte fortschreiten. Leiten Sie daraus allein weder vollständig gültige Daten noch abgeschlossenen Start ab. Prüfen Sie auch Slot, Maske und LastError.
Die Bilder stammen aus KOKURAs DMG-07-Modell. Jede Konsole läuft unabhängig; gesendete und empfangene Werte werden verglichen. Elektrisches Verhalten und Timing physischer Adapter und Kabel sind ungeprüft. CGB-Bilder zeigen Zahlen blau.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Vier-Konsolen-Beispiele starten dieselbe ROM in vier Sitzungen. Ersetzen Sie für DMG-Prüfungen überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[4]=LinkDmg07_HasPingStatus();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Starten Sie dieselbe ROM auf vier Konsolen; jede sendet 32 plus ihre Spielernummer. Alle empfangen PLAYER 1..4 = 33/34/35/36. Die erste gültige Rundsendung hält SENT SEQ=2 und PACKET SEQ=1 fest und zeigt die Verzögerung um ein Paket. Das Bild friert diese Beobachtung ein; ein Spiel fragt anschließend weiter ab.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Setzt Erkennung, Empfangsspeicher und Diagnose zurück und bereitet den Empfang von Adaptertakten vor.
Syntax
void __stackcall LinkDmg07_Init(u8 rate);Parameter
rate8-Bit-RATE-Antwort an den Adapter; null wählt den Standardwert 0x10.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Dieser Treiber beansprucht den seriellen Port. Führen Sie gewöhnliches Link oder Link4 nicht gleichzeitig aus; binden Sie link_hwregs_gb.c und link_dmg07.c je einmal ein. Der Adapter liefert externe Takte; der Treiber wählt nicht den schnellen CGB-Seriellmodus.
Die Bibliothek nummeriert Spieler 1..4; null bedeutet noch nicht erkannt. Verbindungsbits 0..3 entsprechen Spielern 1..4. Die Slotwerte von KOKURA --link-session sind 0..3, eine von der ROM-API getrennte Nummerierung.
Setzt SC auf 0x80 und SB auf 0x88; löscht nur die seriellen Bits in IE und IF. Andere Interruptfreigabebits und CPU-IME bleiben unverändert.
Die Bilder stammen aus KOKURAs DMG-07-Modell. Jede Konsole läuft unabhängig; gesendete und empfangene Werte werden verglichen. Elektrisches Verhalten und Timing physischer Adapter und Kabel sind ungeprüft. CGB-Bilder zeigen Zahlen blau.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Vier-Konsolen-Beispiele starten dieselbe ROM in vier Sitzungen. Ersetzen Sie für DMG-Prüfungen überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
LinkDmg07_Init(0);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Starten Sie dieselbe ROM auf vier Konsolen; jede sendet 32 plus ihre Spielernummer. Alle empfangen PLAYER 1..4 = 33/34/35/36. Die erste gültige Rundsendung hält SENT SEQ=2 und PACKET SEQ=1 fest und zeigt die Verzögerung um ein Paket. Das Bild friert diese Beobachtung ein; ein Spiel fragt anschließend weiter ab.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Prüft, ob die anfängliche undefinierte Rundsendung verworfen wurde.
Syntax
u8 LinkDmg07_IsPipelinePrimed();Rückgabewert
Gibt nach der ersten Rundsendung 1 zurück; Initialisierung, Erkennungsreset und Startbestätigung löschen den Wert.
Bedingungen und Grenzen
Bei SIZE=1 liefert jede Konsole ein Byte; die Vier-Byte-Rundsendung folgt Spielern 1..4. Die erste wird verworfen. Spätere Rundsendungen enthalten die Beiträge des vorigen Pakets. Vier Bytes mit ausschließlich 0xFF sind als Neustartsignal reserviert.
Eine vorbereitete Pipeline enthält nicht zwingend ein vollständiges Paket. Prüfen Sie die Lesebereitschaft mit HasPacket.
Die Bilder stammen aus KOKURAs DMG-07-Modell. Jede Konsole läuft unabhängig; gesendete und empfangene Werte werden verglichen. Elektrisches Verhalten und Timing physischer Adapter und Kabel sind ungeprüft. CGB-Bilder zeigen Zahlen blau.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Vier-Konsolen-Beispiele starten dieselbe ROM in vier Sitzungen. Ersetzen Sie für DMG-Prüfungen überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[9]=LinkDmg07_IsPipelinePrimed();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Starten Sie dieselbe ROM auf vier Konsolen; jede sendet 32 plus ihre Spielernummer. Alle empfangen PLAYER 1..4 = 33/34/35/36. Die erste gültige Rundsendung hält SENT SEQ=2 und PACKET SEQ=1 fest und zeigt die Verzögerung um ein Paket. Das Bild friert diese Beobachtung ein; ein Spiel fragt anschließend weiter ab.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Liest den zuletzt gespeicherten Fehlercode.
Syntax
u8 LinkDmg07_LastError();Rückgabewert
Gibt einen Fehlercode von 0..6 zurück.
Bedingungen und Grenzen
Fehlercodes: 0=kein Fehler, 1=falsche Phase, 2=nicht Spieler 1, 3=nicht bereit, 4=Zeitüberschreitung, 5=Protokollfehler, 6=ungelesenes Paket überschrieben. Anforderungen sind mit null erfolgreich, Empfang/Pop mit eins. Eine erfolgreiche Anforderung löscht keinen früheren Fehler.
Lesen löscht den Wert nicht. Gespeichert wird nur der neueste Code, kein Fehlerverlauf.
Die Bilder stammen aus KOKURAs DMG-07-Modell. Jede Konsole läuft unabhängig; gesendete und empfangene Werte werden verglichen. Elektrisches Verhalten und Timing physischer Adapter und Kabel sind ungeprüft. CGB-Bilder zeigen Zahlen blau.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Vier-Konsolen-Beispiele starten dieselbe ROM in vier Sitzungen. Ersetzen Sie für DMG-Prüfungen überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[9]=LinkDmg07_LastError();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Führen Sie das Beispiel ohne Adapter aus. Erwartet werden PLAYER=0, START ERROR=2, SILENT FRAME=12, TIMEOUTS=1 und ERROR=4. DISCONNECTS bleibt null, weil noch kein Adapter erkannt wurde. Leeres Lesen erhält EMPTY BUFFER=77; ClearError ergibt CLEARED=0.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Verarbeitet ein abgeschlossenes serielles Byte in der aktuellen Phase und bereitet sofort die nächste Antwort vor.
Syntax
void LinkDmg07_Poll();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Dieser Treiber beansprucht den seriellen Port. Führen Sie gewöhnliches Link oder Link4 nicht gleichzeitig aus; binden Sie link_hwregs_gb.c und link_dmg07.c je einmal ein. Der Adapter liefert externe Takte; der Treiber wählt nicht den schnellen CGB-Seriellmodus.
Rufen Sie Poll über den ganzen Frame wiederholt und TickFrame genau einmal pro Frame auf. Ein Poll pro VBlank kann den Port zwischen Adapterbytes nicht neu vorbereiten. d_poll im gemeinsamen Header erkennt den Eintritt in LY >= 144 und ruft TickFrame einmal auf. Serialisieren Sie beide Operationen, statt ISR und Hauptschleife konkurrieren zu lassen.
Tut nichts bei gesetztem SC-Startbit. Die Verarbeitung eines Abschlusses setzt SilenceFrames und die gespeicherte Timeout-Markierung zurück. Initialisieren Sie vor dem Abfragen.
Die Bilder stammen aus KOKURAs DMG-07-Modell. Jede Konsole läuft unabhängig; gesendete und empfangene Werte werden verglichen. Elektrisches Verhalten und Timing physischer Adapter und Kabel sind ungeprüft. CGB-Bilder zeigen Zahlen blau.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Vier-Konsolen-Beispiele starten dieselbe ROM in vier Sitzungen. Ersetzen Sie für DMG-Prüfungen überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
void d_poll(){LinkDmg07_Poll();if(D_LY>=144){if(d_vblank==0){d_vblank=1;LinkDmg07_TickFrame();}}else d_vblank=0;}Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Starten Sie dieselbe ROM auf vier Konsolen; jede sendet 32 plus ihre Spielernummer. Alle empfangen PLAYER 1..4 = 33/34/35/36. Die erste gültige Rundsendung hält SENT SEQ=2 und PACKET SEQ=1 fest und zeigt die Verzögerung um ein Paket. Das Bild friert diese Beobachtung ein; ein Spiel fragt anschließend weiter ab.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Kopiert das zuletzt abgeschlossene Paket und löscht dessen Ungelesen-Flag.
Syntax
u8 __stackcall LinkDmg07_ReadPacket(u8 *dst);Parameter
dstVier beschreibbare Bytes; null verwirft das Paket.
Rückgabewert
Gibt bei Verbrauch 1 zurück, bei Leere 0. Leeres Lesen lässt dst unverändert.
Bedingungen und Grenzen
Bei SIZE=1 liefert jede Konsole ein Byte; die Vier-Byte-Rundsendung folgt Spielern 1..4. Die erste wird verworfen. Spätere Rundsendungen enthalten die Beiträge des vorigen Pakets. Vier Bytes mit ausschließlich 0xFF sind als Neustartsignal reserviert.
Das Empfangsfach speichert nur das neueste Paket. Der Abschluss eines weiteren Pakets überschreibt ungelesene Daten, merkt Fehler 6 und erhöht ErrorCount. Der Adapter wartet nicht auf das Auslesen durch die Anwendung.
Gespeicherte Bytes bleiben nach dem Verbrauch über GetPacketSlot verfügbar. Ein leeres ReadPacket kopiert sie nicht erneut.
Die Bilder stammen aus KOKURAs DMG-07-Modell. Jede Konsole läuft unabhängig; gesendete und empfangene Werte werden verglichen. Elektrisches Verhalten und Timing physischer Adapter und Kabel sind ungeprüft. CGB-Bilder zeigen Zahlen blau.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Vier-Konsolen-Beispiele starten dieselbe ROM in vier Sitzungen. Ersetzen Sie für DMG-Prüfungen überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[10]=LinkDmg07_ReadPacket(packet);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Starten Sie dieselbe ROM auf vier Konsolen; jede sendet 32 plus ihre Spielernummer. Alle empfangen PLAYER 1..4 = 33/34/35/36. Die erste gültige Rundsendung hält SENT SEQ=2 und PACKET SEQ=1 fest und zeigt die Verzögerung um ein Paket. Das Bild friert diese Beobachtung ein; ein Spiel fragt anschließend weiter ab.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Plant Neustartsteuerverkehr ab einer Transferpaketgrenze ein.
Syntax
u8 LinkDmg07_RequestRestart();Rückgabewert
Gibt in TRANSFER 0 zurück, sonst 1. Wiederholte Anforderungen während Vormerkung oder Senden liefern ebenfalls 0.
Bedingungen und Grenzen
Bei SIZE=1 liefert jede Konsole ein Byte; die Vier-Byte-Rundsendung folgt Spielern 1..4. Die erste wird verworfen. Spätere Rundsendungen enthalten die Beiträge des vorigen Pakets. Vier Bytes mit ausschließlich 0xFF sind als Neustartsignal reserviert.
Fehlercodes: 0=kein Fehler, 1=falsche Phase, 2=nicht Spieler 1, 3=nicht bereit, 4=Zeitüberschreitung, 5=Protokollfehler, 6=ungelesenes Paket überschrieben. Anforderungen sind mit null erfolgreich, Empfang/Pop mit eins. Eine erfolgreiche Anforderung löscht keinen früheren Fehler.
Jeder Spieler darf dies anfordern. Erhält die aktuelle Byteposition, sendet ausgerichteten 0xFF-Verkehr und kehrt nach dem vollständigen 0xFF-Signal des Adapters zur Erkennung zurück. Die bloße Anforderung löscht weder lokalen Slot noch Empfangspipeline.
Die Bilder stammen aus KOKURAs DMG-07-Modell. Jede Konsole läuft unabhängig; gesendete und empfangene Werte werden verglichen. Elektrisches Verhalten und Timing physischer Adapter und Kabel sind ungeprüft. CGB-Bilder zeigen Zahlen blau.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Vier-Konsolen-Beispiele starten dieselbe ROM in vier Sitzungen. Ersetzen Sie für DMG-Prüfungen überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[3]=LinkDmg07_RequestRestart();result[4]=LinkDmg07_GetRestartState();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Spieler 2 fordert Neustart an. Seine Konsole erfasst PENDING=1 und SENT FF=1. Alle vier zeigen DATA VALID=1, RESET PHASE=0, SLOT AFTER=0 und RESET PRIME=0. Der Treiber erhält den laufenden Austausch, bis ihn das Adaptersignal zur Erkennung zurückführt.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Plant die Startanforderung des physischen Spielers 1 an der nächsten Erkennungspaketgrenze ein.
Syntax
u8 LinkDmg07_RequestTransmission();Rückgabewert
Gibt bei Einplanung 0 zurück, bei falscher Phase 1, wenn nicht Spieler 1 dann 2 und bei fehlendem lokalem Verbindungsbit 3.
Bedingungen und Grenzen
Die Bibliothek nummeriert Spieler 1..4; null bedeutet noch nicht erkannt. Verbindungsbits 0..3 entsprechen Spielern 1..4. Die Slotwerte von KOKURA --link-session sind 0..3, eine von der ROM-API getrennte Nummerierung.
Fehlercodes: 0=kein Fehler, 1=falsche Phase, 2=nicht Spieler 1, 3=nicht bereit, 4=Zeitüberschreitung, 5=Protokollfehler, 6=ungelesenes Paket überschrieben. Anforderungen sind mit null erfolgreich, Empfang/Pop mit eins. Eine erfolgreiche Anforderung löscht keinen früheren Fehler.
Kann nur in PING eingeplant werden. Wartet nicht selbst auf alle vier Spieler; das Beispiel prüft Maske 15 im Anwendungscode. Die Einplanung ist asynchron: Ausgerichteter 0xAA-Verkehr geht der 0xCC-Bestätigung voraus.
Die Bilder stammen aus KOKURAs DMG-07-Modell. Jede Konsole läuft unabhängig; gesendete und empfangene Werte werden verglichen. Elektrisches Verhalten und Timing physischer Adapter und Kabel sind ungeprüft. CGB-Bilder zeigen Zahlen blau.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Vier-Konsolen-Beispiele starten dieselbe ROM in vier Sitzungen. Ersetzen Sie für DMG-Prüfungen überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
result[5]=LinkDmg07_RequestTransmission();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Starten Sie dieselbe ROM auf vier Konsolen; jede sendet 32 plus ihre Spielernummer. Alle empfangen PLAYER 1..4 = 33/34/35/36. Die erste gültige Rundsendung hält SENT SEQ=2 und PACKET SEQ=1 fest und zeigt die Verzögerung um ein Paket. Das Bild friert diese Beobachtung ein; ein Spiel fragt anschließend weiter ab.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Setzt den Ein-Byte-Anwendungswert für ein künftiges ausgehendes Paket.
Syntax
void __stackcall LinkDmg07_SetLocalByte(u8 value);Parameter
valueZu übermittelnder 8-Bit-Anwendungswert.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Bei SIZE=1 liefert jede Konsole ein Byte; die Vier-Byte-Rundsendung folgt Spielern 1..4. Die erste wird verworfen. Spätere Rundsendungen enthalten die Beiträge des vorigen Pakets. Vier Bytes mit ausschließlich 0xFF sind als Neustartsignal reserviert.
Wird beim Vorbereiten von Paketbyte null übernommen. Ändert kein bereits vorbereitetes SB-Byte. Setzen Sie den ersten Sendewert vor der Startanforderung.
Die Bilder stammen aus KOKURAs DMG-07-Modell. Jede Konsole läuft unabhängig; gesendete und empfangene Werte werden verglichen. Elektrisches Verhalten und Timing physischer Adapter und Kabel sind ungeprüft. CGB-Bilder zeigen Zahlen blau.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Vier-Konsolen-Beispiele starten dieselbe ROM in vier Sitzungen. Ersetzen Sie für DMG-Prüfungen überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
LinkDmg07_SetLocalByte(32+slot);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Starten Sie dieselbe ROM auf vier Konsolen; jede sendet 32 plus ihre Spielernummer. Alle empfangen PLAYER 1..4 = 33/34/35/36. Die erste gültige Rundsendung hält SENT SEQ=2 und PACKET SEQ=1 fest und zeigt die Verzögerung um ein Paket. Das Bild friert diese Beobachtung ein; ein Spiel fragt anschließend weiter ab.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Rückt Ruhe- und Start-/Neustartüberwachung um einen Frame vor und fordert bei Fristablauf Wiederherstellung an.
Syntax
void LinkDmg07_TickFrame();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Rufen Sie Poll über den ganzen Frame wiederholt und TickFrame genau einmal pro Frame auf. Ein Poll pro VBlank kann den Port zwischen Adapterbytes nicht neu vorbereiten. d_poll im gemeinsamen Header erkennt den Eintritt in LY >= 144 und ruft TickFrame einmal auf. Serialisieren Sie beide Operationen, statt ISR und Hauptschleife konkurrieren zu lassen.
SilenceFrames und Diagnosezähler sättigen bei 255. Init setzt alle zurück; gewöhnliche Protokollneustarts erhalten die Diagnosezähler. ClearError löscht nur den Fehlercode.
Die Standardfrist beträgt 12 Aufrufe; definieren Sie vor dem Einbinden LINK_DMG07_TIMEOUT_FRAMES als 1..255 für einen anderen Wert. Eine Ruhephase wird nur einmal gezählt, bis ein weiteres Byte ihre Markierung löscht. Transferwiederherstellung erhält die Byteausrichtung; Wiederherstellung bei Erkennung/Start kehrt zur Erkennung zurück.
Die Bilder stammen aus KOKURAs DMG-07-Modell. Jede Konsole läuft unabhängig; gesendete und empfangene Werte werden verglichen. Elektrisches Verhalten und Timing physischer Adapter und Kabel sind ungeprüft. CGB-Bilder zeigen Zahlen blau.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Vier-Konsolen-Beispiele starten dieselbe ROM in vier Sitzungen. Ersetzen Sie für DMG-Prüfungen überall --cgb=cgb durch --cgb=dmg und --hardware cgb durch --hardware dmg.
Anwendungsbeispiel
void d_poll(){LinkDmg07_Poll();if(D_LY>=144){if(d_vblank==0){d_vblank=1;LinkDmg07_TickFrame();}}else d_vblank=0;}Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Führen Sie das Beispiel ohne Adapter aus. Erwartet werden PLAYER=0, START ERROR=2, SILENT FRAME=12, TIMEOUTS=1 und ERROR=4. DISCONNECTS bleibt null, weil noch kein Adapter erkannt wurde. Leeres Lesen erhält EMPTY BUFFER=77; ClearError ergibt CLEARED=0.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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-Bewegung und Kollisionen
Bietet Boxintegration, AABB-Kontakte und einen optionalen Löser für Oberflächenreaktionen. Körper werden durch Mittelpunkt und halbe Ausdehnungen beschrieben; active=0 schließt einen Arrayplatz aus, inv_mass_q8<=0 macht ihn statisch. KQRect verwendet dagegen linke obere Ecke und Breite/Höhe. Kontakte zwischen Boxen nutzen das restitution-Feld des Körpers nicht; Oberflächenreaktionen verwenden KQSurface2D-Koeffizienten.
Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.
Eine Welt nutzt ein vom aufrufenden Code bereitgestelltes Array. Dieser reserviert und besitzt den Speicher für die Körper und hält ihn gültig. Das Initialisieren der Welt initialisiert nicht die Arrayelemente.
kq2d_body_apply_friction
Skaliert beide Geschwindigkeitskomponenten mit einem vorzeichenbehafteten Bytekoeffizienten geteilt durch 256, ohne Position oder Aktivität zu prüfen.
Syntax
void kq2d_body_apply_friction(KQBody2D* body, u8 friction_q8);Parameter
bodyZeiger auf den zu ändernden Körper. Von dieser Operation nicht verwendete Felder bleiben erhalten.
friction_q8Von dieser Funktion verwendeter Geschwindigkeitsfaktor. Er wird in s8 umgewandelt; dadurch werden 128..255 zu negativen Koeffizienten.
Rückgabewert
Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.
Bedingungen und Grenzen
Werte von 0 bis 127 ergeben Faktoren von 0 bis 127/256. Werte von 128 bis 255 werden durch die s8-Umwandlung negativ und kehren die Geschwindigkeit um. Für nichtnegative Dämpfung über den gesamten Bereich 0..255 verwenden Sie kq2d_scale_q8 für jede Komponente. Produkte werden gegen null abgeschnitten. NULL wird ignoriert.
Anwendungsbeispiel
kq2d_body_apply_friction(&temp,64);
result[11]=temp.vx; result[12]=temp.vy;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Links ist der Anfangszustand zu sehen, rechts der Zustand nach einem Takt. Eine rote 16x16-Box mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden wird ihre Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). Auf dem DMG sind alle Markierungen schwarz. RAM-Prüfungen decken außerdem Initialisierung, Setzfunktionen, Integration, Rechteck-/Punktabfragen und vorzeichenbehaftete Skalierung ab.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Addiert die Schwerkraft zu einem aktiven dynamischen Körper und begrenzt jede Achse auf +/-max_speed, ohne die Position zu ändern.
Syntax
void kq2d_body_apply_gravity(KQBody2D* body, s16 gravity_x, s16 gravity_y, s16 max_speed);Parameter
bodyZeiger auf den zu ändernden Körper. Von dieser Operation nicht verwendete Felder bleiben erhalten.
gravity_xBeschleunigung, die dieser Aufruf zur X-Geschwindigkeit addiert.
gravity_yBeschleunigung, die dieser Aufruf zur Y-Geschwindigkeit addiert.
max_speedGeschwindigkeitsgrenze. Der jeweilige Eintrag erläutert, ob sie für jede Achse einzeln oder den gesamten Vektor gilt.
Rückgabewert
Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.
Bedingungen und Grenzen
Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.
Summen, Differenzen, addierte halbe Ausdehnungen und Produkte zur Kontaktkorrektur müssen im vorzeichenbehafteten 16-Bit-Bereich bleiben. Geschwindigkeitsgrenzen greifen erst nach der Addition und verhindern keinen Überlauf innerhalb dieser Addition.
Integration und Kollisionserkennung für Boxen verwenden gemeinsamen Arbeitsspeicher. Rufen Sie diese Physikroutinen nicht während ihrer Ausführung erneut aus einem Interrupt auf.
Ignoriert NULL, inaktive Körper und Körper mit inverser Masse kleiner oder gleich null. Geben Sie eine nichtnegative Geschwindigkeitsgrenze an.
Anwendungsbeispiel
kq2d_body_apply_gravity(&temp,5,-10,32);
result[9]=temp.vx; result[10]=temp.vy;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Links ist der Anfangszustand zu sehen, rechts der Zustand nach einem Takt. Eine rote 16x16-Box mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden wird ihre Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). Auf dem DMG sind alle Markierungen schwarz. RAM-Prüfungen decken außerdem Initialisierung, Setzfunktionen, Integration, Rechteck-/Punktabfragen und vorzeichenbehaftete Skalierung ab.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Initialisiert eine über ihren Mittelpunkt definierte Box mit den angegebenen halben Ausdehnungen, Geschwindigkeit null, inverser Masse 256 und aktivem Zustand.
Syntax
void kq2d_body_init(KQBody2D* body, s16 x, s16 y, s16 half_x, s16 half_y);Parameter
bodyZeiger auf den zu ändernden Körper. Von dieser Operation nicht verwendete Felder bleiben erhalten.
xX-Koordinate des Mittelpunkts oder Punkts, im Beispiel in Pixeln.
yY-Koordinate des Mittelpunkts oder Punkts; im Beispiel zeigen positive Werte nach unten.
half_xHalbe Ausdehnung entlang X; die gesamte Boxbreite ist doppelt so groß.
half_yHalbe Ausdehnung entlang Y; die gesamte Boxhöhe ist doppelt so groß.
Rückgabewert
Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.
Bedingungen und Grenzen
Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.
Setzt restitution_q8 auf null. Ein NULL-Körper wird ignoriert. Geben Sie positive halbe Ausdehnungen an.
Anwendungsbeispiel
kq2d_body_init(&temp,10,20,8,8);
result[3]=temp.inv_mass_q8; result[4]=temp.active;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Links ist der Anfangszustand zu sehen, rechts der Zustand nach einem Takt. Eine rote 16x16-Box mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden wird ihre Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). Auf dem DMG sind alle Markierungen schwarz. RAM-Prüfungen decken außerdem Initialisierung, Setzfunktionen, Integration, Rechteck-/Punktabfragen und vorzeichenbehaftete Skalierung ab.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Die lokalen Unterschiede dieser API stehen bei den Änderungen und Prüfungen vom 2026-10-03.
Schätzt die Vektorlänge konservativ und skaliert beide Achsen gemeinsam, um die Gesamtgeschwindigkeit zu begrenzen.
Syntax
void kq2d_body_limit_speed(KQBody2D* body, s16 max_speed);Parameter
bodyZeiger auf den zu ändernden Körper. Von dieser Operation nicht verwendete Felder bleiben erhalten.
max_speedGeschwindigkeitsgrenze. Der jeweilige Eintrag erläutert, ob sie für jede Achse einzeln oder den gesamten Vektor gilt.
Rückgabewert
Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.
Bedingungen und Grenzen
Die Beträge der Geschwindigkeitskomponenten und ein positiver max_speed dürfen höchstens 16383 betragen. Eine Grenze kleiner oder gleich null setzt die Geschwindigkeit auf null. NULL wird ignoriert, Aktivität und Masse verhindern die Änderung jedoch nicht. Ganzzahlige Quantisierung kann das Ergebnis unter die Grenze drücken; sehr kleine Faktoren können null ergeben.
Anwendungsbeispiel
kq2d_body_limit_speed(&body,250);
result[2]=body.vx; result[3]=body.vy;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Der rote Körper bleibt an seiner Position. Seine grüne Geschwindigkeitslinie wechselt von (8,16) links zu (2,-8) rechts und zeigt so Rückprall und tangentiale Reibung an der blauen Oberfläche. Die Panelursprünge liegen auf dem Bildschirm bei (8,48)/(88,48), der Körpermittelpunkt innerhalb des Panels bei (24,40). Die Anprallgeschwindigkeit beträgt 16, das Beispiel zum Übertrittszeitpunkt liefert 192/256. Das Beispiel zur Geschwindigkeitsbegrenzung reduziert (300,400) auf (147,196). Auf dem DMG sind alle Markierungen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Die lokalen Unterschiede dieser API stehen bei den Änderungen und Prüfungen vom 2026-10-03.
Nutzt die Geschwindigkeit relativ zu einer bewegten Oberfläche, um normalen Rückprall, eine minimale Rückprallgeschwindigkeit und tangentiale Reibung anzuwenden.
Syntax
s16 kq2d_body_resolve_surface(KQBody2D* body, const KQSurface2D* surface);Parameter
bodyZeiger auf den zu ändernden Körper. Von dieser Operation nicht verwendete Felder bleiben erhalten.
surfaceZeiger auf eine KQSurface2D mit Normale, Geschwindigkeit sowie Rückprall- und Reibungseinstellungen.
Rückgabewert
Liefert die positive Annäherungsgeschwindigkeit entlang der Normalen oder 0 bei NULL-Eingaben oder einer Trennbewegung.
Bedingungen und Grenzen
Verwenden Sie eine Q8-Einheitsnormale mit Länge 256. Relative Komponenten müssen in +/-8191 liegen, threshold/kick nichtnegativ und Koeffizienten in 0..255 sein. Rückprall wird nur bei striktem Überschreiten des Schwellwerts angewendet; kick gibt die minimale Rückprallgeschwindigkeit vor. Bei NULL-Eingaben oder einer Trennbewegung bleibt die Geschwindigkeit unverändert. Kontakterkennung und Eindringkorrektur erfolgen separat; Aktivität und Masse werden nicht geprüft.
Anwendungsbeispiel
result[6]=kq2d_body_resolve_surface(&body,&surface);
result[7]=body.vx; result[8]=body.vy; result[9]=body.y;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Der rote Körper bleibt an seiner Position. Seine grüne Geschwindigkeitslinie wechselt von (8,16) links zu (2,-8) rechts und zeigt so Rückprall und tangentiale Reibung an der blauen Oberfläche. Die Panelursprünge liegen auf dem Bildschirm bei (8,48)/(88,48), der Körpermittelpunkt innerhalb des Panels bei (24,40). Die Anprallgeschwindigkeit beträgt 16, das Beispiel zum Übertrittszeitpunkt liefert 192/256. Das Beispiel zur Geschwindigkeitsbegrenzung reduziert (300,400) auf (147,196). Auf dem DMG sind alle Markierungen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Ersetzt nur den Körpermittelpunkt; Geschwindigkeit, Ausdehnungen und Aktivitätszustand bleiben erhalten.
Syntax
void kq2d_body_set_pos(KQBody2D* body, s16 x, s16 y);Parameter
bodyZeiger auf den zu ändernden Körper. Von dieser Operation nicht verwendete Felder bleiben erhalten.
xX-Koordinate des Mittelpunkts oder Punkts, im Beispiel in Pixeln.
yY-Koordinate des Mittelpunkts oder Punkts; im Beispiel zeigen positive Werte nach unten.
Rückgabewert
Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.
Bedingungen und Grenzen
Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.
NULL wird ignoriert. Bei gültigem Zeiger werden auch inaktive und statische Körper geändert.
Anwendungsbeispiel
kq2d_body_set_pos(&temp,-12,20);
result[5]=temp.x; result[6]=temp.y;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Links ist der Anfangszustand zu sehen, rechts der Zustand nach einem Takt. Eine rote 16x16-Box mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden wird ihre Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). Auf dem DMG sind alle Markierungen schwarz. RAM-Prüfungen decken außerdem Initialisierung, Setzfunktionen, Integration, Rechteck-/Punktabfragen und vorzeichenbehaftete Skalierung ab.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Setzt die Geschwindigkeit direkt, ohne sie zu begrenzen oder die Position zu ändern.
Syntax
void kq2d_body_set_velocity(KQBody2D* body, s16 vx, s16 vy);Parameter
bodyZeiger auf den zu ändernden Körper. Von dieser Operation nicht verwendete Felder bleiben erhalten.
vxX-Verschiebung pro Simulationstakt, in derselben Einheit wie die Position.
vyY-Verschiebung pro Simulationstakt, in derselben Einheit wie die Position.
Rückgabewert
Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.
Bedingungen und Grenzen
Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.
NULL wird ignoriert. Bei gültigem Zeiger werden auch inaktive und statische Körper geändert.
Anwendungsbeispiel
kq2d_body_set_velocity(&temp,40,-30);
result[7]=temp.vx; result[8]=temp.vy;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Links ist der Anfangszustand zu sehen, rechts der Zustand nach einem Takt. Eine rote 16x16-Box mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden wird ihre Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). Auf dem DMG sind alle Markierungen schwarz. RAM-Prüfungen decken außerdem Initialisierung, Setzfunktionen, Integration, Rechteck-/Punktabfragen und vorzeichenbehaftete Skalierung ab.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Wendet Weltschwerkraft und Geschwindigkeitsgrenzen pro Achse auf einen dynamischen Körper an und addiert anschließend die Geschwindigkeit zur Position.
Syntax
void kq2d_integrate_body(KQWorld2D* world, KQBody2D* body);Parameter
worldZeiger auf die Welt mit dem Körperarray und den Simulationseinstellungen.
bodyZeiger auf den zu ändernden Körper. Von dieser Operation nicht verwendete Felder bleiben erhalten.
Rückgabewert
Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.
Bedingungen und Grenzen
Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.
Summen, Differenzen, addierte halbe Ausdehnungen und Produkte zur Kontaktkorrektur müssen im vorzeichenbehafteten 16-Bit-Bereich bleiben. Geschwindigkeitsgrenzen greifen erst nach der Addition und verhindern keinen Überlauf innerhalb dieser Addition.
Integration und Kollisionserkennung für Boxen verwenden gemeinsamen Arbeitsspeicher. Rufen Sie diese Physikroutinen nicht während ihrer Ausführung erneut aus einem Interrupt auf.
Ignoriert NULL, inaktive Körper und Körper mit inverser Masse kleiner oder gleich null. Geben Sie eine nichtnegative Geschwindigkeitsgrenze an.
Dieser Aufruf löst keine Kontakte mit anderen Körpern auf. Auch eine NULL-Welt wird ignoriert.
Anwendungsbeispiel
kq2d_integrate_body(&world,&temp);
result[18]=temp.x; result[19]=temp.y;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Links ist der Anfangszustand zu sehen, rechts der Zustand nach einem Takt. Eine rote 16x16-Box mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden wird ihre Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). Auf dem DMG sind alle Markierungen schwarz. RAM-Prüfungen decken außerdem Initialisierung, Setzfunktionen, Integration, Rechteck-/Punktabfragen und vorzeichenbehaftete Skalierung ab.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Prüft zwei über ihren Mittelpunkt definierte Boxen auf echte Überlappung entlang X und Y.
Syntax
u8 kq2d_overlap_aabb(const KQBody2D* a, const KQBody2D* b);Parameter
aGültiger Körperzeiger. Die Abfrage ignoriert Aktivität, Masse und Flags.
bGültiger Körperzeiger. Die Abfrage ignoriert Aktivität, Masse und Flags.
Rückgabewert
Liefert 1 bei Überlappung der Innenbereiche und 0 bei bloßer Berührung oder getrennten Formen.
Bedingungen und Grenzen
Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.
Summen, Differenzen, addierte halbe Ausdehnungen und Produkte zur Kontaktkorrektur müssen im vorzeichenbehafteten 16-Bit-Bereich bleiben. Geschwindigkeitsgrenzen greifen erst nach der Addition und verhindern keinen Überlauf innerhalb dieser Addition.
Anwendungsbeispiel
result[20]=kq2d_overlap_aabb(&bodies[0],&bodies[1]);
bodies[1].x=40; result[21]=kq2d_overlap_aabb(&bodies[0],&bodies[1]);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Links ist der Anfangszustand zu sehen, rechts der Zustand nach einem Takt. Eine rote 16x16-Box mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden wird ihre Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). Auf dem DMG sind alle Markierungen schwarz. RAM-Prüfungen decken außerdem Initialisierung, Setzfunktionen, Integration, Rechteck-/Punktabfragen und vorzeichenbehaftete Skalierung ab.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Prüft, ob ein Punkt im Rechteck liegt. Linker und oberer Rand zählen dazu, rechter und unterer Rand nicht.
Syntax
u8 kq2d_point_in_rect(s16 x, s16 y, KQRect r);Parameter
xX-Koordinate des Mittelpunkts oder Punkts, im Beispiel in Pixeln.
yY-Koordinate des Mittelpunkts oder Punkts; im Beispiel zeigen positive Werte nach unten.
rKQRect-Wert mit der Position x/y der linken oberen Ecke und Breite/Höhe w/h.
Rückgabewert
Gibt innen 1 und außen 0 zurück.
Bedingungen und Grenzen
Summen, Differenzen, addierte halbe Ausdehnungen und Produkte zur Kontaktkorrektur müssen im vorzeichenbehafteten 16-Bit-Bereich bleiben. Geschwindigkeitsgrenzen greifen erst nach der Addition und verhindern keinen Überlauf innerhalb dieser Addition.
Anwendungsbeispiel
result[16]=kq2d_point_in_rect(0,0,r1);
result[17]=kq2d_point_in_rect(16,0,r1);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Links ist der Anfangszustand zu sehen, rechts der Zustand nach einem Takt. Eine rote 16x16-Box mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden wird ihre Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). Auf dem DMG sind alle Markierungen schwarz. RAM-Prüfungen decken außerdem Initialisierung, Setzfunktionen, Integration, Rechteck-/Punktabfragen und vorzeichenbehaftete Skalierung ab.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Prüft die Innenbereiche zweier Rechtecke auf Überlappung. Die Rechtecke werden durch linke obere Ecke und Größe angegeben.
Syntax
u8 kq2d_rect_intersect(KQRect a, KQRect b);Parameter
aKQRect-Wert mit den Koordinaten der linken oberen Ecke sowie positiver Breite und Höhe.
bKQRect-Wert mit den Koordinaten der linken oberen Ecke sowie positiver Breite und Höhe.
Rückgabewert
Liefert 1 bei Überlappung der Innenbereiche und 0 bei bloßer Berührung oder getrennten Formen.
Bedingungen und Grenzen
Summen, Differenzen, addierte halbe Ausdehnungen und Produkte zur Kontaktkorrektur müssen im vorzeichenbehafteten 16-Bit-Bereich bleiben. Geschwindigkeitsgrenzen greifen erst nach der Addition und verhindern keinen Überlauf innerhalb dieser Addition.
Abmessungen kleiner oder gleich null werden nicht ausdrücklich abgelehnt. Kopieren Sie Mittelpunkt und halbe Ausdehnungen eines Körpers nicht direkt in ein KQRect.
Anwendungsbeispiel
result[14]=kq2d_rect_intersect(r1,r2);
r2.x=16; result[15]=kq2d_rect_intersect(r1,r2);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Links ist der Anfangszustand zu sehen, rechts der Zustand nach einem Takt. Eine rote 16x16-Box mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden wird ihre Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). Auf dem DMG sind alle Markierungen schwarz. RAM-Prüfungen decken außerdem Initialisierung, Setzfunktionen, Integration, Rechteck-/Punktabfragen und vorzeichenbehaftete Skalierung ab.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Die lokalen Unterschiede dieser API stehen bei den Änderungen und Prüfungen vom 2026-10-03.
Multipliziert mit einem vorzeichenbehafteten Koeffizienten geteilt durch 256 und schneidet bei beiden Vorzeichen gegen null ab.
Syntax
s16 kq2d_scale_q8(s16 value, s16 coefficient);Parameter
valueVorzeichenbehafteter 16-Bit-Wert, auf den der Skalierungsfaktor angewendet wird.
coefficientVorzeichenbehafteter Koeffizient von -256 bis 256; 256 steht für 1,0.
Rückgabewert
Liefert das gegen null abgeschnittene Ergebnis als vorzeichenbehafteten 16-Bit-Wert.
Bedingungen und Grenzen
Verwenden Sie nur Koeffizienten in -256..256; +/-256 entspricht +/-1. Für value=-32768 und coefficient=-256 lautet das mathematische Ergebnis 32768 und passt nicht in s16.
Anwendungsbeispiel
result[0]=kq2d_scale_q8(-257,128);
result[1]=kq2d_scale_q8(300,-256);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Der rote Körper bleibt an seiner Position. Seine grüne Geschwindigkeitslinie wechselt von (8,16) links zu (2,-8) rechts und zeigt so Rückprall und tangentiale Reibung an der blauen Oberfläche. Die Panelursprünge liegen auf dem Bildschirm bei (8,48)/(88,48), der Körpermittelpunkt innerhalb des Panels bei (24,40). Die Anprallgeschwindigkeit beträgt 16, das Beispiel zum Übertrittszeitpunkt liefert 192/256. Das Beispiel zur Geschwindigkeitsbegrenzung reduziert (300,400) auf (147,196). Auf dem DMG sind alle Markierungen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Integriert aktive dynamische Körper und löst anschließend Kontakte zwischen aktiven Arrayeinträgen auf.
Syntax
void kq2d_step(KQWorld2D* world);Parameter
worldZeiger auf die Welt mit dem Körperarray und den Simulationseinstellungen.
Rückgabewert
Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.
Bedingungen und Grenzen
Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.
Eine Welt nutzt ein vom aufrufenden Code bereitgestelltes Array. Dieser reserviert und besitzt den Speicher für die Körper und hält ihn gültig. Das Initialisieren der Welt initialisiert nicht die Arrayelemente.
Summen, Differenzen, addierte halbe Ausdehnungen und Produkte zur Kontaktkorrektur müssen im vorzeichenbehafteten 16-Bit-Bereich bleiben. Geschwindigkeitsgrenzen greifen erst nach der Addition und verhindern keinen Überlauf innerhalb dieser Addition.
Kontakte werden entlang der Achse mit der geringsten Eindringtiefe aufgelöst; bei Gleichstand wird Y gewählt. Die Positionskorrektur nutzt inverse Massen, zwei dynamische Körper erhalten auf dieser Achse jedoch den einfachen Mittelwert ihrer Geschwindigkeiten. Bei einer Kollision mit einem statischen Körper wird die Komponente null. Der Löser nutzt restitution_q8 nicht. Die diskrete Kollisionserkennung kann schnelle Durchquerungen übersehen.
Integration und Kollisionserkennung für Boxen verwenden gemeinsamen Arbeitsspeicher. Rufen Sie diese Physikroutinen nicht während ihrer Ausführung erneut aus einem Interrupt auf.
Eine NULL-Welt oder ein NULL-Array wird ignoriert. Auch bei solver_iterations gleich null wird ein Kontaktdurchlauf ausgeführt.
Anwendungsbeispiel
kq2d_step(&world);
result[22]=bodies[0].x; result[23]=bodies[0].y;
result[24]=bodies[0].vx; result[25]=bodies[0].vy;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Links ist der Anfangszustand zu sehen, rechts der Zustand nach einem Takt. Eine rote 16x16-Box mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden wird ihre Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). Auf dem DMG sind alle Markierungen schwarz. RAM-Prüfungen decken außerdem Initialisierung, Setzfunktionen, Integration, Rechteck-/Punktabfragen und vorzeichenbehaftete Skalierung ab.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Schätzt bei linearer Bewegung den Übertrittszeitpunkt innerhalb des Takts anhand der vorzeichenbehafteten Start- und Endabstände.
Syntax
u16 kq2d_surface_toi_q8(s16 start_gap, s16 end_gap);Parameter
start_gapVorzeichenbehafteter Abstand zu Beginn des Takts; positiv bedeutet außerhalb der Oberfläche.
end_gapVorzeichenbehafteter Abstand am Ende des Takts; negativ bedeutet, dass die Oberfläche überschritten wurde.
Rückgabewert
Liefert einen Q8-Zeitpunkt in 0..256; 192 entspricht 75 % des Takts.
Bedingungen und Grenzen
Halten Sie Abstände innerhalb von +/-8191. Ein Startwert kleiner oder gleich null liefert 0; ein Endwert größer oder gleich null liefert 256. Anfangsüberlappung und Zeitpunkt null haben denselben Rückgabewert. Ebenso teilen sich fehlender Übertritt und Kontakt genau am Endpunkt einen Rückgabewert. Positionen werden nicht geändert.
Anwendungsbeispiel
result[4]=kq2d_surface_toi_q8(6,-2);
result[5]=kq2d_surface_toi_q8(6,0);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Der rote Körper bleibt an seiner Position. Seine grüne Geschwindigkeitslinie wechselt von (8,16) links zu (2,-8) rechts und zeigt so Rückprall und tangentiale Reibung an der blauen Oberfläche. Die Panelursprünge liegen auf dem Bildschirm bei (8,48)/(88,48), der Körpermittelpunkt innerhalb des Panels bei (24,40). Die Anprallgeschwindigkeit beträgt 16, das Beispiel zum Übertrittszeitpunkt liefert 192/256. Das Beispiel zur Geschwindigkeitsbegrenzung reduziert (300,400) auf (147,196). Auf dem DMG sind alle Markierungen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Verknüpft ein Array mit einer 2D-Welt und setzt die Schwerkraft auf (0,32), die Kontaktiterationen auf vier und die Geschwindigkeitsgrenze pro Achse auf 512.
Syntax
void kq2d_world_init(KQWorld2D* world, KQBody2D* bodies, u8 body_count);Parameter
worldZeiger auf die Welt mit dem Körperarray und den Simulationseinstellungen.
bodiesAnfang eines vom aufrufenden Code gehaltenen Körperarrays mit body_count Elementen.
body_countAnzahl der Arrayplätze von 0 bis 255, einschließlich inaktiver Einträge.
Rückgabewert
Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.
Bedingungen und Grenzen
Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.
Eine Welt nutzt ein vom aufrufenden Code bereitgestelltes Array. Dieser reserviert und besitzt den Speicher für die Körper und hält ihn gültig. Das Initialisieren der Welt initialisiert nicht die Arrayelemente.
Anwendungsbeispiel
kq2d_world_init(&world,bodies,2);
result[0]=world.gravity_y; result[1]=world.solver_iterations; result[2]=world.max_speed;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Links ist der Anfangszustand zu sehen, rechts der Zustand nach einem Takt. Eine rote 16x16-Box mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden wird ihre Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). Auf dem DMG sind alle Markierungen schwarz. RAM-Prüfungen decken außerdem Initialisierung, Setzfunktionen, Integration, Rechteck-/Punktabfragen und vorzeichenbehaftete Skalierung ab.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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 — Kreisphysik
Unterstützt Kreisradius, inverse Masse, Rückprall, tangentiale Reibung, Weltdämpfung und Grenzen. Der aufrufende Code initialisiert alle Körperfelder. friction_q8 des Körpers und wall_friction_q8 beschreiben den entfernten Anteil tangentialer Bewegung, linear_damping_q8 dagegen den beibehaltenen Geschwindigkeitsanteil. Bytekoeffizienten werden durch 256 geteilt; 255 ist daher nicht genau 1,0.
Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.
Abstände und Normalen bei Kreisen sind ganzzahlige Näherungen. Auch wenn jede Komponente höchstens 255 beträgt, muss die Summe ihrer Quadrate nicht in 65535 passen. Mittelpunktsdifferenzen, Radiensummen und Summen inverser Massen müssen darstellbar bleiben. Beim Berechnen der Gewichte darf inv_mass_q8 * 255 höchstens 32767 betragen; das Beispiel verwendet 64.
kq2dc_overlap_circle
Nähert die Überlappung der Innenbereiche anhand des reduzierten Mittelpunktabstands und der Radiensumme an.
Syntax
u8 kq2dc_overlap_circle(const KQCircleBody2D* a, const KQCircleBody2D* b);Parameter
aGültiger Zeiger auf den ersten Kreis.
bGültiger Zeiger auf den zweiten Kreis.
Rückgabewert
Liefert 1 bei Überlappung der Innenbereiche und 0 bei bloßer Berührung oder getrennten Formen.
Bedingungen und Grenzen
Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.
Abstände und Normalen bei Kreisen sind ganzzahlige Näherungen. Auch wenn jede Komponente höchstens 255 beträgt, muss die Summe ihrer Quadrate nicht in 65535 passen. Mittelpunktsdifferenzen, Radiensummen und Summen inverser Massen müssen darstellbar bleiben. Beim Berechnen der Gewichte darf inv_mass_q8 * 255 höchstens 32767 betragen; das Beispiel verwendet 64.
Benötigt zwei gültige Zeiger und positive Radien. Aktivität und Masse werden ignoriert. Reduktion und ganzzahlige Quadratwurzeln können zu Abweichungen von einem exakten geometrischen Abstandstest führen.
Anwendungsbeispiel
result[4]=kq2dc_overlap_circle(&balls[0],&balls[1]);
balls[1].x=18; result[5]=kq2dc_overlap_circle(&balls[0],&balls[1]);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Ein roter Kreis mit Radius 6 bewegt sich vom Mittelpunkt (24,24) links nach (54,24) rechts. Die lokalen Grenzen sind (4,4)..(60,60). Die rechte Wand begrenzt den Mittelpunkt auf 54 und ändert die X-Geschwindigkeit von 32 auf -15: Auf den Wandrückprall mit 128/256 folgt eine Dämpfung mit 255/256. Die Panelursprünge liegen bei (8,48)/(88,48) auf dem Bildschirm. Auf dem DMG werden Kreis und Begrenzung schwarz dargestellt.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Speichert und aktiviert die Grenzen der Kreiswelt, ohne Körper sofort zu verschieben.
Syntax
void kq2dc_set_bounds(KQCircleWorld2D* world, s16 min_x, s16 min_y, s16 max_x, s16 max_y);Parameter
worldZeiger auf die Welt mit dem Körperarray und den Simulationseinstellungen.
min_xLinke Grenze; der Kreismittelpunkt wird auf mindestens min_x + radius begrenzt.
min_yObere Grenze; der Kreismittelpunkt wird auf mindestens min_y + radius begrenzt.
max_xRechte Grenze; der Kreismittelpunkt wird auf höchstens max_x - radius begrenzt.
max_yUntere Grenze; der Kreismittelpunkt wird auf höchstens max_y - radius begrenzt.
Rückgabewert
Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.
Bedingungen und Grenzen
Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.
NULL wird ignoriert. Reihenfolge der Grenzen und ausreichender Platz werden nicht geprüft; Breite und Höhe müssen mindestens dem Kreisdurchmesser entsprechen. Die eigentliche Positionskorrektur erfolgt in einem Simulationsschritt.
Anwendungsbeispiel
kq2dc_set_bounds(&world,4,4,60,60);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Ein roter Kreis mit Radius 6 bewegt sich vom Mittelpunkt (24,24) links nach (54,24) rechts. Die lokalen Grenzen sind (4,4)..(60,60). Die rechte Wand begrenzt den Mittelpunkt auf 54 und ändert die X-Geschwindigkeit von 32 auf -15: Auf den Wandrückprall mit 128/256 folgt eine Dämpfung mit 255/256. Die Panelursprünge liegen bei (8,48)/(88,48) auf dem Bildschirm. Auf dem DMG werden Kreis und Begrenzung schwarz dargestellt.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Integriert Kreise, behandelt Grenzen und Kreiskontakte und wendet anschließend lineare Dämpfung an.
Syntax
void kq2dc_step(KQCircleWorld2D* world);Parameter
worldZeiger auf die Welt mit dem Körperarray und den Simulationseinstellungen.
Rückgabewert
Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.
Bedingungen und Grenzen
Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.
Eine Welt nutzt ein vom aufrufenden Code bereitgestelltes Array. Dieser reserviert und besitzt den Speicher für die Körper und hält ihn gültig. Das Initialisieren der Welt initialisiert nicht die Arrayelemente.
Abstände und Normalen bei Kreisen sind ganzzahlige Näherungen. Auch wenn jede Komponente höchstens 255 beträgt, muss die Summe ihrer Quadrate nicht in 65535 passen. Mittelpunktsdifferenzen, Radiensummen und Summen inverser Massen müssen darstellbar bleiben. Beim Berechnen der Gewichte darf inv_mass_q8 * 255 höchstens 32767 betragen; das Beispiel verwendet 64.
Setzt abschließend Geschwindigkeitskomponenten in -1..1 auf null. Selbst Dämpfung 255 verringert die Geschwindigkeit etwas. Überlappungen ruhender Kreise können bestehen bleiben. Auch statische Kreise werden in aktivierte Grenzen verschoben. Null Iterationen bedeutet einen Durchlauf; NULL-Welt oder -Array wird ignoriert. Dieser diskrete, quantisierte Löser kann Kontakte bei veränderten Geschwindigkeiten in anderer Reihenfolge bearbeiten.
Anwendungsbeispiel
kq2dc_step(&world);
result[6]=balls[0].x; result[7]=balls[0].y; result[8]=balls[0].vx;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Ein roter Kreis mit Radius 6 bewegt sich vom Mittelpunkt (24,24) links nach (54,24) rechts. Die lokalen Grenzen sind (4,4)..(60,60). Die rechte Wand begrenzt den Mittelpunkt auf 54 und ändert die X-Geschwindigkeit von 32 auf -15: Auf den Wandrückprall mit 128/256 folgt eine Dämpfung mit 255/256. Die Panelursprünge liegen bei (8,48)/(88,48) auf dem Bildschirm. Auf dem DMG werden Kreis und Begrenzung schwarz dargestellt.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Verknüpft ein Kreisarray und setzt Schwerkraft null, vier Durchläufe, eine Geschwindigkeitsgrenze von 768 pro Achse und Dämpfung 252/256.
Syntax
void kq2dc_world_init(KQCircleWorld2D* world, KQCircleBody2D* bodies, u8 body_count);Parameter
worldZeiger auf die Welt mit dem Körperarray und den Simulationseinstellungen.
bodiesAnfang eines vom aufrufenden Code gehaltenen Körperarrays mit body_count Elementen.
body_countAnzahl der Arrayplätze von 0 bis 255, einschließlich inaktiver Einträge.
Rückgabewert
Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.
Bedingungen und Grenzen
Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.
Eine Welt nutzt ein vom aufrufenden Code bereitgestelltes Array. Dieser reserviert und besitzt den Speicher für die Körper und hält ihn gültig. Das Initialisieren der Welt initialisiert nicht die Arrayelemente.
Die Grenzen sind anfangs deaktiviert und auf (0,0)..(159,143) gesetzt; Wandrückprall beträgt 240, Wandreibung 16. Eine Initialisierungsfunktion für Kreiskörper gibt es nicht: Der aufrufende Code muss alle Körperfelder setzen. Eine NULL-Welt wird ignoriert.
Anwendungsbeispiel
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;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Ein roter Kreis mit Radius 6 bewegt sich vom Mittelpunkt (24,24) links nach (54,24) rechts. Die lokalen Grenzen sind (4,4)..(60,60). Die rechte Wand begrenzt den Mittelpunkt auf 54 und ändert die X-Geschwindigkeit von 32 auf -15: Auf den Wandrückprall mit 128/256 folgt eine Dämpfung mit 255/256. Die Panelursprünge liegen bei (8,48)/(88,48) auf dem Bildschirm. Auf dem DMG werden Kreis und Begrenzung schwarz dargestellt.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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 — Physik für achsenparallele 3D-Quader
Physik für nicht rotierende 3D-Boxen, beschrieben durch Mittelpunkt und halbe Ausdehnung je Achse. Masse und inverse Masse gewichten Kontakte, restitution_q8 steuert den Rückprall und ax/ay/az liefern eine dauerhafte Beschleunigung. Die Darstellung erfolgt separat. Das Beispiel zeichnet Vorder- und Draufsicht desselben Körpers, um Tiefenbewegung und Wandrückprall zu zeigen.
Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.
physics3d.c liegt in ROM-Bank 2. Das Beispiel verwendet ein 128-KB-ROM mit MBC5, bindet diese Implementierung zuerst ein und legt main in Bank 0 ab. Ändern Sie während eines Aufrufs die ROM-Zuordnung nicht von außen.
last_impact_speed speichert die größte Annäherungsgeschwindigkeit entlang einer Kontaktachse. Die Integration setzt sie bei aktiven dynamischen Körpern zurück; statische und inaktive Körper behalten sie bei. Weder break_speed noch KQ3D_BODY_BROKEN löst automatisch eine Zerstörung aus. Das Spiel entscheidet darüber und ändert flags/active selbst.
kq3d_body_init
Initialisiert 3D-Mittelpunkt, halbe Ausdehnungen und Masse; setzt Geschwindigkeit, Beschleunigung, Aufprallwert und Flags auf null und aktiviert den Körper.
Syntax
void kq3d_body_init(KQBody3D* body, s16 x, s16 y, s16 z, s16 half_x, s16 half_y, s16 half_z, s16 mass_q8);Parameter
bodyZeiger auf den zu ändernden Körper. Von dieser Operation nicht verwendete Felder bleiben erhalten.
xX-Koordinate des Mittelpunkts oder Punkts, im Beispiel in Pixeln.
yY-Koordinate des Mittelpunkts oder Punkts; im Beispiel zeigen positive Werte nach unten.
zZ-Koordinate des Mittelpunkts, in der Draufsicht des Beispiels vertikal dargestellt.
half_xHalbe Ausdehnung entlang X; die gesamte Boxbreite ist doppelt so groß.
half_yHalbe Ausdehnung entlang Y; die gesamte Boxhöhe ist doppelt so groß.
half_zHalbe Ausdehnung entlang Z; die gesamte Tiefe ist doppelt so groß.
mass_q8Massenwert, bei dem 256 für 1,0 steht. Werte kleiner oder gleich null erzeugen einen statischen Körper.
Rückgabewert
Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.
Bedingungen und Grenzen
Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.
physics3d.c liegt in ROM-Bank 2. Das Beispiel verwendet ein 128-KB-ROM mit MBC5, bindet diese Implementierung zuerst ein und legt main in Bank 0 ab. Ändern Sie während eines Aufrufs die ROM-Zuordnung nicht von außen.
Der Rückprallkoeffizient beträgt 224, break_speed ist null. Für die Masse gelten die Regeln von kq3d_body_set_mass. NULL wird ignoriert; gültige halbe Ausdehnungen muss der aufrufende Code bereitstellen.
Anwendungsbeispiel
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;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Links ist die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Boxen zeigen (36,24,24) nach einem Takt, und blaue Flächen stellen das statische Hindernis dar. Die X-Geschwindigkeit springt beim Rückprall von 16 auf -14, während Z bei 8 bleibt. Der Aufprallwert beträgt 16, flags bleibt jedoch trotz break_speed=1 null. Die Panelursprünge liegen bei (8,48)/(88,48) auf dem Bildschirm. Auf dem DMG sind alle Markierungen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Speichert die angeforderte Masse und berechnet ein Gewicht aus der inversen Masse für Korrektur und Rückprall.
Syntax
void kq3d_body_set_mass(KQBody3D* body, s16 mass_q8);Parameter
bodyZeiger auf den zu ändernden Körper. Von dieser Operation nicht verwendete Felder bleiben erhalten.
mass_q8Massenwert, bei dem 256 für 1,0 steht. Werte kleiner oder gleich null erzeugen einen statischen Körper.
Rückgabewert
Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.
Bedingungen und Grenzen
physics3d.c liegt in ROM-Bank 2. Das Beispiel verwendet ein 128-KB-ROM mit MBC5, bindet diese Implementierung zuerst ein und legt main in Bank 0 ab. Ändern Sie während eines Aufrufs die ROM-Zuordnung nicht von außen.
Masse kleiner oder gleich null ergibt inverse Masse null und damit einen statischen Körper. Bei positiver Masse wird ganzzahlig 32767/max(mass,64) berechnet, mindestens jedoch 1. Die gespeicherte Masse behält den angeforderten Wert; das Gewicht ist daher kein exakter Q8-Kehrwert. Masse 256 ergibt inverse Masse 127. Geschwindigkeit und Aktivität bleiben unverändert; NULL wird ignoriert.
Anwendungsbeispiel
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);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Links ist die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Boxen zeigen (36,24,24) nach einem Takt, und blaue Flächen stellen das statische Hindernis dar. Die X-Geschwindigkeit springt beim Rückprall von 16 auf -14, während Z bei 8 bleibt. Der Aufprallwert beträgt 16, flags bleibt jedoch trotz break_speed=1 null. Die Panelursprünge liegen bei (8,48)/(88,48) auf dem Bildschirm. Auf dem DMG sind alle Markierungen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Teilt jedes der drei vorzeichenbehafteten Produkte durch 256, schneidet jeden Term gegen null ab und addiert anschließend die Terme.
Syntax
s16 kq3d_dot_q8_8(s16 x, s16 y, s16 z, s8 ax, s8 ay, s8 az);Parameter
xVorzeichenbehaftete 16-Bit-Komponente, die mit dem zugehörigen Koeffizienten multipliziert wird; sie kann Position oder Geschwindigkeit darstellen.
yVorzeichenbehaftete 16-Bit-Komponente, die mit dem zugehörigen Koeffizienten multipliziert wird; sie kann Position oder Geschwindigkeit darstellen.
zVorzeichenbehaftete 16-Bit-Komponente, die mit dem zugehörigen Koeffizienten multipliziert wird; sie kann Position oder Geschwindigkeit darstellen.
axVorzeichenbehafteter Bytekoeffizient für diese Achse (-128..127), mit Faktor 1/256 angewendet.
ayVorzeichenbehafteter Bytekoeffizient für diese Achse (-128..127), mit Faktor 1/256 angewendet.
azVorzeichenbehafteter Bytekoeffizient für diese Achse (-128..127), mit Faktor 1/256 angewendet.
Rückgabewert
Liefert die Summe dreier quantisierter Terme als s16.
Bedingungen und Grenzen
physics3d.c liegt in ROM-Bank 2. Das Beispiel verwendet ein 128-KB-ROM mit MBC5, bindet diese Implementierung zuerst ein und legt main in Bank 0 ab. Ändern Sie während eines Aufrufs die ROM-Zuordnung nicht von außen.
Jeden Term zuerst gegen null abzuschneiden kann ein anderes Ergebnis liefern als die Gesamtsumme einmal zu schieben. Ein Koeffizient kann 1,0=256 nicht speichern. Die Endsumme wird nicht gesättigt.
Anwendungsbeispiel
result[13]=kq3d_dot_q8_8(256,128,0,64,-64,127);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Links ist die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Boxen zeigen (36,24,24) nach einem Takt, und blaue Flächen stellen das statische Hindernis dar. Die X-Geschwindigkeit springt beim Rückprall von 16 auf -14, während Z bei 8 bleibt. Der Aufprallwert beträgt 16, flags bleibt jedoch trotz break_speed=1 null. Die Panelursprünge liegen bei (8,48)/(88,48) auf dem Bildschirm. Auf dem DMG sind alle Markierungen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Die lokalen Unterschiede dieser API stehen bei den Änderungen und Prüfungen vom 2026-10-03.
Setzt den Aufprallwert eines aktiven dynamischen Körpers zurück, addiert Weltschwerkraft und Körperbeschleunigung, begrenzt jede Geschwindigkeitsachse und aktualisiert die Position.
Syntax
void kq3d_integrate_body(KQWorld3D* world, KQBody3D* body);Parameter
worldZeiger auf die Welt mit dem Körperarray und den Simulationseinstellungen.
bodyZeiger auf den zu ändernden Körper. Von dieser Operation nicht verwendete Felder bleiben erhalten.
Rückgabewert
Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.
Bedingungen und Grenzen
Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.
Summen, Differenzen, addierte halbe Ausdehnungen und Produkte zur Kontaktkorrektur müssen im vorzeichenbehafteten 16-Bit-Bereich bleiben. Geschwindigkeitsgrenzen greifen erst nach der Addition und verhindern keinen Überlauf innerhalb dieser Addition.
Integration und Kollisionserkennung für Boxen verwenden gemeinsamen Arbeitsspeicher. Rufen Sie diese Physikroutinen nicht während ihrer Ausführung erneut aus einem Interrupt auf.
physics3d.c liegt in ROM-Bank 2. Das Beispiel verwendet ein 128-KB-ROM mit MBC5, bindet diese Implementierung zuerst ein und legt main in Bank 0 ab. Ändern Sie während eines Aufrufs die ROM-Zuordnung nicht von außen.
last_impact_speed speichert die größte Annäherungsgeschwindigkeit entlang einer Kontaktachse. Die Integration setzt sie bei aktiven dynamischen Körpern zurück; statische und inaktive Körper behalten sie bei. Weder break_speed noch KQ3D_BODY_BROKEN löst automatisch eine Zerstörung aus. Das Spiel entscheidet darüber und ändert flags/active selbst.
ax/ay/az bleiben erhalten und wirken erneut bei der nächsten Integration. Diese Funktion allein löst keine Kontakte auf. NULL, inaktive und statische Körper werden nicht verändert.
Anwendungsbeispiel
kq3d_integrate_body(&world,&temp);
result[9]=temp.x; result[10]=temp.y; result[11]=temp.z; result[12]=temp.last_impact_speed;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Links ist die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Boxen zeigen (36,24,24) nach einem Takt, und blaue Flächen stellen das statische Hindernis dar. Die X-Geschwindigkeit springt beim Rückprall von 16 auf -14, während Z bei 8 bleibt. Der Aufprallwert beträgt 16, flags bleibt jedoch trotz break_speed=1 null. Die Panelursprünge liegen bei (8,48)/(88,48) auf dem Bildschirm. Auf dem DMG sind alle Markierungen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Prüft zwei über ihren Mittelpunkt definierte Boxen auf echte Überlappung entlang aller drei Achsen.
Syntax
u8 kq3d_overlap_aabb(const KQBody3D* a, const KQBody3D* b);Parameter
aGültiger Körperzeiger. Die Abfrage ignoriert Aktivität, Masse und Flags.
bGültiger Körperzeiger. Die Abfrage ignoriert Aktivität, Masse und Flags.
Rückgabewert
Liefert 1 bei Überlappung der Innenbereiche und 0 bei bloßer Berührung oder getrennten Formen.
Bedingungen und Grenzen
Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.
Summen, Differenzen, addierte halbe Ausdehnungen und Produkte zur Kontaktkorrektur müssen im vorzeichenbehafteten 16-Bit-Bereich bleiben. Geschwindigkeitsgrenzen greifen erst nach der Addition und verhindern keinen Überlauf innerhalb dieser Addition.
physics3d.c liegt in ROM-Bank 2. Das Beispiel verwendet ein 128-KB-ROM mit MBC5, bindet diese Implementierung zuerst ein und legt main in Bank 0 ab. Ändern Sie während eines Aufrufs die ROM-Zuordnung nicht von außen.
Anwendungsbeispiel
result[14]=kq3d_overlap_aabb(&bodies[0],&bodies[1]);
bodies[1].z=32; result[15]=kq3d_overlap_aabb(&bodies[0],&bodies[1]);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Links ist die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Boxen zeigen (36,24,24) nach einem Takt, und blaue Flächen stellen das statische Hindernis dar. Die X-Geschwindigkeit springt beim Rückprall von 16 auf -14, während Z bei 8 bleibt. Der Aufprallwert beträgt 16, flags bleibt jedoch trotz break_speed=1 null. Die Panelursprünge liegen bei (8,48)/(88,48) auf dem Bildschirm. Auf dem DMG sind alle Markierungen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Die lokalen Unterschiede dieser API stehen bei den Änderungen und Prüfungen vom 2026-10-03.
Integriert aktive dynamische Körper und verarbeitet Kontaktkorrektur, Rückprall und Aufprallwerte zwischen aktiven Welteinträgen.
Syntax
void kq3d_step(KQWorld3D* world);Parameter
worldZeiger auf die Welt mit dem Körperarray und den Simulationseinstellungen.
Rückgabewert
Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.
Bedingungen und Grenzen
Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.
Eine Welt nutzt ein vom aufrufenden Code bereitgestelltes Array. Dieser reserviert und besitzt den Speicher für die Körper und hält ihn gültig. Das Initialisieren der Welt initialisiert nicht die Arrayelemente.
Summen, Differenzen, addierte halbe Ausdehnungen und Produkte zur Kontaktkorrektur müssen im vorzeichenbehafteten 16-Bit-Bereich bleiben. Geschwindigkeitsgrenzen greifen erst nach der Addition und verhindern keinen Überlauf innerhalb dieser Addition.
Integration und Kollisionserkennung für Boxen verwenden gemeinsamen Arbeitsspeicher. Rufen Sie diese Physikroutinen nicht während ihrer Ausführung erneut aus einem Interrupt auf.
physics3d.c liegt in ROM-Bank 2. Das Beispiel verwendet ein 128-KB-ROM mit MBC5, bindet diese Implementierung zuerst ein und legt main in Bank 0 ab. Ändern Sie während eines Aufrufs die ROM-Zuordnung nicht von außen.
Kontakte nutzen die Achse mit der geringsten Eindringtiefe; bei Gleichstand gilt die Reihenfolge X, Y, Z. Nur eine Annäherung führt zum Abprallen. Dafür werden inverse Massen und der auf 0..256 begrenzte mittlere Rückprallkoeffizient verwendet. Schnelles Durchtunneln, Rotation, Drehimpuls und Reibung werden nicht behandelt.
last_impact_speed speichert die größte Annäherungsgeschwindigkeit entlang einer Kontaktachse. Die Integration setzt sie bei aktiven dynamischen Körpern zurück; statische und inaktive Körper behalten sie bei. Weder break_speed noch KQ3D_BODY_BROKEN löst automatisch eine Zerstörung aus. Das Spiel entscheidet darüber und ändert flags/active selbst.
Eine NULL-Welt oder ein NULL-Array wird ignoriert. Auch bei solver_iterations gleich null wird ein Kontaktdurchlauf ausgeführt.
Auch die Zwischenprodukte impact*(256+restitution) und correction*inverse-mass sind s16. Halten Sie die Produkte bei höchstens 32767; bei restitution 256 darf impact beispielsweise höchstens 63 betragen.
Anwendungsbeispiel
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;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Links ist die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Boxen zeigen (36,24,24) nach einem Takt, und blaue Flächen stellen das statische Hindernis dar. Die X-Geschwindigkeit springt beim Rückprall von 16 auf -14, während Z bei 8 bleibt. Der Aufprallwert beträgt 16, flags bleibt jedoch trotz break_speed=1 null. Die Panelursprünge liegen bei (8,48)/(88,48) auf dem Bildschirm. Auf dem DMG sind alle Markierungen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Verknüpft ein Körperarray mit einer 3D-Welt mit Schwerkraft (0,24,0), vier Durchläufen und Geschwindigkeitsgrenze 512 pro Achse.
Syntax
void kq3d_world_init(KQWorld3D* world, KQBody3D* bodies, u8 body_count);Parameter
worldZeiger auf die Welt mit dem Körperarray und den Simulationseinstellungen.
bodiesAnfang eines vom aufrufenden Code gehaltenen Körperarrays mit body_count Elementen.
body_countAnzahl der Arrayplätze von 0 bis 255, einschließlich inaktiver Einträge.
Rückgabewert
Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.
Bedingungen und Grenzen
Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.
Eine Welt nutzt ein vom aufrufenden Code bereitgestelltes Array. Dieser reserviert und besitzt den Speicher für die Körper und hält ihn gültig. Das Initialisieren der Welt initialisiert nicht die Arrayelemente.
physics3d.c liegt in ROM-Bank 2. Das Beispiel verwendet ein 128-KB-ROM mit MBC5, bindet diese Implementierung zuerst ein und legt main in Bank 0 ab. Ändern Sie während eines Aufrufs die ROM-Zuordnung nicht von außen.
Anwendungsbeispiel
kq3d_world_init(&world,bodies,2);
result[0]=world.gravity_y; result[1]=world.solver_iterations; result[2]=world.max_speed;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Links ist die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Boxen zeigen (36,24,24) nach einem Takt, und blaue Flächen stellen das statische Hindernis dar. Die X-Geschwindigkeit springt beim Rückprall von 16 auf -14, während Z bei 8 bleibt. Der Aufprallwert beträgt 16, flags bleibt jedoch trotz break_speed=1 null. Die Panelursprünge liegen bei (8,48)/(88,48) auf dem Bildschirm. Auf dem DMG sind alle Markierungen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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 — Scrolltabellen für Bildstreifen und Bildschirmzeilen
Die Raster-Bibliothek bietet eine Tabelle mit acht Bändern und einen LineX-Renderer, der X auf allen 144 sichtbaren Zeilen ändert. Bänder eignen sich für feste HUDs, Parallaxe, Fensteränderungen und CGB-Farbbereiche. LineX eignet sich für wellenförmige Titel und Bildschirmeffekte. Wählen Sie einen Treiber; betreiben Sie nicht beide gleichzeitig.
Binden Sie raster.h ein und kompilieren Sie raster.c zusammen mit scroll.c. Eine gemeinsame Tabelle fasst bis zu acht Bänder. Mischen Sie beim Aufbau mit Raster_* keine direkten Aufrufe von Scroll_Split* oder __scroll_split_* ein: Sie umgehen die Zählung und die Verwaltung der letzten Zeile im Wrapper.
Bauen Sie die Tabelle während VBlank oder in einem anderen Zeitraum mit kontrollierbarer Bildwirkung neu auf: leeren, Einträge hinzufügen, aktivieren. Das Leeren stoppt auch aktive Teilungen; es wird kein unabhängiger Hintergrundpuffer bearbeitet. LY plant einen Interrupt, Registerzugriffe benötigen zusätzliche Zeit. Für Wellen pro Rasterzeile verwenden Sie die separate Familie Raster_LineX*; betreiben Sie nicht beide Treiber gleichzeitig.
Rasterzeilenwelle und animierte Titeleinblendung
Wird die X-Position des Hintergrunds für jede Bildschirmzeile verändert, verbiegen sich Säulen und Schrift wellenförmig. Das eignet sich für eine Teleportation, einen Bossauftritt oder eine Titelanimation. Die Vorschau unten zeigt acht Aufnahmen im Wechsel; in der ROM schreitet die Wellenphase mit jedem Frame fort.
Raster_Push-Operationen planen bis zu acht Bänder. Verwenden Sie Raster_LineXRunFrame für einen eigenen horizontalen Versatz je Rasterzeile. Sprites und Fenster werden nicht verbogen. Der Renderer belegt während aller 144 sichtbaren Zeilen die CPU und maskiert Interrupts; aktualisieren Sie Spiellogik und Audio daher zwischen den Aufrufen.

Beispiel einer fortlaufenden Welle
Beispiel einer Titeleinblendung
Der Titel kommt von rechts mit einer großen Welle ins Bild, wechselt zu einer kleinen Wellenbewegung und kommt dann zur Ruhe. Das Beispiel bindet raster_wave.c aus demselben Verzeichnis ein; halten Sie beide Quelldateien zusammen. Die API-Einträge unten enthalten Build-Befehle und individuelle Nutzungshinweise.
Die Raster-Bibliothek bietet eine Tabelle mit acht Bändern und einen LineX-Renderer, der X auf allen 144 sichtbaren Zeilen ändert. Bänder eignen sich für feste HUDs, Parallaxe, Fensteränderungen und CGB-Farbbereiche. LineX eignet sich für wellenförmige Titel und Bildschirmeffekte. Wählen Sie einen Treiber; betreiben Sie nicht beide gleichzeitig.
Binden Sie raster.h ein und kompilieren Sie raster.c zusammen mit scroll.c. Eine gemeinsame Tabelle fasst bis zu acht Bänder. Mischen Sie beim Aufbau mit Raster_* keine direkten Aufrufe von Scroll_Split* oder __scroll_split_* ein: Sie umgehen die Zählung und die Verwaltung der letzten Zeile im Wrapper.
Bauen Sie die Tabelle während VBlank oder in einem anderen Zeitraum mit kontrollierbarer Bildwirkung neu auf: leeren, Einträge hinzufügen, aktivieren. Das Leeren stoppt auch aktive Teilungen; es wird kein unabhängiger Hintergrundpuffer bearbeitet. LY plant einen Interrupt, Registerzugriffe benötigen zusätzliche Zeit. Für Wellen pro Rasterzeile verwenden Sie die separate Familie Raster_LineX*; betreiben Sie nicht beide Treiber gleichzeitig.
Raster_BuildHudBottom
Erstellt ein scrollendes oberes Spielfeld und ein festes unteres HUD. LY=0 verwendet Kamerakoordinaten; hud_y schaltet den Hintergrund auf (0,0).
Syntax
u8 Raster_BuildHudBottom(u8 hud_y, u8 camera_x, u8 camera_y);Parameter
hud_yTeilungszeile in 1..143. Null oder Werte ab 144 liefern BAD_RANGE.
camera_xHintergrund-Scrollbyte in 0..255. SCX/SCY geben die Leseposition in der Hintergrundkarte an, keine Bildschirmposition. Die Koordinaten laufen innerhalb des 256-Pixel-Hintergrunds zyklisch um.
camera_yHintergrund-Scrollbyte in 0..255. SCX/SCY geben die Leseposition in der Hintergrundkarte an, keine Bildschirmposition. Die Koordinaten laufen innerhalb des 256-Pixel-Hintergrunds zyklisch um.
Rückgabewert
Liefert bei Erfolg KQ_RASTER_OK (0), sonst einen Fehlerstatus von 1 bis 4. Beachten Sie die Funktionsbedingungen und Raster_GetLastError.
Bedingungen und Grenzen
Binden Sie raster.h ein und kompilieren Sie raster.c zusammen mit scroll.c. Eine gemeinsame Tabelle fasst bis zu acht Bänder. Mischen Sie beim Aufbau mit Raster_* keine direkten Aufrufe von Scroll_Split* oder __scroll_split_* ein: Sie umgehen die Zählung und die Verwaltung der letzten Zeile im Wrapper.
Bauen Sie die Tabelle während VBlank oder in einem anderen Zeitraum mit kontrollierbarer Bildwirkung neu auf: leeren, Einträge hinzufügen, aktivieren. Das Leeren stoppt auch aktive Teilungen; es wird kein unabhängiger Hintergrundpuffer bearbeitet. LY plant einen Interrupt, Registerzugriffe benötigen zusätzliche Zeit. Für Wellen pro Rasterzeile verwenden Sie die separate Familie Raster_LineX*; betreiben Sie nicht beide Treiber gleichzeitig.
Die Statuscodes sind 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED und 4 BAD_RANGE. Beim Hinzufügen werden LY-Bereich, Kapazität und Reihenfolge in dieser Reihenfolge geprüft. Ein abgelehnter Eintrag vergrößert die Tabelle nicht. Ein späterer erfolgreicher Eintrag oder das Leeren setzt den Fehler auf null zurück; prüfen Sie daher jeden Rückgabewert unmittelbar.
Gültige Parameter stoppen bestehende Teilungen, leeren die Tabelle und fügen neue Bänder hinzu. Ungültige Parameter lassen Tabelle und Anzahl unverändert und speichern BAD_RANGE. Auch nach erfolgreichem Aufbau ist Raster_Commit erforderlich.
Anwendungsbeispiel
Raster_BuildHudBottom(96,8,8);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Die Zeilen ab 96 bleiben fest. Kamera (8,8) setzt die oberen Rechtecke auf (24,8) und (24,72), während das untere bei (32,112) bleibt. FIXED BOTTOM HUD bleibt unten.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Erstellt zwei Hintergrundbänder für ein festes oberes HUD: (0,0) bei LY=0, danach Kamerakoordinaten ab hud_height. Dies teilt den Hintergrundscroll und verwendet kein Fenster.
Syntax
u8 Raster_BuildHudTop(u8 hud_height, u8 camera_x, u8 camera_y);Parameter
hud_heightTeilungszeile in 1..143. Null oder Werte ab 144 liefern BAD_RANGE.
camera_xHintergrund-Scrollbyte in 0..255. SCX/SCY geben die Leseposition in der Hintergrundkarte an, keine Bildschirmposition. Die Koordinaten laufen innerhalb des 256-Pixel-Hintergrunds zyklisch um.
camera_yHintergrund-Scrollbyte in 0..255. SCX/SCY geben die Leseposition in der Hintergrundkarte an, keine Bildschirmposition. Die Koordinaten laufen innerhalb des 256-Pixel-Hintergrunds zyklisch um.
Rückgabewert
Liefert bei Erfolg KQ_RASTER_OK (0), sonst einen Fehlerstatus von 1 bis 4. Beachten Sie die Funktionsbedingungen und Raster_GetLastError.
Bedingungen und Grenzen
Binden Sie raster.h ein und kompilieren Sie raster.c zusammen mit scroll.c. Eine gemeinsame Tabelle fasst bis zu acht Bänder. Mischen Sie beim Aufbau mit Raster_* keine direkten Aufrufe von Scroll_Split* oder __scroll_split_* ein: Sie umgehen die Zählung und die Verwaltung der letzten Zeile im Wrapper.
Bauen Sie die Tabelle während VBlank oder in einem anderen Zeitraum mit kontrollierbarer Bildwirkung neu auf: leeren, Einträge hinzufügen, aktivieren. Das Leeren stoppt auch aktive Teilungen; es wird kein unabhängiger Hintergrundpuffer bearbeitet. LY plant einen Interrupt, Registerzugriffe benötigen zusätzliche Zeit. Für Wellen pro Rasterzeile verwenden Sie die separate Familie Raster_LineX*; betreiben Sie nicht beide Treiber gleichzeitig.
Die Statuscodes sind 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED und 4 BAD_RANGE. Beim Hinzufügen werden LY-Bereich, Kapazität und Reihenfolge in dieser Reihenfolge geprüft. Ein abgelehnter Eintrag vergrößert die Tabelle nicht. Ein späterer erfolgreicher Eintrag oder das Leeren setzt den Fehler auf null zurück; prüfen Sie daher jeden Rückgabewert unmittelbar.
Gültige Parameter stoppen bestehende Teilungen, leeren die Tabelle und fügen neue Bänder hinzu. Ungültige Parameter lassen Tabelle und Anzahl unverändert und speichern BAD_RANGE. Auch nach erfolgreichem Aufbau ist Raster_Commit erforderlich.
Anwendungsbeispiel
Raster_BuildHudTop(32,8,8);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Die oberen 32 Zeilen bleiben fest. Das obere Rechteck bleibt bei (32,16); Kamera (8,8) verschiebt die anderen beiden nach (24,72) und (24,104). FIXED TOP HUD bleibt oben.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Erstellt zwei Hintergrundbänder mit getrennten horizontalen Offsets: far_scx bei LY=0 und near_scx ab split_y, bei gemeinsamem Y-Scroll.
Syntax
u8 Raster_BuildParallax2(u8 split_y, u8 far_scx, u8 near_scx, u8 scy);Parameter
split_yTeilungszeile in 1..143. Null oder Werte ab 144 liefern BAD_RANGE.
far_scxHintergrund-Scrollbyte in 0..255. SCX/SCY geben die Leseposition in der Hintergrundkarte an, keine Bildschirmposition. Die Koordinaten laufen innerhalb des 256-Pixel-Hintergrunds zyklisch um.
near_scxHintergrund-Scrollbyte in 0..255. SCX/SCY geben die Leseposition in der Hintergrundkarte an, keine Bildschirmposition. Die Koordinaten laufen innerhalb des 256-Pixel-Hintergrunds zyklisch um.
scyHintergrund-Scrollbyte in 0..255. SCX/SCY geben die Leseposition in der Hintergrundkarte an, keine Bildschirmposition. Die Koordinaten laufen innerhalb des 256-Pixel-Hintergrunds zyklisch um.
Rückgabewert
Liefert bei Erfolg KQ_RASTER_OK (0), sonst einen Fehlerstatus von 1 bis 4. Beachten Sie die Funktionsbedingungen und Raster_GetLastError.
Bedingungen und Grenzen
Binden Sie raster.h ein und kompilieren Sie raster.c zusammen mit scroll.c. Eine gemeinsame Tabelle fasst bis zu acht Bänder. Mischen Sie beim Aufbau mit Raster_* keine direkten Aufrufe von Scroll_Split* oder __scroll_split_* ein: Sie umgehen die Zählung und die Verwaltung der letzten Zeile im Wrapper.
Bauen Sie die Tabelle während VBlank oder in einem anderen Zeitraum mit kontrollierbarer Bildwirkung neu auf: leeren, Einträge hinzufügen, aktivieren. Das Leeren stoppt auch aktive Teilungen; es wird kein unabhängiger Hintergrundpuffer bearbeitet. LY plant einen Interrupt, Registerzugriffe benötigen zusätzliche Zeit. Für Wellen pro Rasterzeile verwenden Sie die separate Familie Raster_LineX*; betreiben Sie nicht beide Treiber gleichzeitig.
Die Statuscodes sind 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED und 4 BAD_RANGE. Beim Hinzufügen werden LY-Bereich, Kapazität und Reihenfolge in dieser Reihenfolge geprüft. Ein abgelehnter Eintrag vergrößert die Tabelle nicht. Ein späterer erfolgreicher Eintrag oder das Leeren setzt den Fehler auf null zurück; prüfen Sie daher jeden Rückgabewert unmittelbar.
Gültige Parameter stoppen bestehende Teilungen, leeren die Tabelle und fügen neue Bänder hinzu. Ungültige Parameter lassen Tabelle und Anzahl unverändert und speichern BAD_RANGE. Auch nach erfolgreichem Aufbau ist Raster_Commit erforderlich.
Anwendungsbeispiel
Raster_BuildParallax2(64,0,16,0);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
X wechselt an der geplanten Zeile 64 von 0 auf 16. Rechtecke erscheinen bei (32,16), (16,80) und (16,112); nur der untere Bereich wird sechzehn Pixel nach links verschoben.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Trägt scx0, scx1 und scx2 für Bänder ab LY=0, y1 und y2 ein. Ferne, mittlere und nahe Ebenen erhalten verschiedene horizontale Offsets bei gemeinsamem Y-Scroll.
Syntax
u8 Raster_BuildParallax3(u8 y1, u8 y2, u8 scx0, u8 scx1, u8 scx2, u8 scy);Parameter
y1Teilungszeilen mit der Bedingung 1 <= y1 < y2 <= 143.
y2Teilungszeilen mit der Bedingung 1 <= y1 < y2 <= 143.
scx0Hintergrund-Scrollbyte in 0..255. SCX/SCY geben die Leseposition in der Hintergrundkarte an, keine Bildschirmposition. Die Koordinaten laufen innerhalb des 256-Pixel-Hintergrunds zyklisch um.
scx1Hintergrund-Scrollbyte in 0..255. SCX/SCY geben die Leseposition in der Hintergrundkarte an, keine Bildschirmposition. Die Koordinaten laufen innerhalb des 256-Pixel-Hintergrunds zyklisch um.
scx2Hintergrund-Scrollbyte in 0..255. SCX/SCY geben die Leseposition in der Hintergrundkarte an, keine Bildschirmposition. Die Koordinaten laufen innerhalb des 256-Pixel-Hintergrunds zyklisch um.
scyHintergrund-Scrollbyte in 0..255. SCX/SCY geben die Leseposition in der Hintergrundkarte an, keine Bildschirmposition. Die Koordinaten laufen innerhalb des 256-Pixel-Hintergrunds zyklisch um.
Rückgabewert
Liefert bei Erfolg KQ_RASTER_OK (0), sonst einen Fehlerstatus von 1 bis 4. Beachten Sie die Funktionsbedingungen und Raster_GetLastError.
Bedingungen und Grenzen
Binden Sie raster.h ein und kompilieren Sie raster.c zusammen mit scroll.c. Eine gemeinsame Tabelle fasst bis zu acht Bänder. Mischen Sie beim Aufbau mit Raster_* keine direkten Aufrufe von Scroll_Split* oder __scroll_split_* ein: Sie umgehen die Zählung und die Verwaltung der letzten Zeile im Wrapper.
Bauen Sie die Tabelle während VBlank oder in einem anderen Zeitraum mit kontrollierbarer Bildwirkung neu auf: leeren, Einträge hinzufügen, aktivieren. Das Leeren stoppt auch aktive Teilungen; es wird kein unabhängiger Hintergrundpuffer bearbeitet. LY plant einen Interrupt, Registerzugriffe benötigen zusätzliche Zeit. Für Wellen pro Rasterzeile verwenden Sie die separate Familie Raster_LineX*; betreiben Sie nicht beide Treiber gleichzeitig.
Die Statuscodes sind 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED und 4 BAD_RANGE. Beim Hinzufügen werden LY-Bereich, Kapazität und Reihenfolge in dieser Reihenfolge geprüft. Ein abgelehnter Eintrag vergrößert die Tabelle nicht. Ein späterer erfolgreicher Eintrag oder das Leeren setzt den Fehler auf null zurück; prüfen Sie daher jeden Rückgabewert unmittelbar.
Gültige Parameter stoppen bestehende Teilungen, leeren die Tabelle und fügen neue Bänder hinzu. Ungültige Parameter lassen Tabelle und Anzahl unverändert und speichern BAD_RANGE. Auch nach erfolgreichem Aufbau ist Raster_Commit erforderlich.
Anwendungsbeispiel
Raster_BuildParallax3(64,104,0,8,16,0);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Die geplanten Zeilen 64 und 104 begrenzen Bereiche mit X-Offsets 0, 8 und 16. Rechtecke bei (32,16), (24,80) und (16,112) zeigen die zunehmende Verschiebung über drei Bänder.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Stoppt die Teilungsplanung sofort und setzt Anzahl, Reihenfolge und Fehlerzustand zurück, bevor die Tabelle in derselben Szene neu aufgebaut wird. Nicht jedes Byte des Tabellenspeichers wird auf null gesetzt.
Syntax
void Raster_Clear();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Binden Sie raster.h ein und kompilieren Sie raster.c zusammen mit scroll.c. Eine gemeinsame Tabelle fasst bis zu acht Bänder. Mischen Sie beim Aufbau mit Raster_* keine direkten Aufrufe von Scroll_Split* oder __scroll_split_* ein: Sie umgehen die Zählung und die Verwaltung der letzten Zeile im Wrapper.
Bauen Sie die Tabelle während VBlank oder in einem anderen Zeitraum mit kontrollierbarer Bildwirkung neu auf: leeren, Einträge hinzufügen, aktivieren. Das Leeren stoppt auch aktive Teilungen; es wird kein unabhängiger Hintergrundpuffer bearbeitet. LY plant einen Interrupt, Registerzugriffe benötigen zusätzliche Zeit. Für Wellen pro Rasterzeile verwenden Sie die separate Familie Raster_LineX*; betreiben Sie nicht beide Treiber gleichzeitig.
Die Statuscodes sind 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED und 4 BAD_RANGE. Beim Hinzufügen werden LY-Bereich, Kapazität und Reihenfolge in dieser Reihenfolge geprüft. Ein abgelehnter Eintrag vergrößert die Tabelle nicht. Ein späterer erfolgreicher Eintrag oder das Leeren setzt den Fehler auf null zurück; prüfen Sie daher jeden Rückgabewert unmittelbar.
Das Stoppen der Teilungen setzt SCX, SCY, WX und WY nicht auf null. Stellen Sie den gewünschten Grundzustand mit normalen Setzfunktionen wie Scroll_SetBg her. Auch vorherige VBlank-/STAT-IE-Bits oder IME werden nicht wiederhergestellt.
Anwendungsbeispiel
Raster_Clear();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Rote Rechtecke von jeweils 24x16 Pixeln, auf DMG schwarz, erscheinen bei (32,16), (24,80) und (16,112). Tiefere Bänder werden weiter nach links verschoben. Intern werden Anzahl 3, Fehler 0 und Aktivierungsergebnis 0 gespeichert.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Aktiviert die aufgebaute gemeinsame Tabelle. Auch wenn ein Hinzufügen fehlschlug, werden zuvor erfolgreich eingetragene Bänder aktiviert. Der aufrufende Code muss jede Eintragung prüfen.
Syntax
u8 Raster_Commit();Rückgabewert
Liefert den zuletzt gespeicherten Fehler. Null beweist nicht, dass alle vorherigen Eintragungen erfolgreich waren.
Bedingungen und Grenzen
Binden Sie raster.h ein und kompilieren Sie raster.c zusammen mit scroll.c. Eine gemeinsame Tabelle fasst bis zu acht Bänder. Mischen Sie beim Aufbau mit Raster_* keine direkten Aufrufe von Scroll_Split* oder __scroll_split_* ein: Sie umgehen die Zählung und die Verwaltung der letzten Zeile im Wrapper.
Bauen Sie die Tabelle während VBlank oder in einem anderen Zeitraum mit kontrollierbarer Bildwirkung neu auf: leeren, Einträge hinzufügen, aktivieren. Das Leeren stoppt auch aktive Teilungen; es wird kein unabhängiger Hintergrundpuffer bearbeitet. LY plant einen Interrupt, Registerzugriffe benötigen zusätzliche Zeit. Für Wellen pro Rasterzeile verwenden Sie die separate Familie Raster_LineX*; betreiben Sie nicht beide Treiber gleichzeitig.
Die Statuscodes sind 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED und 4 BAD_RANGE. Beim Hinzufügen werden LY-Bereich, Kapazität und Reihenfolge in dieser Reihenfolge geprüft. Ein abgelehnter Eintrag vergrößert die Tabelle nicht. Ein späterer erfolgreicher Eintrag oder das Leeren setzt den Fehler auf null zurück; prüfen Sie daher jeden Rückgabewert unmittelbar.
Eine nicht leere Tabelle setzt die VBlank-/STAT-IE-Bits und führt EI aus, um Interrupts zu aktivieren; andere IE-Bits bleiben erhalten. Eine leere Tabelle deaktiviert die Teilungsplanung, stellt aber die globale Interruptkonfiguration nicht wieder her.
Anwendungsbeispiel
result[2]=Raster_Commit();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Rote Rechtecke von jeweils 24x16 Pixeln, auf DMG schwarz, erscheinen bei (32,16), (24,80) und (16,112). Tiefere Bänder werden weiter nach links verschoben. Intern werden Anzahl 3, Fehler 0 und Aktivierungsergebnis 0 gespeichert.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Leert und aktiviert eine leere Tabelle, um Rasterbänder abzuschalten. Verwenden Sie dies als ausdrücklichen Stopp beim Wechsel in eine Szene ohne geteiltes Scrollen.
Syntax
void Raster_Disable();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Binden Sie raster.h ein und kompilieren Sie raster.c zusammen mit scroll.c. Eine gemeinsame Tabelle fasst bis zu acht Bänder. Mischen Sie beim Aufbau mit Raster_* keine direkten Aufrufe von Scroll_Split* oder __scroll_split_* ein: Sie umgehen die Zählung und die Verwaltung der letzten Zeile im Wrapper.
Bauen Sie die Tabelle während VBlank oder in einem anderen Zeitraum mit kontrollierbarer Bildwirkung neu auf: leeren, Einträge hinzufügen, aktivieren. Das Leeren stoppt auch aktive Teilungen; es wird kein unabhängiger Hintergrundpuffer bearbeitet. LY plant einen Interrupt, Registerzugriffe benötigen zusätzliche Zeit. Für Wellen pro Rasterzeile verwenden Sie die separate Familie Raster_LineX*; betreiben Sie nicht beide Treiber gleichzeitig.
Die Statuscodes sind 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED und 4 BAD_RANGE. Beim Hinzufügen werden LY-Bereich, Kapazität und Reihenfolge in dieser Reihenfolge geprüft. Ein abgelehnter Eintrag vergrößert die Tabelle nicht. Ein späterer erfolgreicher Eintrag oder das Leeren setzt den Fehler auf null zurück; prüfen Sie daher jeden Rückgabewert unmittelbar.
Das Stoppen der Teilungen setzt SCX, SCY, WX und WY nicht auf null. Stellen Sie den gewünschten Grundzustand mit normalen Setzfunktionen wie Scroll_SetBg her. Auch vorherige VBlank-/STAT-IE-Bits oder IME werden nicht wiederhergestellt.
Anwendungsbeispiel
Raster_Disable();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Rote Rechtecke von jeweils 24x16 Pixeln, auf DMG schwarz, erscheinen bei (32,16), (24,80) und (16,112). Tiefere Bänder werden weiter nach links verschoben. Intern werden Anzahl 3, Fehler 0 und Aktivierungsergebnis 0 gespeichert.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Liest die Anzahl der über den Raster-Wrapper eingetragenen Bänder. Clear/Disable setzt sie auf null; bloßes Aktivieren erhält sie.
Syntax
u8 Raster_GetCount();Rückgabewert
Liefert die Anzahl der Einträge in 0..8. Acht minus dieser Wert ergibt die freie Kapazität. Das Lesen verändert keinen Zustand.
Bedingungen und Grenzen
Binden Sie raster.h ein und kompilieren Sie raster.c zusammen mit scroll.c. Eine gemeinsame Tabelle fasst bis zu acht Bänder. Mischen Sie beim Aufbau mit Raster_* keine direkten Aufrufe von Scroll_Split* oder __scroll_split_* ein: Sie umgehen die Zählung und die Verwaltung der letzten Zeile im Wrapper.
Bauen Sie die Tabelle während VBlank oder in einem anderen Zeitraum mit kontrollierbarer Bildwirkung neu auf: leeren, Einträge hinzufügen, aktivieren. Das Leeren stoppt auch aktive Teilungen; es wird kein unabhängiger Hintergrundpuffer bearbeitet. LY plant einen Interrupt, Registerzugriffe benötigen zusätzliche Zeit. Für Wellen pro Rasterzeile verwenden Sie die separate Familie Raster_LineX*; betreiben Sie nicht beide Treiber gleichzeitig.
Die Statuscodes sind 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED und 4 BAD_RANGE. Beim Hinzufügen werden LY-Bereich, Kapazität und Reihenfolge in dieser Reihenfolge geprüft. Ein abgelehnter Eintrag vergrößert die Tabelle nicht. Ein späterer erfolgreicher Eintrag oder das Leeren setzt den Fehler auf null zurück; prüfen Sie daher jeden Rückgabewert unmittelbar.
Anwendungsbeispiel
result[0]=Raster_GetCount();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Rote Rechtecke von jeweils 24x16 Pixeln, auf DMG schwarz, erscheinen bei (32,16), (24,80) und (16,112). Tiefere Bänder werden weiter nach links verschoben. Intern werden Anzahl 3, Fehler 0 und Aktivierungsergebnis 0 gespeichert.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Liest den zuletzt gespeicherten Raster-Status, ohne ihn zu löschen. Er ist keine kumulative Aufzeichnung aller früheren Fehler.
Syntax
u8 Raster_GetLastError();Rückgabewert
Liefert den gespeicherten Status in 0..4. Das Aktivieren gibt diesen Wert zurück, macht aber weder einen Fehler automatisch rückgängig noch verwirft es die Tabelle.
Bedingungen und Grenzen
Binden Sie raster.h ein und kompilieren Sie raster.c zusammen mit scroll.c. Eine gemeinsame Tabelle fasst bis zu acht Bänder. Mischen Sie beim Aufbau mit Raster_* keine direkten Aufrufe von Scroll_Split* oder __scroll_split_* ein: Sie umgehen die Zählung und die Verwaltung der letzten Zeile im Wrapper.
Bauen Sie die Tabelle während VBlank oder in einem anderen Zeitraum mit kontrollierbarer Bildwirkung neu auf: leeren, Einträge hinzufügen, aktivieren. Das Leeren stoppt auch aktive Teilungen; es wird kein unabhängiger Hintergrundpuffer bearbeitet. LY plant einen Interrupt, Registerzugriffe benötigen zusätzliche Zeit. Für Wellen pro Rasterzeile verwenden Sie die separate Familie Raster_LineX*; betreiben Sie nicht beide Treiber gleichzeitig.
Die Statuscodes sind 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED und 4 BAD_RANGE. Beim Hinzufügen werden LY-Bereich, Kapazität und Reihenfolge in dieser Reihenfolge geprüft. Ein abgelehnter Eintrag vergrößert die Tabelle nicht. Ein späterer erfolgreicher Eintrag oder das Leeren setzt den Fehler auf null zurück; prüfen Sie daher jeden Rückgabewert unmittelbar.
Anwendungsbeispiel
result[1]=Raster_GetLastError();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Rote Rechtecke von jeweils 24x16 Pixeln, auf DMG schwarz, erscheinen bei (32,16), (24,80) und (16,112). Tiefere Bänder werden weiter nach links verschoben. Intern werden Anzahl 3, Fehler 0 und Aktivierungsergebnis 0 gespeichert.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Leert die gemeinsame Bandtabelle, stoppt Teilungen und initialisiert Anzahl, Gültigkeit des letzten LY sowie Fehlerzustand. Anders als Scroll_Init initialisiert dies nicht die Hintergrund- und Fensterkoordinaten.
Syntax
void Raster_Init();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Binden Sie raster.h ein und kompilieren Sie raster.c zusammen mit scroll.c. Eine gemeinsame Tabelle fasst bis zu acht Bänder. Mischen Sie beim Aufbau mit Raster_* keine direkten Aufrufe von Scroll_Split* oder __scroll_split_* ein: Sie umgehen die Zählung und die Verwaltung der letzten Zeile im Wrapper.
Bauen Sie die Tabelle während VBlank oder in einem anderen Zeitraum mit kontrollierbarer Bildwirkung neu auf: leeren, Einträge hinzufügen, aktivieren. Das Leeren stoppt auch aktive Teilungen; es wird kein unabhängiger Hintergrundpuffer bearbeitet. LY plant einen Interrupt, Registerzugriffe benötigen zusätzliche Zeit. Für Wellen pro Rasterzeile verwenden Sie die separate Familie Raster_LineX*; betreiben Sie nicht beide Treiber gleichzeitig.
Die Statuscodes sind 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED und 4 BAD_RANGE. Beim Hinzufügen werden LY-Bereich, Kapazität und Reihenfolge in dieser Reihenfolge geprüft. Ein abgelehnter Eintrag vergrößert die Tabelle nicht. Ein späterer erfolgreicher Eintrag oder das Leeren setzt den Fehler auf null zurück; prüfen Sie daher jeden Rückgabewert unmittelbar.
Das Stoppen der Teilungen setzt SCX, SCY, WX und WY nicht auf null. Stellen Sie den gewünschten Grundzustand mit normalen Setzfunktionen wie Scroll_SetBg her. Auch vorherige VBlank-/STAT-IE-Bits oder IME werden nicht wiederhergestellt.
Anwendungsbeispiel
Raster_Init();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Rote Rechtecke von jeweils 24x16 Pixeln, auf DMG schwarz, erscheinen bei (32,16), (24,80) und (16,112). Tiefere Bänder werden weiter nach links verschoben. Intern werden Anzahl 3, Fehler 0 und Aktivierungsergebnis 0 gespeichert.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Berechnet SCX für die gewünschte Zeile, ohne Zustand, Anzeige oder Phase zu ändern.
Syntax
u8 Raster_LineXGetOffset(const RasterLineX* effect, u8 ly);Parameter
effectZeiger auf einen initialisierten RasterLineX, der während des gesamten Aufrufs gültig bleibt.
lyAbzufragende Zeilenkoordinate (0..255); sichtbar sind Zeilen 0..143. Die Abfrage läuft mit der Wellenperiode um, statt einen Bereichsfehler zu melden.
Rückgabewert
Achtbit-SCX aus Basis-X plus Verschiebung der jeweiligen Zeile. Die Beispielabfrage bei Phase 8, Zeile 0 liefert 17.
Bedingungen und Grenzen
SCX ist ein Achtbitwert, und der Hintergrund läuft nach 256 Pixeln um. Negative Verschiebungen verwenden Bytewerte modulo 256. Füllen Sie die Karte auch außerhalb des sichtbaren Ausschnitts.
Der Effekt verändert den horizontalen Hintergrundscroll; Sprites und Fenster werden nicht gebogen. RunFrame belegt die CPU und sperrt Interrupts während aller 144 sichtbaren Zeilen. Aktualisieren Sie Spiellogik und Audio zwischen den Aufrufen und kombinieren Sie diesen Renderer nicht mit einem STAT-Rasterinterrupttreiber.
Die Bilder stammen aus DMG- und CGB-Läufen in KOKURA. Jedes Pixel der 160×144-Szene einschließlich Säulen und Text wird mit den erwarteten Koordinaten je Zeile verglichen. Das Timing auf echter Hardware wurde nicht getestet.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Das ROM unterstützt DMG und CGB; wählen Sie dmg oder cgb mit KOKURA --hardware.
Anwendungsbeispiel
wave_lookup = Raster_LineXGetOffset(&wave, 0);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Säulen und Buchstaben werden horizontal um bis zu 24 Pixel gebogen. Eine Welle umfasst 64 Rasterzeilen, ihre Phase rückt pro Frame um eine Zeile vor. Auf dem CGB sind Säulen und Schrift blau. Achten Sie auf unterschiedliche horizontale Offsets je Zeile statt auf eine einheitliche Bewegung des ganzen Bildes.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Initialisiert Profil und Basis-X mit Phase null und einem Phasenschritt pro Frame. Der Aufruf zeichnet nichts und schreibt keine Scrollregister.
Syntax
void Raster_LineXInit(RasterLineX* effect, u8 profile, u8 base_x);Parameter
effectZeiger auf beschreibbaren RasterLineX-Speicher; eine vorherige Initialisierung ist nicht nötig.
profile0 (FLAT) erzeugt keine Verschiebung; 1 (X_TITLE) wiederholt Offsets von −4 bis +3 Pixeln alle 16 Zeilen; 2 (TRAVEL_GATE) wiederholt eine Welle von ±24 Pixeln alle 64 Zeilen. Andere Werte erzeugen keine Verschiebung.
base_xHintergrund-X, das zur Wellenverschiebung addiert wird, in Pixeln (0..255).
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
SCX ist ein Achtbitwert, und der Hintergrund läuft nach 256 Pixeln um. Negative Verschiebungen verwenden Bytewerte modulo 256. Füllen Sie die Karte auch außerhalb des sichtbaren Ausschnitts.
Der Effekt verändert den horizontalen Hintergrundscroll; Sprites und Fenster werden nicht gebogen. RunFrame belegt die CPU und sperrt Interrupts während aller 144 sichtbaren Zeilen. Aktualisieren Sie Spiellogik und Audio zwischen den Aufrufen und kombinieren Sie diesen Renderer nicht mit einem STAT-Rasterinterrupttreiber.
Die Bilder stammen aus DMG- und CGB-Läufen in KOKURA. Jedes Pixel der 160×144-Szene einschließlich Säulen und Text wird mit den erwarteten Koordinaten je Zeile verglichen. Das Timing auf echter Hardware wurde nicht getestet.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Das ROM unterstützt DMG und CGB; wählen Sie dmg oder cgb mit KOKURA --hardware.
Anwendungsbeispiel
Raster_LineXInit(&wave, KQ_RASTER_LINE_TRAVEL_GATE, 0);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Säulen und Buchstaben werden horizontal um bis zu 24 Pixel gebogen. Eine Welle umfasst 64 Rasterzeilen, ihre Phase rückt pro Frame um eine Zeile vor. Auf dem CGB sind Säulen und Schrift blau. Achten Sie auf unterschiedliche horizontale Offsets je Zeile statt auf eine einheitliche Bewegung des ganzen Bildes.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Wartet auf VBlank und rendert die folgenden 144 sichtbaren Zeilen mit zeilenweisem Hintergrund-X. Anschließend wird der Teilerzähler erhöht und die Phase im gewählten Intervall aktualisiert.
Syntax
void Raster_LineXRunFrame(RasterLineX* effect);Parameter
effectZeiger auf einen initialisierten RasterLineX, der während des gesamten Aufrufs gültig bleibt.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Bei ausgeschaltetem LCD kehrt die Funktion sofort ohne Effektänderung zurück. Andernfalls blockiert sie, bis SCX für alle 144 Zeilen aktualisiert ist, stellt den Interrupt-Aktivierungszustand wieder her und synchronisiert die Scroll-Hilfe mit dem letzten SCX. Die Rückkehr garantiert keinen aktiven VBlank. Warten Sie vor direkten VRAM-Schreibzugriffen auf VBlank oder nutzen Sie eine Übertragungsroutine mit sicherem Zugriffstiming.
SCX ist ein Achtbitwert, und der Hintergrund läuft nach 256 Pixeln um. Negative Verschiebungen verwenden Bytewerte modulo 256. Füllen Sie die Karte auch außerhalb des sichtbaren Ausschnitts.
Der Effekt verändert den horizontalen Hintergrundscroll; Sprites und Fenster werden nicht gebogen. RunFrame belegt die CPU und sperrt Interrupts während aller 144 sichtbaren Zeilen. Aktualisieren Sie Spiellogik und Audio zwischen den Aufrufen und kombinieren Sie diesen Renderer nicht mit einem STAT-Rasterinterrupttreiber.
Die Bilder stammen aus DMG- und CGB-Läufen in KOKURA. Jedes Pixel der 160×144-Szene einschließlich Säulen und Text wird mit den erwarteten Koordinaten je Zeile verglichen. Das Timing auf echter Hardware wurde nicht getestet.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Das ROM unterstützt DMG und CGB; wählen Sie dmg oder cgb mit KOKURA --hardware.
Anwendungsbeispiel
Raster_LineXRunFrame(&wave);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Säulen und Buchstaben werden horizontal um bis zu 24 Pixel gebogen. Eine Welle umfasst 64 Rasterzeilen, ihre Phase rückt pro Frame um eine Zeile vor. Auf dem CGB sind Säulen und Schrift blau. Achten Sie auf unterschiedliche horizontale Offsets je Zeile statt auf eine einheitliche Bewegung des ganzen Bildes.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Setzt die Wellenposition direkt und erhält Basis-X, Geschwindigkeit und Teilerzähler.
Syntax
void Raster_LineXSetPhase(RasterLineX* effect, u8 phase);Parameter
effectZeiger auf einen initialisierten RasterLineX, der während des gesamten Aufrufs gültig bleibt.
phaseAchtbit-Phasenwert; die gewählte Welle wiederholt sich alle 16 oder 64 Schritte.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
SCX ist ein Achtbitwert, und der Hintergrund läuft nach 256 Pixeln um. Negative Verschiebungen verwenden Bytewerte modulo 256. Füllen Sie die Karte auch außerhalb des sichtbaren Ausschnitts.
Der Effekt verändert den horizontalen Hintergrundscroll; Sprites und Fenster werden nicht gebogen. RunFrame belegt die CPU und sperrt Interrupts während aller 144 sichtbaren Zeilen. Aktualisieren Sie Spiellogik und Audio zwischen den Aufrufen und kombinieren Sie diesen Renderer nicht mit einem STAT-Rasterinterrupttreiber.
Die Bilder stammen aus DMG- und CGB-Läufen in KOKURA. Jedes Pixel der 160×144-Szene einschließlich Säulen und Text wird mit den erwarteten Koordinaten je Zeile verglichen. Das Timing auf echter Hardware wurde nicht getestet.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Das ROM unterstützt DMG und CGB; wählen Sie dmg oder cgb mit KOKURA --hardware.
Anwendungsbeispiel
Raster_LineXSetPhase(&wave, 8);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Säulen und Buchstaben werden horizontal um bis zu 24 Pixel gebogen. Eine Welle umfasst 64 Rasterzeilen, ihre Phase rückt pro Frame um eine Zeile vor. Auf dem CGB sind Säulen und Schrift blau. Achten Sie auf unterschiedliche horizontale Offsets je Zeile statt auf eine einheitliche Bewegung des ganzen Bildes.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Wählt ein Profil und setzt Phase und Frame-Teilerzähler auf null. Basis-X und Geschwindigkeit bleiben erhalten.
Syntax
void Raster_LineXSetProfile(RasterLineX* effect, u8 profile);Parameter
effectZeiger auf einen initialisierten RasterLineX, der während des gesamten Aufrufs gültig bleibt.
profile0 (FLAT) erzeugt keine Verschiebung; 1 (X_TITLE) wiederholt Offsets von −4 bis +3 Pixeln alle 16 Zeilen; 2 (TRAVEL_GATE) wiederholt eine Welle von ±24 Pixeln alle 64 Zeilen. Andere Werte erzeugen keine Verschiebung.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
SCX ist ein Achtbitwert, und der Hintergrund läuft nach 256 Pixeln um. Negative Verschiebungen verwenden Bytewerte modulo 256. Füllen Sie die Karte auch außerhalb des sichtbaren Ausschnitts.
Der Effekt verändert den horizontalen Hintergrundscroll; Sprites und Fenster werden nicht gebogen. RunFrame belegt die CPU und sperrt Interrupts während aller 144 sichtbaren Zeilen. Aktualisieren Sie Spiellogik und Audio zwischen den Aufrufen und kombinieren Sie diesen Renderer nicht mit einem STAT-Rasterinterrupttreiber.
Die Bilder stammen aus DMG- und CGB-Läufen in KOKURA. Jedes Pixel der 160×144-Szene einschließlich Säulen und Text wird mit den erwarteten Koordinaten je Zeile verglichen. Das Timing auf echter Hardware wurde nicht getestet.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Das ROM unterstützt DMG und CGB; wählen Sie dmg oder cgb mit KOKURA --hardware.
Anwendungsbeispiel
Raster_LineXSetProfile(&wave, KQ_RASTER_LINE_X_TITLE);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Der eigenständig gestaltete Titel ORBIT GUARD kommt mit einer großen Welle von rechts ins Bild. Nach 48 gerenderten Frames geht sie in eine kleine Welle über; ab Frame 96 steht der Titel still. Nach 160 Frames wiederholt sich der Einlauf. Die Bilder zeigen nacheinander Einlauf, kleine Welle und ruhenden Titel.






Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Setzt Phasenzuwachs und Aktualisierungsintervall. Setzt den Teilerzähler zurück und erhält die aktuelle Phase.
Syntax
void Raster_LineXSetSpeed(RasterLineX* effect, u8 phase_step, u8 frame_divider);Parameter
effectZeiger auf einen initialisierten RasterLineX, der während des gesamten Aufrufs gültig bleibt.
phase_stepPhasenzuwachs pro Aktualisierung (0..255). Null friert die Welle ein. 255 bewegt sie durch Achtbitumlauf um einen Schritt rückwärts.
frame_dividerAnzahl tatsächlich rendernder RunFrame-Aufrufe pro Phasenaktualisierung (1..255). Null wählt eins. Aufrufe, die wegen ausgeschaltetem LCD zurückkehren, zählen nicht.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
SCX ist ein Achtbitwert, und der Hintergrund läuft nach 256 Pixeln um. Negative Verschiebungen verwenden Bytewerte modulo 256. Füllen Sie die Karte auch außerhalb des sichtbaren Ausschnitts.
Der Effekt verändert den horizontalen Hintergrundscroll; Sprites und Fenster werden nicht gebogen. RunFrame belegt die CPU und sperrt Interrupts während aller 144 sichtbaren Zeilen. Aktualisieren Sie Spiellogik und Audio zwischen den Aufrufen und kombinieren Sie diesen Renderer nicht mit einem STAT-Rasterinterrupttreiber.
Die Bilder stammen aus DMG- und CGB-Läufen in KOKURA. Jedes Pixel der 160×144-Szene einschließlich Säulen und Text wird mit den erwarteten Koordinaten je Zeile verglichen. Das Timing auf echter Hardware wurde nicht getestet.
Legen Sie kitaqgb, kokura und kitaq-docs unter demselben übergeordneten Verzeichnis ab und öffnen Sie dort PowerShell. Das ROM unterstützt DMG und CGB; wählen Sie dmg oder cgb mit KOKURA --hardware.
Anwendungsbeispiel
Raster_LineXSetSpeed(&wave, 1, 1);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Säulen und Buchstaben werden horizontal um bis zu 24 Pixel gebogen. Eine Welle umfasst 64 Rasterzeilen, ihre Phase rückt pro Frame um eine Zeile vor. Auf dem CGB sind Säulen und Schrift blau. Achten Sie auf unterschiedliche horizontale Offsets je Zeile statt auf eine einheitliche Bewegung des ganzen Bildes.


Vollständiges Beispielprogramm
Build-Befehl
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.pngImplementierung und Quelltext
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
Fügt ein Band hinzu, das Hintergrund-SCX/SCY beim geplanten LY ändert. Diese reine Hintergrundoperation verändert weder Fenster noch Farben.
Syntax
u8 Raster_Push(u8 ly, u8 scx, u8 scy);Parameter
lyGeplante sichtbare Zeile in 0..143, strikt größer als die vorherige Tabellenzeile. Ein erster Eintrag bei LY=0 wird in der VBlank-Behandlung angewendet und legt den Zustand am Frameanfang fest.
scxHintergrund-Scrollbyte in 0..255. SCX/SCY geben die Leseposition in der Hintergrundkarte an, keine Bildschirmposition. Die Koordinaten laufen innerhalb des 256-Pixel-Hintergrunds zyklisch um.
scyHintergrund-Scrollbyte in 0..255. SCX/SCY geben die Leseposition in der Hintergrundkarte an, keine Bildschirmposition. Die Koordinaten laufen innerhalb des 256-Pixel-Hintergrunds zyklisch um.
Rückgabewert
Liefert bei Erfolg KQ_RASTER_OK (0), sonst einen Fehlerstatus von 1 bis 4. Beachten Sie die Funktionsbedingungen und Raster_GetLastError.
Bedingungen und Grenzen
Binden Sie raster.h ein und kompilieren Sie raster.c zusammen mit scroll.c. Eine gemeinsame Tabelle fasst bis zu acht Bänder. Mischen Sie beim Aufbau mit Raster_* keine direkten Aufrufe von Scroll_Split* oder __scroll_split_* ein: Sie umgehen die Zählung und die Verwaltung der letzten Zeile im Wrapper.
Bauen Sie die Tabelle während VBlank oder in einem anderen Zeitraum mit kontrollierbarer Bildwirkung neu auf: leeren, Einträge hinzufügen, aktivieren. Das Leeren stoppt auch aktive Teilungen; es wird kein unabhängiger Hintergrundpuffer bearbeitet. LY plant einen Interrupt, Registerzugriffe benötigen zusätzliche Zeit. Für Wellen pro Rasterzeile verwenden Sie die separate Familie Raster_LineX*; betreiben Sie nicht beide Treiber gleichzeitig.
Die Statuscodes sind 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED und 4 BAD_RANGE. Beim Hinzufügen werden LY-Bereich, Kapazität und Reihenfolge in dieser Reihenfolge geprüft. Ein abgelehnter Eintrag vergrößert die Tabelle nicht. Ein späterer erfolgreicher Eintrag oder das Leeren setzt den Fehler auf null zurück; prüfen Sie daher jeden Rückgabewert unmittelbar.
Anwendungsbeispiel
Raster_Push(0,0,0);Raster_Push(64,8,0);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Rote Rechtecke von jeweils 24x16 Pixeln, auf DMG schwarz, erscheinen bei (32,16), (24,80) und (16,112). Tiefere Bänder werden weiter nach links verschoben. Intern werden Anzahl 3, Fehler 0 und Aktivierungsergebnis 0 gespeichert.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Fügt ein Band hinzu, das während des Frames Farbe null der CGB-Hintergrundpalette null ändert. Es wählt keine andere Palette und ändert nicht deren drei weitere Farben. Eine Eintragung auf dem DMG erzeugt keinen Farbeffekt.
Syntax
u8 Raster_PushBgColor0(u8 ly, u16 rgb15);Parameter
lyGeplante sichtbare Zeile in 0..143, strikt größer als die vorherige Tabellenzeile. Ein erster Eintrag bei LY=0 wird in der VBlank-Behandlung angewendet und legt den Zustand am Frameanfang fest.
rgb15RGB15: Rot in Bits 0..4, Grün in 5..9, Blau in 10..14. 0x001F ist Rot, 0x03E0 Grün und 0x7C00 Blau. Der Eingabebereich wird nicht geprüft.
Rückgabewert
Liefert bei Erfolg KQ_RASTER_OK (0), sonst einen Fehlerstatus von 1 bis 4. Beachten Sie die Funktionsbedingungen und Raster_GetLastError.
Bedingungen und Grenzen
Binden Sie raster.h ein und kompilieren Sie raster.c zusammen mit scroll.c. Eine gemeinsame Tabelle fasst bis zu acht Bänder. Mischen Sie beim Aufbau mit Raster_* keine direkten Aufrufe von Scroll_Split* oder __scroll_split_* ein: Sie umgehen die Zählung und die Verwaltung der letzten Zeile im Wrapper.
Bauen Sie die Tabelle während VBlank oder in einem anderen Zeitraum mit kontrollierbarer Bildwirkung neu auf: leeren, Einträge hinzufügen, aktivieren. Das Leeren stoppt auch aktive Teilungen; es wird kein unabhängiger Hintergrundpuffer bearbeitet. LY plant einen Interrupt, Registerzugriffe benötigen zusätzliche Zeit. Für Wellen pro Rasterzeile verwenden Sie die separate Familie Raster_LineX*; betreiben Sie nicht beide Treiber gleichzeitig.
Die Statuscodes sind 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED und 4 BAD_RANGE. Beim Hinzufügen werden LY-Bereich, Kapazität und Reihenfolge in dieser Reihenfolge geprüft. Ein abgelehnter Eintrag vergrößert die Tabelle nicht. Ein späterer erfolgreicher Eintrag oder das Leeren setzt den Fehler auf null zurück; prüfen Sie daher jeden Rückgabewert unmittelbar.
Farbänderungen nutzen BCPS/BCPD und erhalten den bisherigen BCPS-Index nicht. Setzen Sie den Index ausdrücklich, wenn auch der Hauptcode Paletten schreibt. Der Handler wartet auf einen zugänglichen LCD-Modus; die sichtbare Farbgrenze kann daher nach der geplanten LY-Zeile liegen.
Anwendungsbeispiel
Raster_PushBgColor0(0,0x7C00);Raster_PushBgColor0(64,0x001F);Raster_PushBgColor0(112,0x03E0);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
In der geprüften CGB-Aufnahme bei normaler Geschwindigkeit sind Zeilen 0..65 blau, 66..113 rot und 114..143 grün. Geplant sind LY 0, 64 und 112; Interrupt- und Palettenzugriffslatenz beeinflussen die sichtbaren Grenzen. Eine DMG-Farbversion gibt es nicht.

Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Aktualisiert Hintergrundscroll und Fensterkoordinaten in einem Band. Der Wrapper ergänzt BG und WIN und wandelt Fenster-Bildschirm-X in WX um.
Syntax
u8 Raster_PushBgWindowScreen(u8 ly, u8 scx, u8 scy, u8 screen_x, u8 screen_y, u8 flags);Parameter
lyGeplante sichtbare Zeile in 0..143, strikt größer als die vorherige Tabellenzeile. Ein erster Eintrag bei LY=0 wird in der VBlank-Behandlung angewendet und legt den Zustand am Frameanfang fest.
scxHintergrund-Scrollbyte in 0..255. SCX/SCY geben die Leseposition in der Hintergrundkarte an, keine Bildschirmposition. Die Koordinaten laufen innerhalb des 256-Pixel-Hintergrunds zyklisch um.
scyHintergrund-Scrollbyte in 0..255. SCX/SCY geben die Leseposition in der Hintergrundkarte an, keine Bildschirmposition. Die Koordinaten laufen innerhalb des 256-Pixel-Hintergrunds zyklisch um.
screen_xBildschirm-X-Koordinate des linken Fensterrands. Der Wrapper addiert sieben, um WX zu bilden. Verwenden Sie normalerweise 0..159. Werte ab 249 laufen bei der Byteaddition über; nutzen Sie sie nicht zum Verstecken des Fensters.
screen_yFenster-WY in Pixeln ab dem oberen Rand. Anders als bei X wird zu Y keine sieben addiert. WY-Werte ab 144 haben keine Startzeile im sichtbaren Bereich.
flagsÜbergeben Sie normalerweise WIN_SHOW oder WIN_HIDE. Der Wrapper ergänzt WIN; null genügt daher zum Ändern der Koordinaten ohne Änderung der Sichtbarkeit. Andere unterstützte Bits werden weitergereicht. Vermeiden Sie unbeabsichtigte BG- oder Farboperationen.
Rückgabewert
Liefert bei Erfolg KQ_RASTER_OK (0), sonst einen Fehlerstatus von 1 bis 4. Beachten Sie die Funktionsbedingungen und Raster_GetLastError.
Bedingungen und Grenzen
Binden Sie raster.h ein und kompilieren Sie raster.c zusammen mit scroll.c. Eine gemeinsame Tabelle fasst bis zu acht Bänder. Mischen Sie beim Aufbau mit Raster_* keine direkten Aufrufe von Scroll_Split* oder __scroll_split_* ein: Sie umgehen die Zählung und die Verwaltung der letzten Zeile im Wrapper.
Bauen Sie die Tabelle während VBlank oder in einem anderen Zeitraum mit kontrollierbarer Bildwirkung neu auf: leeren, Einträge hinzufügen, aktivieren. Das Leeren stoppt auch aktive Teilungen; es wird kein unabhängiger Hintergrundpuffer bearbeitet. LY plant einen Interrupt, Registerzugriffe benötigen zusätzliche Zeit. Für Wellen pro Rasterzeile verwenden Sie die separate Familie Raster_LineX*; betreiben Sie nicht beide Treiber gleichzeitig.
Die Statuscodes sind 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED und 4 BAD_RANGE. Beim Hinzufügen werden LY-Bereich, Kapazität und Reihenfolge in dieser Reihenfolge geprüft. Ein abgelehnter Eintrag vergrößert die Tabelle nicht. Ein späterer erfolgreicher Eintrag oder das Leeren setzt den Fehler auf null zurück; prüfen Sie daher jeden Rückgabewert unmittelbar.
Anwendungsbeispiel
Raster_PushBgWindowScreen(0,8,0,24,48,KQ_RASTER_WIN_SHOW);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Hintergrund-X=8 verschiebt das rote Hintergrundrechteck nach (24,16). Der Fensterursprung bleibt bei (24,48), sein blaues Rechteck damit bei (32,56). Dies zeigt die unabhängigen Koordinatensysteme.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Fügt ein erweitertes Band mit den durch Flags gewählten Hintergrund-, Fenster-, Sichtbarkeits- oder Farboperationen hinzu. Für reine Hintergrundänderungen nutzen Sie Raster_Push mit weniger Argumenten.
Syntax
u8 Raster_PushEx(u8 ly, u8 scx, u8 scy, u8 wx, u8 wy, u8 flags);Parameter
lyGeplante sichtbare Zeile in 0..143, strikt größer als die vorherige Tabellenzeile. Ein erster Eintrag bei LY=0 wird in der VBlank-Behandlung angewendet und legt den Zustand am Frameanfang fest.
scxHintergrund-Scrollbyte in 0..255. SCX/SCY geben die Leseposition in der Hintergrundkarte an, keine Bildschirmposition. Die Koordinaten laufen innerhalb des 256-Pixel-Hintergrunds zyklisch um.
scyHintergrund-Scrollbyte in 0..255. SCX/SCY geben die Leseposition in der Hintergrundkarte an, keine Bildschirmposition. Die Koordinaten laufen innerhalb des 256-Pixel-Hintergrunds zyklisch um.
wxRoher Hardwarewert WX. Addieren Sie sieben zur normalen Bildschirm-X-Koordinate; WX=7 setzt das Fenster an den linken Rand. Die Funktion begrenzt oder prüft WX nicht.
wyFenster-WY in Pixeln ab dem oberen Rand. Anders als bei X wird zu Y keine sieben addiert. WY-Werte ab 144 haben keine Startzeile im sichtbaren Bereich.
flagsFlags: BG=1 aktualisiert den Hintergrundscroll, WIN=2 WX/WY, WIN_SHOW=4 zeigt das Fenster, WIN_HIDE=8 verbirgt es, BG_COLOR0=16 aktualisiert CGB-Hintergrundfarbe null. Unbekannte obere Bits werden verworfen. Sind SHOW und HIDE gesetzt, wird SHOW zuletzt angewendet. Farbänderungen verwenden die Datenfelder SCX/SCY erneut; kombinieren Sie sie nicht mit normalem Hintergrundscrollen.
Rückgabewert
Liefert bei Erfolg KQ_RASTER_OK (0), sonst einen Fehlerstatus von 1 bis 4. Beachten Sie die Funktionsbedingungen und Raster_GetLastError.
Bedingungen und Grenzen
Binden Sie raster.h ein und kompilieren Sie raster.c zusammen mit scroll.c. Eine gemeinsame Tabelle fasst bis zu acht Bänder. Mischen Sie beim Aufbau mit Raster_* keine direkten Aufrufe von Scroll_Split* oder __scroll_split_* ein: Sie umgehen die Zählung und die Verwaltung der letzten Zeile im Wrapper.
Bauen Sie die Tabelle während VBlank oder in einem anderen Zeitraum mit kontrollierbarer Bildwirkung neu auf: leeren, Einträge hinzufügen, aktivieren. Das Leeren stoppt auch aktive Teilungen; es wird kein unabhängiger Hintergrundpuffer bearbeitet. LY plant einen Interrupt, Registerzugriffe benötigen zusätzliche Zeit. Für Wellen pro Rasterzeile verwenden Sie die separate Familie Raster_LineX*; betreiben Sie nicht beide Treiber gleichzeitig.
Die Statuscodes sind 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED und 4 BAD_RANGE. Beim Hinzufügen werden LY-Bereich, Kapazität und Reihenfolge in dieser Reihenfolge geprüft. Ein abgelehnter Eintrag vergrößert die Tabelle nicht. Ein späterer erfolgreicher Eintrag oder das Leeren setzt den Fehler auf null zurück; prüfen Sie daher jeden Rückgabewert unmittelbar.
Anwendungsbeispiel
Raster_PushEx(104,16,0,7,0,KQ_RASTER_BG|KQ_RASTER_WIN_HIDE);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Rote Rechtecke von jeweils 24x16 Pixeln, auf DMG schwarz, erscheinen bei (32,16), (24,80) und (16,112). Tiefere Bänder werden weiter nach links verschoben. Intern werden Anzahl 3, Fehler 0 und Aktivierungsergebnis 0 gespeichert.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Fügt ein Fensterband mit rohen Hardwarewerten WX/WY hinzu. Ergänzt automatisch WIN und übergibt null für beide Hintergrund-Datenbytes.
Syntax
u8 Raster_PushWindowRaw(u8 ly, u8 wx, u8 wy, u8 flags);Parameter
lyGeplante sichtbare Zeile in 0..143, strikt größer als die vorherige Tabellenzeile. Ein erster Eintrag bei LY=0 wird in der VBlank-Behandlung angewendet und legt den Zustand am Frameanfang fest.
wxRoher Hardwarewert WX. Addieren Sie sieben zur normalen Bildschirm-X-Koordinate; WX=7 setzt das Fenster an den linken Rand. Die Funktion begrenzt oder prüft WX nicht.
wyFenster-WY in Pixeln ab dem oberen Rand. Anders als bei X wird zu Y keine sieben addiert. WY-Werte ab 144 haben keine Startzeile im sichtbaren Bereich.
flagsÜbergeben Sie normalerweise WIN_SHOW oder WIN_HIDE. Der Wrapper ergänzt WIN; null genügt daher zum Ändern der Koordinaten ohne Änderung der Sichtbarkeit. Andere unterstützte Bits werden weitergereicht. Vermeiden Sie unbeabsichtigte BG- oder Farboperationen.
Rückgabewert
Liefert bei Erfolg KQ_RASTER_OK (0), sonst einen Fehlerstatus von 1 bis 4. Beachten Sie die Funktionsbedingungen und Raster_GetLastError.
Bedingungen und Grenzen
Binden Sie raster.h ein und kompilieren Sie raster.c zusammen mit scroll.c. Eine gemeinsame Tabelle fasst bis zu acht Bänder. Mischen Sie beim Aufbau mit Raster_* keine direkten Aufrufe von Scroll_Split* oder __scroll_split_* ein: Sie umgehen die Zählung und die Verwaltung der letzten Zeile im Wrapper.
Bauen Sie die Tabelle während VBlank oder in einem anderen Zeitraum mit kontrollierbarer Bildwirkung neu auf: leeren, Einträge hinzufügen, aktivieren. Das Leeren stoppt auch aktive Teilungen; es wird kein unabhängiger Hintergrundpuffer bearbeitet. LY plant einen Interrupt, Registerzugriffe benötigen zusätzliche Zeit. Für Wellen pro Rasterzeile verwenden Sie die separate Familie Raster_LineX*; betreiben Sie nicht beide Treiber gleichzeitig.
Die Statuscodes sind 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED und 4 BAD_RANGE. Beim Hinzufügen werden LY-Bereich, Kapazität und Reihenfolge in dieser Reihenfolge geprüft. Ein abgelehnter Eintrag vergrößert die Tabelle nicht. Ein späterer erfolgreicher Eintrag oder das Leeren setzt den Fehler auf null zurück; prüfen Sie daher jeden Rückgabewert unmittelbar.
Anwendungsbeispiel
Raster_PushWindowRaw(0,31,48,KQ_RASTER_WIN_SHOW);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
WX=31 und WY=48 legen den Fensterursprung auf Bildschirmposition (24,48). Das blaue 16x16-Rechteck an lokaler Position (8,8) erscheint bei (32,56). Das obere rote Hintergrundrechteck bleibt bei (32,16). Auf dem DMG sind beide schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Fügt ein Fensterband in Bildschirmkoordinaten hinzu. Addiert vor dem Aufruf der Rohwertvariante sieben zu X, damit Bildschirm-X und WX beim Positionieren nicht verwechselt werden.
Syntax
u8 Raster_PushWindowScreen(u8 ly, u8 screen_x, u8 screen_y, u8 flags);Parameter
lyGeplante sichtbare Zeile in 0..143, strikt größer als die vorherige Tabellenzeile. Ein erster Eintrag bei LY=0 wird in der VBlank-Behandlung angewendet und legt den Zustand am Frameanfang fest.
screen_xBildschirm-X-Koordinate des linken Fensterrands. Der Wrapper addiert sieben, um WX zu bilden. Verwenden Sie normalerweise 0..159. Werte ab 249 laufen bei der Byteaddition über; nutzen Sie sie nicht zum Verstecken des Fensters.
screen_yFenster-WY in Pixeln ab dem oberen Rand. Anders als bei X wird zu Y keine sieben addiert. WY-Werte ab 144 haben keine Startzeile im sichtbaren Bereich.
flagsÜbergeben Sie normalerweise WIN_SHOW oder WIN_HIDE. Der Wrapper ergänzt WIN; null genügt daher zum Ändern der Koordinaten ohne Änderung der Sichtbarkeit. Andere unterstützte Bits werden weitergereicht. Vermeiden Sie unbeabsichtigte BG- oder Farboperationen.
Rückgabewert
Liefert bei Erfolg KQ_RASTER_OK (0), sonst einen Fehlerstatus von 1 bis 4. Beachten Sie die Funktionsbedingungen und Raster_GetLastError.
Bedingungen und Grenzen
Binden Sie raster.h ein und kompilieren Sie raster.c zusammen mit scroll.c. Eine gemeinsame Tabelle fasst bis zu acht Bänder. Mischen Sie beim Aufbau mit Raster_* keine direkten Aufrufe von Scroll_Split* oder __scroll_split_* ein: Sie umgehen die Zählung und die Verwaltung der letzten Zeile im Wrapper.
Bauen Sie die Tabelle während VBlank oder in einem anderen Zeitraum mit kontrollierbarer Bildwirkung neu auf: leeren, Einträge hinzufügen, aktivieren. Das Leeren stoppt auch aktive Teilungen; es wird kein unabhängiger Hintergrundpuffer bearbeitet. LY plant einen Interrupt, Registerzugriffe benötigen zusätzliche Zeit. Für Wellen pro Rasterzeile verwenden Sie die separate Familie Raster_LineX*; betreiben Sie nicht beide Treiber gleichzeitig.
Die Statuscodes sind 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED und 4 BAD_RANGE. Beim Hinzufügen werden LY-Bereich, Kapazität und Reihenfolge in dieser Reihenfolge geprüft. Ein abgelehnter Eintrag vergrößert die Tabelle nicht. Ein späterer erfolgreicher Eintrag oder das Leeren setzt den Fehler auf null zurück; prüfen Sie daher jeden Rückgabewert unmittelbar.
Anwendungsbeispiel
Raster_PushWindowScreen(0,24,48,KQ_RASTER_WIN_SHOW);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Die direkte Übergabe der Bildschirmkoordinaten (24,48) erzeugt dasselbe blaue Fensterrechteck bei (32,56) wie das Beispiel mit Rohwerten. Die Bibliothek addiert sieben zu X. Das obere rote Hintergrundrechteck liegt bei (32,16).


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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 — Zufallszahlen, Text, Karten, Spielstände und RPG-/ADV-/SLG-Funktionen
Die Texthelfer mit absoluten Positionen zeichnen direkt auf die Hintergrundkarte. text_window öffnet einen umrahmten Bereich, text_clear_rect füllt eine Region und text_print_xy schreibt Tile-Bytes ohne Steuercodeauswertung. text_print_u8, text_print_u16 und text_print_s16 wandeln Zahlen in Dezimaldarstellung um und belegen nur die nötigen Zellen. Reservieren und löschen Sie beim Ersetzen unterschiedlich langer Werte das gesamte Feld.
Die in rpg.h deklarierten RNG-Funktionen sind in lib/rng.c implementiert. Sie teilen den GB-Generator des Compilers: rng_seed setzt ihn zurück, rng8/rng_next8 verbrauchen ein Byte, rng16/rng_next16 zwei, und rand_range/rng_range, rng_chance sowie weighted_choice passen Ziehungen an Spielentscheidungen an. Kompilieren Sie rng.c mit dem Programm, wenn Sie diese Funktionen aufrufen. Reproduzierbare Tests benötigen festen Startwert und Aufrufreihenfolge; modulo-basierte Auswahlen garantieren keine exakten Wahrscheinlichkeiten.
RLE-Decodierung verwendet count/value-Bytepaare und count null als Abschluss. rle_decode liest einen normalen Zeiger und schreibt in RAM; rle_decode_far liest einen Zeiger mit ROM-Bankangabe nach RAM; __rle_decode_vram entpackt Bankdaten mit LCD-gerechten Schreibzugriffen direkt in VRAM. Die RAM-Funktionen liegen in lib/rle.c, die direkte VRAM-Operation wird vom Compiler erzeugt. Alle drei liefern die Anzahl ausgegebener Bytes und benötigen einen gültigen Strom sowie genügend Zielspeicher.
Den in rpg.h deklarierten Spielzustandsspeicher implementiert lib/flags.c. Die drei Flagfunktionen arbeiten auf 2048 unabhängigen booleschen Bits; quest_state und quest_set_state auf 64 unabhängigen Bytes für spieldefinierte Stufen. Kompilieren Sie flags.c bei der Nutzung, beachten Sie die ID-Grenzen und verwenden Sie ein separates Speichersystem, wenn Fortschritt das Ausschalten überdauern soll.
Fensterdialoge teilen sich ein aktives Rechteck, einen Cursor und eine Zeichengeschwindigkeit. text_open initialisiert den Bereich, text_close löscht ihn und text_set_speed setzt VBlank-Warten je Zeichen. text_print und text_print_far interpretieren Steuerströme; text_choice führt eine blockierende vertikale Auswahl aus. Laden Sie Kacheln, dimensionieren Sie den Bereich und planen Sie den Umgang mit blockierenden Aufrufen im Spiel.
Bietet Karten-/Metakachelzeichnung, Skripte, SRAM-Spielstände und Wegsuche. Gewöhnliche Zellen sind 8×8 Pixel groß, Metakacheln 16×16. Laden/Zeichnen, Bewegungs- und Angriffsmasken sind getrennte Operationen; das Spiel koordiniert Grafikladen und Ereignisausführung.
Die Suche verwendet etwa 4 KiB gemeinsamen, nicht reentranten Arbeitsspeicher. Begrenzen Sie Karten auf 1024 Zellen und untersuchte Entfernungen auf 254. Distanz 0xFF bedeutet „nicht erreicht“; eine Route mit 255 Schritten ist daher nicht darstellbar. Kosten- und Maskenausgaben benötigen width*height beschreibbare Bytes.
Standardmäßig gibt es vier 512-Byte-Slots mit je sechs Headerbytes und bis zu 506 Nutzdatenbytes. Das Beispiel verwendet MBC5 mit 8 KiB SRAM. Aufrufe enden mit deaktiviertem RAM, ohne die vorherige Bank oder den Aktivierungszustand wiederherzustellen.
Menüs unterstützen sowohl eine blockierende Auswahl als auch getrennte Eingabe- und Zeichenaufrufe aus der Spielschleife. Das Inventarmenü zeigt Gegenstandsnamen und Mengen an.
camera_center
Zentriert eine Zelle einer gewöhnlichen Karte in einem Ausschnitt von 20×18 Kacheln, begrenzt durch die Kartenränder.
Syntax
void camera_center(u8 x, u8 y);Parameter
xX-Koordinate der Zelle.
yY-Koordinate der Zelle.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Der Ursprung beginnt bei max(x−10,0), max(y−9,0), wird auf die Kartengrenzen begrenzt und schreibt dann die unteren Bytes von Ursprung*8 nach SCX/SCY. Im Metakachelmodus wird dies nicht angewandt. Neue Zeilen oder Spalten werden nicht in den VRAM nachgeladen.
Anwendungsbeispiel
camera_center(5,4);result[9]=*((u8*)0xFF43);result[10]=*((u8*)0xFF42);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das linke Raster zeigt Bewegungskosten innerhalb von drei Schritten, das rechte eine kürzeste Route von S nach G. Grüne Sternchen markieren neun Schritte um eine rote Wand aus drei Zellen; blaue Ziffern zeigen Kosten. Auf dem DMG erscheint dieselbe Anordnung schwarz. RAM-Prüfungen zeigen außerdem, dass die Angriffsmaske Wände ignoriert.


Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Liest ein Little-Endian-Wort über einen Zeiger mit Bankangabe.
Syntax
#define far_read16(p) __farpeek16((p).bank, (p).ptr)Parameter
pfar_ptr_t mit bank und ptr, wobei ptr eine CPU-sichtbare Adresse ist.
Rückgabewert
Das Wort als u16.
Bedingungen und Grenzen
Das Makro liest p.bank und p.ptr getrennt; übergeben Sie keinen Ausdruck mit Seiteneffekten. Die intrinsische Funktion wählt die ROM-Bank vorübergehend und stellt sie wieder her. Vermeiden Sie gleichzeitige Bankwechsel aus Interrupts.
Anwendungsbeispiel
result[1]=far_read16(far);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Lesen Sie die Hexadezimalwerte 34 12 AB aus einer anderen ROM-Bank: erstes Byte 52, Little-Endian-Wort 4660 und letztes kopiertes Byte 171.


Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
kitaqgb/lib/rpg.h:172
far_read8
Liest ein Byte über einen Zeiger mit Bankangabe.
Syntax
#define far_read8(p) __farpeek8((p).bank, (p).ptr)Parameter
pfar_ptr_t mit bank und ptr, wobei ptr eine CPU-sichtbare Adresse ist.
Rückgabewert
Das Byte als u8.
Bedingungen und Grenzen
Das Makro liest p.bank und p.ptr getrennt; übergeben Sie keinen Ausdruck mit Seiteneffekten. Die intrinsische Funktion wählt die ROM-Bank vorübergehend und stellt sie wieder her. Vermeiden Sie gleichzeitige Bankwechsel aus Interrupts.
Anwendungsbeispiel
far.bank=1;far.ptr=bank_bytes;result[0]=far_read8(far);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Lesen Sie die Hexadezimalwerte 34 12 AB aus einer anderen ROM-Bank: erstes Byte 52, Little-Endian-Wort 4660 und letztes kopiertes Byte 171.


Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
kitaqgb/lib/rpg.h:171
far_read_block
Kopiert aufeinanderfolgende Bytes von einem Zeiger mit Bankangabe in den RAM.
Syntax
#define far_read_block(dst, p, len) __farmemcpy((dst), (p).bank, (p).ptr, (len))Parameter
dstBeginn von len beschreibbaren RAM-Bytes.
pfar_ptr_t mit bank und ptr, wobei ptr eine CPU-sichtbare Adresse ist.
lenByte-Anzahl; der gesamte Quellbereich muss innerhalb seiner Bank bleiben.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Makro zur Weiterleitung an __farmemcpy. Überschreitet ROM-Bankgrenzen nicht automatisch und ist keine Verschiebeoperation für überlappende Speicherbereiche.
Anwendungsbeispiel
far_read_block(copy,far,3);result[2]=copy[2];Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Lesen Sie die Hexadezimalwerte 34 12 AB aus einer anderen ROM-Bank: erstes Byte 52, Little-Endian-Wort 4660 und letztes kopiertes Byte 171.


Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
kitaqgb/lib/rpg.h:173
flag_clear
Löscht ein Spielflag auf 0, ohne benachbarte Flags zu löschen. Verwenden Sie dies beim Aufheben einer Ereignisbedingung oder zur ausdrücklichen Initialisierung eines Flags. Ein bereits gelöschtes Flag bleibt null.
Syntax
void flag_clear(u16 id);Parameter
idFlagnummer von 0 bis 2047, als u16 übergeben. Der Byteoffset ist id / 8, die Bitposition darin id % 8, beginnend beim niederwertigsten Bit. Der breitere Parametertyp vergrößert den festen Speicher für 2048 Flags nicht.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Die Funktion prüft die ID nicht. Halten Sie Flag-IDs unter 2048 und Aufgaben-IDs unter 64. Zugriffe außerhalb des Bereichs können fremde RAM-Inhalte lesen oder überschreiben. Die Beispiele initialisieren ausdrücklich, statt sich auf Anfangsinhalte zu verlassen.
flags.c besitzt 256 RAM-Bytes für Flags und weitere 64 Bytes für Aufgaben. Diese Funktionen greifen nicht auf Cartridge-Speicher-RAM zu und erhalten keine Daten über das Ausschalten hinweg. Für dauerhaften Fortschritt muss das Spiel Flag- und Aufgabenwerte über sein Speichersystem serialisieren und beim Laden wiederherstellen.
Binden Sie rpg.h ein und kompilieren Sie lib/flags.c mit dem Spiel. Die Arrays sind innerhalb dieser Quelldatei privat; verwenden Sie die Flag- und Aufgaben-APIs zum Zugriff. Alle Aufrufer teilen sich den Speicher. Koordinieren Sie daher Schreibzugriffe aus Hauptschleife und Interrupt-Handlern selbst.
Anwendungsbeispiel
flag_clear(9);flag_clear(9); // Mark it closed; clearing twice still leaves 0.
cleared=flag_get(9);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel löscht Türflag 9 nach dem Setzen. DOOR CLOSED zeigt 000, obwohl zweimal gelöscht wird. Der zuvor beobachtete Wert DOOR OPEN 001 bleibt sichtbar, sodass sich beide gespeicherten Beobachtungen vergleichen lassen.
Das vollständige Programm zeigt Dezimalergebnisse auf Weiß: auf DMG mit schwarzem, auf CGB mit blauem Text. FAILED muss 000 sein. Die Aufnahmen zeigen nur das Verhalten der RAM-Zustände und belegen kein Speichern eines Spiels.
Die Prüfung im DMG-Emulator deckte alle Flag-IDs von 0 bis 2047, wiederholtes Setzen und Löschen, benachbarte Einträge sowie alle 256 Zustandswerte jeder der 64 Aufgaben ab. Ein abschließendes Muster aus 256 Flagbytes und 64 Aufgabenbytes wurde mit den erwarteten Daten verglichen. Beide Lehrbildschirme wurden nach 240 Frames geprüft. Echte Hardware und dauerhafte Speicherung wurden nicht getestet.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Liest ein Ein/Aus-Spielflag aus dem RAM-Bitarray der Bibliothek. Damit fragen Sie ab, ob eine Tür offen ist, ein Gegenstand gesammelt wurde oder ein anderes vom Spiel definiertes Ereignis eingetreten ist. Lesen verändert das Flag nicht.
Syntax
u8 flag_get(u16 id);Parameter
idFlagnummer von 0 bis 2047, als u16 übergeben. Der Byteoffset ist id / 8, die Bitposition darin id % 8, beginnend beim niederwertigsten Bit. Der breitere Parametertyp vergrößert den festen Speicher für 2048 Flags nicht.
Rückgabewert
Normalisierter boolescher u8-Wert: 0 bei gelöschtem, 1 bei gesetztem Flag. Diese GB-Bibliothek ruft das GB-Intrinsic __bit_test auf, das das Ergebnis normalisiert.
Bedingungen und Grenzen
Die Funktion prüft die ID nicht. Halten Sie Flag-IDs unter 2048 und Aufgaben-IDs unter 64. Zugriffe außerhalb des Bereichs können fremde RAM-Inhalte lesen oder überschreiben. Die Beispiele initialisieren ausdrücklich, statt sich auf Anfangsinhalte zu verlassen.
flags.c besitzt 256 RAM-Bytes für Flags und weitere 64 Bytes für Aufgaben. Diese Funktionen greifen nicht auf Cartridge-Speicher-RAM zu und erhalten keine Daten über das Ausschalten hinweg. Für dauerhaften Fortschritt muss das Spiel Flag- und Aufgabenwerte über sein Speichersystem serialisieren und beim Laden wiederherstellen.
Binden Sie rpg.h ein und kompilieren Sie lib/flags.c mit dem Spiel. Die Arrays sind innerhalb dieser Quelldatei privat; verwenden Sie die Flag- und Aufgaben-APIs zum Zugriff. Alle Aufrufer teilen sich den Speicher. Koordinieren Sie daher Schreibzugriffe aus Hauptschleife und Interrupt-Handlern selbst.
Anwendungsbeispiel
before=flag_get(9); // Door-open flag: 0 after explicit initialization.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel ordnet Flag 9 einer Tür zu. Nach ausdrücklichem Löschen zeigt BEFORE 000. Späteres Setzen und Löschen ergibt DOOR OPEN 001 und DOOR CLOSED 000 und zeigt damit, dass Abfragen den gespeicherten Zustand wiedergeben.
Das vollständige Programm zeigt Dezimalergebnisse auf Weiß: auf DMG mit schwarzem, auf CGB mit blauem Text. FAILED muss 000 sein. Die Aufnahmen zeigen nur das Verhalten der RAM-Zustände und belegen kein Speichern eines Spiels.
Die Prüfung im DMG-Emulator deckte alle Flag-IDs von 0 bis 2047, wiederholtes Setzen und Löschen, benachbarte Einträge sowie alle 256 Zustandswerte jeder der 64 Aufgaben ab. Ein abschließendes Muster aus 256 Flagbytes und 64 Aufgabenbytes wurde mit den erwarteten Daten verglichen. Beide Lehrbildschirme wurden nach 240 Frames geprüft. Echte Hardware und dauerhafte Speicherung wurden nicht getestet.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Setzt ein Spielflag auf 1 und bewahrt die sieben anderen Flags desselben Bytes. Ein bereits gesetztes Flag bleibt gesetzt. Damit lassen sich einmalige Ereignisse wie das Öffnen einer Tür vermerken.
Syntax
void flag_set(u16 id);Parameter
idFlagnummer von 0 bis 2047, als u16 übergeben. Der Byteoffset ist id / 8, die Bitposition darin id % 8, beginnend beim niederwertigsten Bit. Der breitere Parametertyp vergrößert den festen Speicher für 2048 Flags nicht.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Die Funktion prüft die ID nicht. Halten Sie Flag-IDs unter 2048 und Aufgaben-IDs unter 64. Zugriffe außerhalb des Bereichs können fremde RAM-Inhalte lesen oder überschreiben. Die Beispiele initialisieren ausdrücklich, statt sich auf Anfangsinhalte zu verlassen.
flags.c besitzt 256 RAM-Bytes für Flags und weitere 64 Bytes für Aufgaben. Diese Funktionen greifen nicht auf Cartridge-Speicher-RAM zu und erhalten keine Daten über das Ausschalten hinweg. Für dauerhaften Fortschritt muss das Spiel Flag- und Aufgabenwerte über sein Speichersystem serialisieren und beim Laden wiederherstellen.
Binden Sie rpg.h ein und kompilieren Sie lib/flags.c mit dem Spiel. Die Arrays sind innerhalb dieser Quelldatei privat; verwenden Sie die Flag- und Aufgaben-APIs zum Zugriff. Alle Aufrufer teilen sich den Speicher. Koordinieren Sie daher Schreibzugriffe aus Hauptschleife und Interrupt-Handlern selbst.
Anwendungsbeispiel
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.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel setzt Türflag 9 zweimal. DOOR OPEN zeigt 001, während das benachbarte Flag 8 bei NEIGHBOR 000 bleibt. Beide Flags liegen im selben Byte. Der Nachbarwert zeigt daher, dass das Setzen eines Flags das andere bewahrt.
Das vollständige Programm zeigt Dezimalergebnisse auf Weiß: auf DMG mit schwarzem, auf CGB mit blauem Text. FAILED muss 000 sein. Die Aufnahmen zeigen nur das Verhalten der RAM-Zustände und belegen kein Speichern eines Spiels.
Die Prüfung im DMG-Emulator deckte alle Flag-IDs von 0 bis 2047, wiederholtes Setzen und Löschen, benachbarte Einträge sowie alle 256 Zustandswerte jeder der 64 Aufgaben ab. Ein abschließendes Muster aus 256 Flagbytes und 64 Aufgabenbytes wurde mit den erwarteten Daten verglichen. Beide Lehrbildschirme wurden nach 240 Frames geprüft. Echte Hardware und dauerhafte Speicherung wurden nicht getestet.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Liest die Höhe der aktiven Karte.
Syntax
u8 map_current_height();Rückgabewert
Gibt die Höhe in Zellen zurück oder null, wenn keine Karte geladen ist.
Bedingungen und Grenzen
Koordinaten bezeichnen Zellen der aktuellen Karte: 8×8 Pixel bei gewöhnlichen Kacheln, 16×16 Pixel bei Metakacheln.
Anwendungsbeispiel
result[1]=map_current_height();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das linke Raster zeigt Bewegungskosten innerhalb von drei Schritten, das rechte eine kürzeste Route von S nach G. Grüne Sternchen markieren neun Schritte um eine rote Wand aus drei Zellen; blaue Ziffern zeigen Kosten. Auf dem DMG erscheint dieselbe Anordnung schwarz. RAM-Prüfungen zeigen außerdem, dass die Angriffsmaske Wände ignoriert.


Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Liest die Breite der aktiven Karte.
Syntax
u8 map_current_width();Rückgabewert
Gibt die Breite in Zellen zurück oder null, wenn keine Karte geladen ist.
Bedingungen und Grenzen
Koordinaten bezeichnen Zellen der aktuellen Karte: 8×8 Pixel bei gewöhnlichen Kacheln, 16×16 Pixel bei Metakacheln.
Anwendungsbeispiel
result[0]=map_current_width();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das linke Raster zeigt Bewegungskosten innerhalb von drei Schritten, das rechte eine kürzeste Route von S nach G. Grüne Sternchen markieren neun Schritte um eine rote Wand aus drei Zellen; blaue Ziffern zeigen Kosten. Auf dem DMG erscheint dieselbe Anordnung schwarz. RAM-Prüfungen zeigen außerdem, dass die Angriffsmaske Wände ignoriert.


Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Zeichnet 10×9 Metakacheln ab dem gewünschten Ursprung und merkt sich diese Kameraposition für Neuzeichnungen nach Änderungen.
Syntax
void map_draw_visible(u8 camera_tx, u8 camera_ty);Parameter
camera_txX der äußersten linken Zelle; höchstens 246, um einen Byte-Überlauf beim Durchlaufen zu vermeiden.
camera_tyY der obersten Zelle; höchstens 247.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Zellen außerhalb zeichnen Metakachel-ID null; stellen Sie daher immer Definition null bereit. Der Aufruf lässt Zellen außerhalb des 20×18-Kachelausschnitts und CGB-Attribute unverändert.
Anwendungsbeispiel
map_draw_visible(1,0);result[9]=*((u8*)0x9800);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Ändern Sie eine Metakachel-ID im RAM, markieren Sie die Änderung und übertragen Sie sie. Kamera (1,0) zeigt links oben ein grünes 16×16-Quadrat. Das Beispiel wendet Palettenmetadaten ausdrücklich auf CGB-Attribute an. Auf dem DMG erscheint ein schwarzes Quadrat.


Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Zeichnet bei gesetztem Änderungsflag den Ausschnitt am gespeicherten Kameraursprung neu und löscht das Flag.
Syntax
void map_flush_dirty();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Tut ohne Änderungsmarkierung nichts. Das Neuzeichnen umfasst alle 10×9 Metakacheln, nicht nur die geänderte Zelle.
Anwendungsbeispiel
map_flush_dirty();result[11]=*((u8*)0x9800);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Ändern Sie eine Metakachel-ID im RAM, markieren Sie die Änderung und übertragen Sie sie. Kamera (1,0) zeigt links oben ein grünes 16×16-Quadrat. Das Beispiel wendet Palettenmetadaten ausdrücklich auf CGB-Attribute an. Auf dem DMG erscheint ein schwarzes Quadrat.


Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Liest Palettenmetadaten aus der Metakacheldefinition der Zelle.
Syntax
u8 map_get_attr(u8 tx, u8 ty);Parameter
txMetakachel-X-Koordinate.
tyMetakachel-Y-Koordinate.
Rückgabewert
Gibt das Palettenbyte zurück. Zellen außerhalb nutzen Definition null; ohne Metakachelmodus wird null zurückgegeben.
Bedingungen und Grenzen
Koordinaten bezeichnen Zellen der aktuellen Karte: 8×8 Pixel bei gewöhnlichen Kacheln, 16×16 Pixel bei Metakacheln.
Anwendungsbeispiel
result[3]=map_get_attr(0,0);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Ändern Sie eine Metakachel-ID im RAM, markieren Sie die Änderung und übertragen Sie sie. Kamera (1,0) zeigt links oben ein grünes 16×16-Quadrat. Das Beispiel wendet Palettenmetadaten ausdrücklich auf CGB-Attribute an. Auf dem DMG erscheint ein schwarzes Quadrat.


Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Liest eine Metakachel-Ereignis-ID; gewöhnliche Karten melden das Vorhandensein eines Ereignisses.
Syntax
u8 map_get_event(u8 tx, u8 ty);Parameter
txMetakachel-X-Koordinate.
tyMetakachel-Y-Koordinate.
Rückgabewert
Gibt das Metakachel-Ereignisbyte oder den booleschen Wert der gewöhnlichen Karte zurück; bei fehlender Karte oder Zellen außerhalb null.
Bedingungen und Grenzen
Koordinaten bezeichnen Zellen der aktuellen Karte: 8×8 Pixel bei gewöhnlichen Kacheln, 16×16 Pixel bei Metakacheln.
Anwendungsbeispiel
result[7]=map_get_event(0,0);result[8]=map_get_event(3,0);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Ändern Sie eine Metakachel-ID im RAM, markieren Sie die Änderung und übertragen Sie sie. Kamera (1,0) zeigt links oben ein grünes 16×16-Quadrat. Das Beispiel wendet Palettenmetadaten ausdrücklich auf CGB-Attribute an. Auf dem DMG erscheint ein schwarzes Quadrat.


Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Liest die Metakachel-ID einer Zelle.
Syntax
u8 map_get_metatile(u8 tx, u8 ty);Parameter
txMetakachel-X-Koordinate.
tyMetakachel-Y-Koordinate.
Rückgabewert
Gibt die ID zurück, außerhalb der Karte oder ohne Metakachelmodus null.
Bedingungen und Grenzen
Koordinaten bezeichnen Zellen der aktuellen Karte: 8×8 Pixel bei gewöhnlichen Kacheln, 16×16 Pixel bei Metakacheln.
Anwendungsbeispiel
result[1]=map_get_metatile(0,0);result[2]=map_get_metatile(3,0);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Ändern Sie eine Metakachel-ID im RAM, markieren Sie die Änderung und übertragen Sie sie. Kamera (1,0) zeigt links oben ein grünes 16×16-Quadrat. Das Beispiel wendet Palettenmetadaten ausdrücklich auf CGB-Attribute an. Auf dem DMG erscheint ein schwarzes Quadrat.


Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Prüft, ob eine Zielzelle die Bewegung blockiert; der Metakachelmodus nutzt das Feld collision der Definition.
Syntax
u8 map_is_blocked(u8 x, u8 y);Parameter
xX-Koordinate der Zelle.
yY-Koordinate der Zelle.
Rückgabewert
Gibt bei einer Wand, einer Koordinate außerhalb oder fehlender Karte 1 zurück, bei passierbaren Zellen 0. Ein NULL-Kollisionsarray einer gewöhnlichen Karte macht alle Zellen innerhalb der Karte passierbar.
Bedingungen und Grenzen
Koordinaten bezeichnen Zellen der aktuellen Karte: 8×8 Pixel bei gewöhnlichen Kacheln, 16×16 Pixel bei Metakacheln.
Anwendungsbeispiel
result[4]=map_is_blocked(2,2);result[5]=map_is_blocked(6,2);result[6]=map_is_blocked(1,2);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das linke Raster zeigt Bewegungskosten innerhalb von drei Schritten, das rechte eine kürzeste Route von S nach G. Grüne Sternchen markieren neun Schritte um eine rote Wand aus drei Zellen; blaue Ziffern zeigen Kosten. Auf dem DMG erscheint dieselbe Anordnung schwarz. RAM-Prüfungen zeigen außerdem, dass die Angriffsmaske Wände ignoriert.


Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Prüft Solidität und verwendet im gewöhnlichen Kartenmodus die Kollisionsbits.
Syntax
u8 map_is_solid(u8 tx, u8 ty);Parameter
txMetakachel-X-Koordinate.
tyMetakachel-Y-Koordinate.
Rückgabewert
Gibt bei einem Kollisionswert ungleich null oder einer Zelle außerhalb 1 zurück, sonst 0.
Bedingungen und Grenzen
Koordinaten bezeichnen Zellen der aktuellen Karte: 8×8 Pixel bei gewöhnlichen Kacheln, 16×16 Pixel bei Metakacheln.
Anwendungsbeispiel
result[4]=map_is_solid(0,0);result[5]=map_is_solid(1,0);result[6]=map_is_solid(3,0);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Ändern Sie eine Metakachel-ID im RAM, markieren Sie die Änderung und übertragen Sie sie. Kamera (1,0) zeigt links oben ein grünes 16×16-Quadrat. Das Beispiel wendet Palettenmetadaten ausdrücklich auf CGB-Attribute an. Auf dem DMG erscheint ein schwarzes Quadrat.


Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Lädt einen Deskriptor für eine gewöhnliche Karte und zeichnet ab ihrer linken oberen Ecke bis zu 20×18 Kacheln in die gewählte Hintergrundkarte.
Syntax
void map_load(u8 bank, const map_t* map);Parameter
bankROM-Bank für Deskriptor, Kollisionsbits und Ereignisse.
mapGepacktes map_t mit neun Bytes. tiles enthält width*height Kachel-IDs; collision_bits packt Zellen beginnend beim niederwertigsten Bit; events speichert ein Byte je Zelle. Kachellesezugriffe verwenden bank_tiles.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Es gibt eine gemeinsame aktive Karte. Der Deskriptor wird kopiert, seine Arrays müssen jedoch während der gesamten Nutzung lesbar bleiben. Laden Sie Kachelgrafiken getrennt in den VRAM.
Koordinaten bezeichnen Zellen der aktuellen Karte: 8×8 Pixel bei gewöhnlichen Kacheln, 16×16 Pixel bei Metakacheln.
Zellen außerhalb einer kleinen Karte werden nicht gelöscht. Bei gewöhnlichen Karten bedeutet bank_tiles=0 Bank null; die Bank des Deskriptors wird nicht übernommen.
Anwendungsbeispiel
map_load(0,maps);result[2]=map_current_width();result[3]=map_current_height();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das linke Raster zeigt Bewegungskosten innerhalb von drei Schritten, das rechte eine kürzeste Route von S nach G. Grüne Sternchen markieren neun Schritte um eine rote Wand aus drei Zellen; blaue Ziffern zeigen Kosten. Auf dem DMG erscheint dieselbe Anordnung schwarz. RAM-Prüfungen zeigen außerdem, dass die Angriffsmaske Wände ignoriert.


Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Wählt eine Metakachelkarte und erweitert einen Ausschnitt von 10×9 Zellen bei Kamera (0,0) zu 20×18 Kacheln.
Syntax
void map_load_metatile(u8 bank, const metatile_map_t* map);Parameter
bankROM-Bank mit dem Deskriptor.
mapZeiger auf metatile_map_t. Die Abmessungen zählen 16×16-Pixel-Zellen. Er verweist auf ein ID-Array und eine Tabelle aus sieben Byte großen metatile_t-Definitionen.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Es gibt eine gemeinsame aktive Karte. Der Deskriptor wird kopiert, seine Arrays müssen jedoch während der gesamten Nutzung lesbar bleiben. Laden Sie Kachelgrafiken getrennt in den VRAM.
bank_tiles=0 übernimmt die Bank des Deskriptors; ein Wert ungleich null wählt die Bank für IDs und Definitionen. Eine Definition speichert die Kacheln links oben, rechts oben, links unten und rechts unten sowie Kollision, Palette und Ereignis. Beim Zeichnen werden Palettenmetadaten nicht automatisch angewandt.
Anwendungsbeispiel
map_load_metatile(0,&level);result[0]=*((u8*)0x9800);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Ändern Sie eine Metakachel-ID im RAM, markieren Sie die Änderung und übertragen Sie sie. Kamera (1,0) zeigt links oben ein grünes 16×16-Quadrat. Das Beispiel wendet Palettenmetadaten ausdrücklich auf CGB-Attribute an. Auf dem DMG erscheint ein schwarzes Quadrat.


Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Markiert den Ausschnitt zum Neuzeichnen, wenn eine gültige Metakachelkoordinate übergeben wird.
Syntax
void map_mark_dirty(u8 tx, u8 ty);Parameter
txMetakachel-X-Koordinate.
tyMetakachel-Y-Koordinate.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Setzt ein gemeinsames Änderungsflag, statt Einzelzellenaktualisierungen einzureihen. Koordinaten außerhalb werden ignoriert. Der aufrufende Code ändert IDs oder Definitionen getrennt, bevor er die Änderung markiert.
Anwendungsbeispiel
ids[1]=1;map_mark_dirty(1,0);result[10]=*((u8*)0x9800);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Ändern Sie eine Metakachel-ID im RAM, markieren Sie die Änderung und übertragen Sie sie. Kamera (1,0) zeigt links oben ein grünes 16×16-Quadrat. Das Beispiel wendet Palettenmetadaten ausdrücklich auf CGB-Attribute an. Auf dem DMG erscheint ein schwarzes Quadrat.


Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Prüft, ob eine Zelle ein Ereignis hat, ohne es auszuführen.
Syntax
u8 map_trigger_at(u8 x, u8 y);Parameter
xX-Koordinate der Zelle.
yY-Koordinate der Zelle.
Rückgabewert
Gibt bei vorhandenem Ereignis 1 zurück, sonst 0; liefert weder das gespeicherte Ereignisbyte noch die Ereignis-ID einer Metakachel.
Bedingungen und Grenzen
Koordinaten bezeichnen Zellen der aktuellen Karte: 8×8 Pixel bei gewöhnlichen Kacheln, 16×16 Pixel bei Metakacheln.
Anwendungsbeispiel
result[7]=map_trigger_at(5,4);result[8]=map_trigger_at(6,4);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das linke Raster zeigt Bewegungskosten innerhalb von drei Schritten, das rechte eine kürzeste Route von S nach G. Grüne Sternchen markieren neun Schritte um eine rote Wand aus drei Zellen; blaue Ziffern zeigen Kosten. Auf dem DMG erscheint dieselbe Anordnung schwarz. RAM-Prüfungen zeigen außerdem, dass die Angriffsmaske Wände ignoriert.


Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Findet eine kürzeste orthogonale Route und schreibt ihre Richtungen in der Reihenfolge vom Start zum Ziel.
Syntax
u8 path_find_bfs(u8 sx, u8 sy, u8 gx, u8 gy, u8* out_path, u8 max_len);Parameter
sxX der Startzelle innerhalb der Karte.
syY der Startzelle.
gxX der Zielzelle; ein blockiertes Ziel, das vom Ursprung abweicht, wird abgelehnt.
gyY der Zielzelle.
out_pathBeschreibbares Array mit mindestens max_len Bytes; 0=oben, 1=rechts, 2=unten, 3=links.
max_lenAusgabekapazität; eine zu lange Route führt zu einem Fehlschlag, statt abgeschnitten zu werden.
Rückgabewert
Gibt die Routenlänge zurück; null bedeutet unerreichbar, ungültige Koordinaten, unzureichendes max_len oder bereits erreichtes Ziel.
Bedingungen und Grenzen
Koordinaten bezeichnen Zellen der aktuellen Karte: 8×8 Pixel bei gewöhnlichen Kacheln, 16×16 Pixel bei Metakacheln.
Die Suche verwendet etwa 4 KiB gemeinsamen, nicht reentranten Arbeitsspeicher. Begrenzen Sie Karten auf 1024 Zellen und untersuchte Entfernungen auf 254. Distanz 0xFF bedeutet „nicht erreicht“; eine Route mit 255 Schritten ist daher nicht darstellbar. Kosten- und Maskenausgaben benötigen width*height beschreibbare Bytes.
max_len begrenzt die Ausgabe, nicht den Suchradius. Verwenden Sie die Ausgabe nach einem Fehlschlag nicht als neue Route.
Anwendungsbeispiel
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);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das linke Raster zeigt Bewegungskosten innerhalb von drei Schritten, das rechte eine kürzeste Route von S nach G. Grüne Sternchen markieren neun Schritte um eine rote Wand aus drei Zellen; blaue Ziffern zeigen Kosten. Auf dem DMG erscheint dieselbe Anordnung schwarz. RAM-Prüfungen zeigen außerdem, dass die Angriffsmaske Wände ignoriert.


Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Ersetzt das gesamte Zustandsbyte einer Aufgabe. Die Bedeutung jedes Werts bestimmt das Spiel, etwa 1 für angenommen und 3 für abgeschlossen. Die Funktion prüft nicht, ob der Übergang erlaubt ist, und löst weder Belohnungen noch Callbacks aus.
Syntax
void quest_set_state(u8 quest_id, u8 state);Parameter
quest_idAufgabennummer von 0 bis 63, als u8 übergeben. Sie adressiert direkt eines der 64 Zustandsbytes und ist eine vom Spiel definierte ID, kein Zeiger und keine Anzahl abgeschlossener Aufgaben.
stateNeuer u8-Zustand von 0 bis 255. Alle acht Bits ersetzen den vorherigen Wert. Die Bibliothek weist den Werten keine feste Bedeutung zu und reserviert weder 0 noch 255.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Die Funktion prüft die ID nicht. Halten Sie Flag-IDs unter 2048 und Aufgaben-IDs unter 64. Zugriffe außerhalb des Bereichs können fremde RAM-Inhalte lesen oder überschreiben. Die Beispiele initialisieren ausdrücklich, statt sich auf Anfangsinhalte zu verlassen.
flags.c besitzt 256 RAM-Bytes für Flags und weitere 64 Bytes für Aufgaben. Diese Funktionen greifen nicht auf Cartridge-Speicher-RAM zu und erhalten keine Daten über das Ausschalten hinweg. Für dauerhaften Fortschritt muss das Spiel Flag- und Aufgabenwerte über sein Speichersystem serialisieren und beim Laden wiederherstellen.
Binden Sie rpg.h ein und kompilieren Sie lib/flags.c mit dem Spiel. Die Arrays sind innerhalb dieser Quelldatei privat; verwenden Sie die Flag- und Aufgaben-APIs zum Zugriff. Alle Aufrufer teilen sich den Speicher. Koordinieren Sie daher Schreibzugriffe aus Hauptschleife und Interrupt-Handlern selbst.
Anwendungsbeispiel
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.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel speichert für Aufgabe 2 zunächst 1 und überschreibt den Wert mit 3. ACCEPTED zeigt die erste Beobachtung 001, COMPLETED den Ersatzwert 003. LAST QUEST ist 255, nachdem 255 in Aufgaben-ID 63, dem letzten gültigen Eintrag, gespeichert wurde.
Das vollständige Programm zeigt Dezimalergebnisse auf Weiß: auf DMG mit schwarzem, auf CGB mit blauem Text. FAILED muss 000 sein. Die Aufnahmen zeigen nur das Verhalten der RAM-Zustände und belegen kein Speichern eines Spiels.
Die Prüfung im DMG-Emulator deckte alle Flag-IDs von 0 bis 2047, wiederholtes Setzen und Löschen, benachbarte Einträge sowie alle 256 Zustandswerte jeder der 64 Aufgaben ab. Ein abschließendes Muster aus 256 Flagbytes und 64 Aufgabenbytes wurde mit den erwarteten Daten verglichen. Beide Lehrbildschirme wurden nach 240 Frames geprüft. Echte Hardware und dauerhafte Speicherung wurden nicht getestet.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Liest das gespeicherte Byte einer Aufgabe. Anders als ein Ein-Bit-Flag kann ein Aufgabenbyte mehrere Stufen wie nicht begonnen, angenommen und abgeschlossen unterscheiden. Die Funktion liest nur den Speicher, führt keine Aufgabenlogik aus und schaltet keine Stufe weiter.
Syntax
u8 quest_state(u8 quest_id);Parameter
quest_idAufgabennummer von 0 bis 63, als u8 übergeben. Sie adressiert direkt eines der 64 Zustandsbytes und ist eine vom Spiel definierte ID, kein Zeiger und keine Anzahl abgeschlossener Aufgaben.
Rückgabewert
Gespeicherter u8-Wert von 0 bis 255. Dies ist ein vollständiges Zustandsbyte, kein normalisierter boolescher Wert. Vergleichen Sie ihn mit den vom Spiel definierten Stufenwerten.
Bedingungen und Grenzen
Die Funktion prüft die ID nicht. Halten Sie Flag-IDs unter 2048 und Aufgaben-IDs unter 64. Zugriffe außerhalb des Bereichs können fremde RAM-Inhalte lesen oder überschreiben. Die Beispiele initialisieren ausdrücklich, statt sich auf Anfangsinhalte zu verlassen.
flags.c besitzt 256 RAM-Bytes für Flags und weitere 64 Bytes für Aufgaben. Diese Funktionen greifen nicht auf Cartridge-Speicher-RAM zu und erhalten keine Daten über das Ausschalten hinweg. Für dauerhaften Fortschritt muss das Spiel Flag- und Aufgabenwerte über sein Speichersystem serialisieren und beim Laden wiederherstellen.
Binden Sie rpg.h ein und kompilieren Sie lib/flags.c mit dem Spiel. Die Arrays sind innerhalb dieser Quelldatei privat; verwenden Sie die Flag- und Aufgaben-APIs zum Zugriff. Alle Aufrufer teilen sich den Speicher. Koordinieren Sie daher Schreibzugriffe aus Hauptschleife und Interrupt-Handlern selbst.
Anwendungsbeispiel
finished=quest_state(2); // Read back 3 without advancing any quest logic.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel liest Aufgabe 2, nachdem das Spiel ihren Zustand ausdrücklich von 1 auf 3 geändert hat. ACCEPTED zeigt 001 und COMPLETED 003. Namen und Stufenbedeutungen legt das Beispiel fest, nicht die Bibliothek.
Das vollständige Programm zeigt Dezimalergebnisse auf Weiß: auf DMG mit schwarzem, auf CGB mit blauem Text. FAILED muss 000 sein. Die Aufnahmen zeigen nur das Verhalten der RAM-Zustände und belegen kein Speichern eines Spiels.
Die Prüfung im DMG-Emulator deckte alle Flag-IDs von 0 bis 2047, wiederholtes Setzen und Löschen, benachbarte Einträge sowie alle 256 Zustandswerte jeder der 64 Aufgaben ab. Ein abschließendes Muster aus 256 Flagbytes und 64 Aufgabenbytes wurde mit den erwarteten Daten verglichen. Beide Lehrbildschirme wurden nach 240 Frames geprüft. Echte Hardware und dauerhafte Speicherung wurden nicht getestet.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Wählt mit rng8() % max einen Wert ab null und kleiner als max. Eine Grenze von 10 liefert beispielsweise einen Index von 0 bis 9. Bei Grenze null wird sofort null ohne Ziehung geliefert.
Syntax
u8 rand_range(u8 max);Parameter
maxAusgeschlossene Obergrenze als u8 (0–255). Für max > 0 ist das Ergebnis kleiner als max. Der Parameter kann 256 nicht darstellen; verwenden Sie rng8 für den gesamten Bytebereich ohne Modulo-Reduktion.
Rückgabewert
Für max > 0 ein u8 von 0 bis max−1 nach einer Ziehung. Für max == 0 null ohne Ziehung. Selbst max == 1 verbraucht eine Ziehung, obwohl das Ergebnis immer null ist.
Bedingungen und Grenzen
Modulo-Reduktion kann bestimmte Ergebnisse bevorzugen, wenn der Eingabebereich nicht durch die Grenze teilbar ist. Auch der zugrunde liegende Generator muss nicht gleichverteilt sein. Behandeln Sie begrenzte Ergebnisse und Chancenschwellen als Spielnäherungen statt als exakte Wahrscheinlichkeiten.
Diese Aufrufe teilen einen persistenten Zustand. Reproduktion erfordert dasselbe Zielsystem, denselben Startwert und dieselbe Aufrufreihenfolge einschließlich anderer Hilfsfunktionen. Führen Sie Startwertsetzung und Ziehungen in einem Ausführungskontext aus; die Prüfungen belegen keine sichere gleichzeitige Nutzung aus einem Interrupthandler.
GB und FC verwenden unterschiedliche Algorithmen und versprechen bei gleichem Startwert keine gleiche Folge. Dies sind deterministische Spielgeneratoren, keine Quellen kryptografischer Zufälligkeit. Die Tests prüfen Implementierungsverhalten, nicht statistische Qualität oder Periode.
Binden Sie rpg.h ein und kompilieren Sie lib/rng.c mit dem Spiel, wenn Sie die Bibliotheksfunktionen nutzen. __rng_seed und __rng8 werden als intrinsische Funktionen vom Compiler erzeugt; ein Programm mit nur diesen beiden benötigt kein rng.c-Objekt.
Anwendungsbeispiel
rng_seed(0x1234);
bounded=rand_range(10); // An index from 0 through 9; this seed yields 2.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieses Beispiel wählt einen Index unter 10. RANGE 10 zeigt 00002, weil das erste Byte nach Startwert 0x1234 gleich 2 ist. ZERO BOUND ist 00000 und das folgende NEXT BYTE weiterhin 00002; der Aufruf mit Grenze null hat somit keine Ziehung verbraucht.
Das vollständige Programm zeigt Dezimalergebnisse auf Weiß: schwarze Schrift auf DMG, blaue auf CGB. FAILED muss 00000 anzeigen. Die Bilder zeigen die tatsächliche Emulatorausgabe dieses Beispiels.
Die Prüfung verglich je Fall 32 Ausgaben und acht anschließende Byteziehungen mit einem unabhängigen Hostmodell: 93 GB- und 18 FC-Fälle, einschließlich konstanter und zur Laufzeit gesetzter Startwerte sowie GB-Grenzfällen für Bereiche, Chancen und Gewichte. Die Lehrbildschirme wurden nach 240 Emulatorframes geprüft. Echte Hardware und statistische Qualität wurden nicht getestet.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Durchsucht orthogonale Nachbarzellen per Breitensuche mit Einheitskosten, um Bewegungskosten zu ermitteln.
Syntax
void range_fill_move(u8 sx, u8 sy, u8 move, u8* out_costmap);Parameter
sxX der Startzelle innerhalb der Karte.
syY der Startzelle.
moveBewegungsgrenze 0..254; null erreicht nur den Ursprung.
out_costmapBeschreibbares Kostenarray mit width*height Einträgen: 255 für nicht erreicht, null am Ursprung.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Koordinaten bezeichnen Zellen der aktuellen Karte: 8×8 Pixel bei gewöhnlichen Kacheln, 16×16 Pixel bei Metakacheln.
Die Suche verwendet etwa 4 KiB gemeinsamen, nicht reentranten Arbeitsspeicher. Begrenzen Sie Karten auf 1024 Zellen und untersuchte Entfernungen auf 254. Distanz 0xFF bedeutet „nicht erreicht“; eine Route mit 255 Schritten ist daher nicht darstellbar. Kosten- und Maskenausgaben benötigen width*height beschreibbare Bytes.
Bei fehlender Karte oder ungültigem Ursprung bleibt die Ausgabe unverändert. Blockierte Zielzellen werden nicht betreten.
Anwendungsbeispiel
range_fill_move(0,2,3,costs);for(i=0;i<30;i++)result[13+i]=costs[i];Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das linke Raster zeigt Bewegungskosten innerhalb von drei Schritten, das rechte eine kürzeste Route von S nach G. Grüne Sternchen markieren neun Schritte um eine rote Wand aus drei Zellen; blaue Ziffern zeigen Kosten. Auf dem DMG erscheint dieselbe Anordnung schwarz. RAM-Prüfungen zeigen außerdem, dass die Angriffsmaske Wände ignoriert.


Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Entpackt einen lauflängencodierten Bytestrom in normalen beschreibbaren RAM. Jedes Paar count/value wiederholt ein Byte count-mal; count gleich null beendet den Strom. Nutzen Sie diese Variante, wenn die codierten Daten über einen normalen Zeiger lesbar sind und Sie die entpackten Bytes vor dem Übertragen prüfen oder ändern möchten.
Syntax
u16 rle_decode(void* dst, const void* src);Parameter
dstZeiger auf genügend beschreibbaren RAM für den gesamten entpackten Strom. Die Funktion erhält keine Kapazitätsangabe. Trennen Sie Ausgabe und codierte Quelle, damit Schreibzugriffe keine noch ungelesenen Paare überschreiben.
srcLesbarer Zeiger auf count/value-Bytepaare mit count null als Abschluss. Normale Läufe haben count 1–255; value darf jedes Byte einschließlich null sein. Auf die abschließende null folgt kein Wertebyte. Der Zeiger muss während des gesamten Aufrufs in der aktuellen Zuordnung lesbar bleiben.
Rückgabewert
Anzahl geschriebener Bytes als u16. Ein sofortiger Nullzähler erzeugt keine Bytes und liefert 0. Der Abschluss wird nicht kopiert. Die entpackte Länge muss in u16 passen; der Rückgabewert enthält keinen separaten Fehlercode und ist keine Kachelanzahl.
Bedingungen und Grenzen
Die Codierung verarbeitet Bytes, keinen Text. Beispielsweise wird {3, 0x12, 2, 0xA5, 0} zu fünf Bytes: 12 12 12 A5 A5. Diese Ausgabeliste verwendet Hexadezimalwerte. Ein Nullwert bei einem Paar mit count ungleich null ist normales Datum, kein Endzeichen.
Es gibt keine Argumente für codierte Größe, Ausgabekapazität oder fehlerhafte Daten. Prüfen Sie Ressourcen beim Erstellen oder Laden, setzen Sie die abschließende null und berechnen Sie vor dem Decodieren die entpackte Größe. Ein ungültiger oder nicht abgeschlossener Strom kann über Quelle und Ziel hinaus lesen beziehungsweise schreiben.
Die RAM-Decoder verwenden normale Schreibzugriffe ohne Synchronisierung mit LCD-Zugriffsphasen. Ihre Ziele müssen im RAM liegen. Zum Anzeigen übertragen Sie das Ergebnis separat mit einer passenden VRAM-Kopierfunktion, wie im Beispiel bei gestopptem LCD.
Während eines Zugriffs mit Bankangabe dürfen Interruptroutinen weder die ROM-Zuordnung ändern noch die Far-Copy-Hilfe erneut verwenden; die Hilfen teilen ihre Bankverwaltung. Platzieren Sie den Decoder für normale Zeiger und seine Quelle in kompatiblen Zuordnungen. Ein Wechsel zur Funktionsbank darf einen normalen Quellzeiger nicht verdecken.
rle_decode und rle_decode_far sind in rpg.h deklariert und in lib/rle.c implementiert. Kompilieren Sie diese Implementierung einmal mit dem Spiel. Das vollständige Beispiel bindet rle.c nach #pragma bank 0 ein, damit Aufrufer und Decoder in der gemeinsamen Bank bleiben; übergeben Sie rle.c dafür nicht zusätzlich als eigene Eingabe. Die intrinsische Funktion __rle_decode_vram benötigt selbst keine Bibliotheksimplementierungsdatei.
Anwendungsbeispiel
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.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieses Beispiel entpackt neun codierte Bytes in einen RAM-Puffer mit Schutzbereichen und kopiert die 48 Ergebnisbytes an die Kacheldatenadresse 0x8800. RLE TO RAM zeigt 048. Die obere Reihe ist auf dem CGB rot und zeigt die drei über den normalen Zeiger decodierten Kacheln.
Jede Reihe enthält von links nach rechts ein gefülltes 8×8-Quadrat, einen 8×8-Rahmen mit einem Pixel Stärke und ein gefülltes 4×8-Rechteck in der linken Hälfte einer 8×8-Kachel. Die Kachelspalten sind 2, 5 und 8 (Pixel-x = 16, 40 und 64). Die drei Reihen beginnen bei Pixel-y = 32, 72 und 112. Auf dem DMG sind die Formen schwarz, auf dem CGB je Reihe rot, grün und blau. FAILED muss 000 sein. Die Zahlen zählen Bytes: Drei GB-Kacheln zu je 16 Bytes erfordern 48 entpackte Bytes.
Die Prüfmatrix umfasst 42 Fälle: leerer Strom, Einbyte-Lauf, Nullwertdaten, 255-Byte-Lauf, 510-Byte-Ausgabe über eine Zielseitengrenze und codierte Daten über eine Quellseitengrenze. Verglichen werden alle 528 beobachteten Ziel-/Schutzbytes, Ausgabelänge und wiederhergestellte ROM-Zuordnung. Direkte VRAM-Fälle umfassen LCD an/aus auf DMG und CGB sowie CGB-VBK 1. Die beiden Lehrbildschirme werden nach 240 Emulatorframes geprüft. Ungültige Ressourcen, gleichzeitige Interruptnutzung und echte Hardware sind nicht abgedeckt.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Entpackt dasselbe count/value-Format in RAM, liest jedes codierte Byte aber über __farpeek8 aus der angegebenen ROM-Bank. Geeignet für komprimierte Ressourcen in einer umschaltbaren ROM-Bank. Das Ziel bleibt ein normaler RAM-Zeiger; das Bankargument beschreibt die Quelle.
Syntax
u16 rle_decode_far(void* dst, u8 bank, const void* src);Parameter
dstZeiger auf genügend beschreibbaren RAM für den gesamten entpackten Strom. Die Funktion erhält keine Kapazitätsangabe. Trennen Sie Ausgabe und codierte Quelle, damit Schreibzugriffe keine noch ungelesenen Paare überschreiben.
bankROM-Quellbanknummer als u8. Bank und CPU-Adresse müssen zu Cartridge-Mapper und Ressourcenablage passen. Nach jedem codierten Byte wird die Bankauswahl wiederhergestellt. Das Argument wählt keine VRAM-Zielbank und kann keine Neunbit-MBC5-Banknummer darstellen.
srcCPU-Zeiger auf den codierten Strom in der angegebenen Bank. Die Adresse wird erhöht, die Banknummer bleibt jedoch fest. Halten Sie den gesamten Strom einschließlich Endnull in einer lesbaren Zuordnung; das Überschreiten von 0x7FFF setzt ihn nicht automatisch in der nächsten ROM-Bank fort.
Rückgabewert
Anzahl geschriebener Bytes als u16. Ein sofortiger Nullzähler erzeugt keine Bytes und liefert 0. Der Abschluss wird nicht kopiert. Die entpackte Länge muss in u16 passen; der Rückgabewert enthält keinen separaten Fehlercode und ist keine Kachelanzahl.
Bedingungen und Grenzen
Die Codierung verarbeitet Bytes, keinen Text. Beispielsweise wird {3, 0x12, 2, 0xA5, 0} zu fünf Bytes: 12 12 12 A5 A5. Diese Ausgabeliste verwendet Hexadezimalwerte. Ein Nullwert bei einem Paar mit count ungleich null ist normales Datum, kein Endzeichen.
Es gibt keine Argumente für codierte Größe, Ausgabekapazität oder fehlerhafte Daten. Prüfen Sie Ressourcen beim Erstellen oder Laden, setzen Sie die abschließende null und berechnen Sie vor dem Decodieren die entpackte Größe. Ein ungültiger oder nicht abgeschlossener Strom kann über Quelle und Ziel hinaus lesen beziehungsweise schreiben.
Die RAM-Decoder verwenden normale Schreibzugriffe ohne Synchronisierung mit LCD-Zugriffsphasen. Ihre Ziele müssen im RAM liegen. Zum Anzeigen übertragen Sie das Ergebnis separat mit einer passenden VRAM-Kopierfunktion, wie im Beispiel bei gestopptem LCD.
Während eines Zugriffs mit Bankangabe dürfen Interruptroutinen weder die ROM-Zuordnung ändern noch die Far-Copy-Hilfe erneut verwenden; die Hilfen teilen ihre Bankverwaltung. Platzieren Sie den Decoder für normale Zeiger und seine Quelle in kompatiblen Zuordnungen. Ein Wechsel zur Funktionsbank darf einen normalen Quellzeiger nicht verdecken.
rle_decode und rle_decode_far sind in rpg.h deklariert und in lib/rle.c implementiert. Kompilieren Sie diese Implementierung einmal mit dem Spiel. Das vollständige Beispiel bindet rle.c nach #pragma bank 0 ein, damit Aufrufer und Decoder in der gemeinsamen Bank bleiben; übergeben Sie rle.c dafür nicht zusätzlich als eigene Eingabe. Die intrinsische Funktion __rle_decode_vram benötigt selbst keine Bibliotheksimplementierungsdatei.
Anwendungsbeispiel
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);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieses Beispiel liest den codierten Strom aus ROM-Bank 2, entpackt 48 Bytes in RAM und überträgt sie nach 0x8830. BANKED RAM zeigt 048. Die mittlere Reihe ist auf dem CGB grün. Ein Marker in ROM-Bank 1 prüft zusätzlich die Wiederherstellung der Zuordnung des Aufrufers.
Jede Reihe enthält von links nach rechts ein gefülltes 8×8-Quadrat, einen 8×8-Rahmen mit einem Pixel Stärke und ein gefülltes 4×8-Rechteck in der linken Hälfte einer 8×8-Kachel. Die Kachelspalten sind 2, 5 und 8 (Pixel-x = 16, 40 und 64). Die drei Reihen beginnen bei Pixel-y = 32, 72 und 112. Auf dem DMG sind die Formen schwarz, auf dem CGB je Reihe rot, grün und blau. FAILED muss 000 sein. Die Zahlen zählen Bytes: Drei GB-Kacheln zu je 16 Bytes erfordern 48 entpackte Bytes.
Die Prüfmatrix umfasst 42 Fälle: leerer Strom, Einbyte-Lauf, Nullwertdaten, 255-Byte-Lauf, 510-Byte-Ausgabe über eine Zielseitengrenze und codierte Daten über eine Quellseitengrenze. Verglichen werden alle 528 beobachteten Ziel-/Schutzbytes, Ausgabelänge und wiederhergestellte ROM-Zuordnung. Direkte VRAM-Fälle umfassen LCD an/aus auf DMG und CGB sowie CGB-VBK 1. Die beiden Lehrbildschirme werden nach 240 Emulatorframes geprüft. Ungültige Ressourcen, gleichzeitige Interruptnutzung und echte Hardware sind nicht abgedeckt.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Bildet einen vorzeichenlosen 16-Bit-Wert aus zwei aufeinanderfolgenden rng8-Ziehungen. Das erste Byte belegt Bits 15–8, das zweite Bits 7–0. Geeignet, wenn ein Byte den benötigten Wertebereich nicht abdeckt.
Syntax
u16 rng16();Rückgabewert
Ein u16-Ergebnis (0–65535), gebildet als (first_byte << 8) | second_byte. Genau zwei Byteziehungen werden verbraucht; eine Gleichverteilung aller 65536 Werte ist damit nicht belegt.
Bedingungen und Grenzen
Diese Aufrufe teilen einen persistenten Zustand. Reproduktion erfordert dasselbe Zielsystem, denselben Startwert und dieselbe Aufrufreihenfolge einschließlich anderer Hilfsfunktionen. Führen Sie Startwertsetzung und Ziehungen in einem Ausführungskontext aus; die Prüfungen belegen keine sichere gleichzeitige Nutzung aus einem Interrupthandler.
GB und FC verwenden unterschiedliche Algorithmen und versprechen bei gleichem Startwert keine gleiche Folge. Dies sind deterministische Spielgeneratoren, keine Quellen kryptografischer Zufälligkeit. Die Tests prüfen Implementierungsverhalten, nicht statistische Qualität oder Periode.
Binden Sie rpg.h ein und kompilieren Sie lib/rng.c mit dem Spiel, wenn Sie die Bibliotheksfunktionen nutzen. __rng_seed und __rng8 werden als intrinsische Funktionen vom Compiler erzeugt; ein Programm mit nur diesen beiden benötigt kein rng.c-Objekt.
Anwendungsbeispiel
rng_seed(0x1234);
word=rng16(); // First draw 2 is high, second draw 34 is low: 0x0222 = 546.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieses Beispiel zeigt die Wortbildung. Nach erneutem Startwert 0x1234 bilden die Bytes 2 und 34 den Wert 0x0222, weshalb RNG16 00546 zeigt. FIRST und SECOND zeigen die zugehörigen Bytewerte einzeln.
Das vollständige Programm zeigt Dezimalergebnisse auf Weiß: schwarze Schrift auf DMG, blaue auf CGB. FAILED muss 00000 anzeigen. Die Bilder zeigen die tatsächliche Emulatorausgabe dieses Beispiels.
Die Prüfung verglich je Fall 32 Ausgaben und acht anschließende Byteziehungen mit einem unabhängigen Hostmodell: 93 GB- und 18 FC-Fälle, einschließlich konstanter und zur Laufzeit gesetzter Startwerte sowie GB-Grenzfällen für Bereiche, Chancen und Gewichte. Die Lehrbildschirme wurden nach 240 Emulatorframes geprüft. Echte Hardware und statistische Qualität wurden nicht getestet.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Liefert ein Pseudozufallsbyte über die GB-Bibliothek. rng8 ruft __rng8 genau einmal auf und ist damit die grundlegende Ziehoperation der anderen rng.c-Hilfen.
Syntax
u8 rng8();Rückgabewert
Ein u8-Ergebnis (0–255) nach einmaligem Fortschalten des gemeinsamen Generators. Dies beschreibt Typ und Grenzen, nicht gleiche Wahrscheinlichkeit für jedes Byte.
Bedingungen und Grenzen
Diese Aufrufe teilen einen persistenten Zustand. Reproduktion erfordert dasselbe Zielsystem, denselben Startwert und dieselbe Aufrufreihenfolge einschließlich anderer Hilfsfunktionen. Führen Sie Startwertsetzung und Ziehungen in einem Ausführungskontext aus; die Prüfungen belegen keine sichere gleichzeitige Nutzung aus einem Interrupthandler.
GB und FC verwenden unterschiedliche Algorithmen und versprechen bei gleichem Startwert keine gleiche Folge. Dies sind deterministische Spielgeneratoren, keine Quellen kryptografischer Zufälligkeit. Die Tests prüfen Implementierungsverhalten, nicht statistische Qualität oder Periode.
Binden Sie rpg.h ein und kompilieren Sie lib/rng.c mit dem Spiel, wenn Sie die Bibliotheksfunktionen nutzen. __rng_seed und __rng8 werden als intrinsische Funktionen vom Compiler erzeugt; ein Programm mit nur diesen beiden benötigt kein rng.c-Objekt.
Anwendungsbeispiel
rng_seed(0x1234); // Reset the same generator used by the intrinsics.
wrapped=rng8(); // One byte draw: 2 after the preceding seed.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieses Beispiel vergleicht die Byteziehung der Bibliothek mit der intrinsischen Funktion. Nach rng_seed(0x1234) zeigt RNG8 wie FIRST den Wert 00002. Das Setzen des Startwerts verbraucht die erste Ziehung nicht.
Das vollständige Programm zeigt Dezimalergebnisse auf Weiß: schwarze Schrift auf DMG, blaue auf CGB. FAILED muss 00000 anzeigen. Die Bilder zeigen die tatsächliche Emulatorausgabe dieses Beispiels.
Die Prüfung verglich je Fall 32 Ausgaben und acht anschließende Byteziehungen mit einem unabhängigen Hostmodell: 93 GB- und 18 FC-Fälle, einschließlich konstanter und zur Laufzeit gesetzter Startwerte sowie GB-Grenzfällen für Bereiche, Chancen und Gewichte. Die Lehrbildschirme wurden nach 240 Emulatorframes geprüft. Echte Hardware und statistische Qualität wurden nicht getestet.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Trifft mit rng_range(100) < percent eine Ja-/Nein-Entscheidung. Das eignet sich für ungefähre Spielchancen, etwa einen Gegenstandsdrop. Null liefert immer falsch, 100 oder mehr immer wahr; beide Randfälle verbrauchen keine Ziehung.
Syntax
u8 rng_chance(u8 percent);Parameter
percentGewünschte Chance als u8. Werte 1–99 verwenden ein modulo-reduziertes Byte; 0 liefert falsch, 100–255 liefern wahr. Die Zwischenwerte sind ungefähre Schwellwerte, keine Garantie exakter Prozentsätze.
Rückgabewert
Normalisierter Wahrheitswert: 0 für falsch, 1 für wahr. Ein Schwellwert von 1 bis 99 verbraucht eine Byteziehung.
Bedingungen und Grenzen
Modulo-Reduktion kann bestimmte Ergebnisse bevorzugen, wenn der Eingabebereich nicht durch die Grenze teilbar ist. Auch der zugrunde liegende Generator muss nicht gleichverteilt sein. Behandeln Sie begrenzte Ergebnisse und Chancenschwellen als Spielnäherungen statt als exakte Wahrscheinlichkeiten.
Diese Aufrufe teilen einen persistenten Zustand. Reproduktion erfordert dasselbe Zielsystem, denselben Startwert und dieselbe Aufrufreihenfolge einschließlich anderer Hilfsfunktionen. Führen Sie Startwertsetzung und Ziehungen in einem Ausführungskontext aus; die Prüfungen belegen keine sichere gleichzeitige Nutzung aus einem Interrupthandler.
GB und FC verwenden unterschiedliche Algorithmen und versprechen bei gleichem Startwert keine gleiche Folge. Dies sind deterministische Spielgeneratoren, keine Quellen kryptografischer Zufälligkeit. Die Tests prüfen Implementierungsverhalten, nicht statistische Qualität oder Periode.
Binden Sie rpg.h ein und kompilieren Sie lib/rng.c mit dem Spiel, wenn Sie die Bibliotheksfunktionen nutzen. __rng_seed und __rng8 werden als intrinsische Funktionen vom Compiler erzeugt; ein Programm mit nur diesen beiden benötigt kein rng.c-Objekt.
Anwendungsbeispiel
rng_seed(0x1234);
chance=rng_chance(50); // Here 2 % 100 < 50, so the result is 1 (true).Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieses Beispiel führt eine ungefähre 50-Prozent-Entscheidung aus. Das gezogene Byte ist 2 und 2 % 100 < 50 wahr, daher zeigt CHANCE 50 den Wert 00001. Ein einzelner Erfolg belegt keine langfristige Erfolgsquote von 50 Prozent.
Das vollständige Programm zeigt Dezimalergebnisse auf Weiß: schwarze Schrift auf DMG, blaue auf CGB. FAILED muss 00000 anzeigen. Die Bilder zeigen die tatsächliche Emulatorausgabe dieses Beispiels.
Die Prüfung verglich je Fall 32 Ausgaben und acht anschließende Byteziehungen mit einem unabhängigen Hostmodell: 93 GB- und 18 FC-Fälle, einschließlich konstanter und zur Laufzeit gesetzter Startwerte sowie GB-Grenzfällen für Bereiche, Chancen und Gewichte. Die Lehrbildschirme wurden nach 240 Emulatorframes geprüft. Echte Hardware und statistische Qualität wurden nicht getestet.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Liefert dasselbe Wort aus zwei Ziehungen wie rng16. Dieser Bibliotheksalias legt die erste Ziehung ins High-Byte und die zweite ins Low-Byte; er überspringt vorher keinen zusätzlichen Wert.
Syntax
u16 rng_next16();Rückgabewert
Ein u16-Ergebnis (0–65535), gebildet als (first_byte << 8) | second_byte. Genau zwei Byteziehungen werden verbraucht; eine Gleichverteilung aller 65536 Werte ist damit nicht belegt.
Bedingungen und Grenzen
Diese Aufrufe teilen einen persistenten Zustand. Reproduktion erfordert dasselbe Zielsystem, denselben Startwert und dieselbe Aufrufreihenfolge einschließlich anderer Hilfsfunktionen. Führen Sie Startwertsetzung und Ziehungen in einem Ausführungskontext aus; die Prüfungen belegen keine sichere gleichzeitige Nutzung aus einem Interrupthandler.
GB und FC verwenden unterschiedliche Algorithmen und versprechen bei gleichem Startwert keine gleiche Folge. Dies sind deterministische Spielgeneratoren, keine Quellen kryptografischer Zufälligkeit. Die Tests prüfen Implementierungsverhalten, nicht statistische Qualität oder Periode.
Binden Sie rpg.h ein und kompilieren Sie lib/rng.c mit dem Spiel, wenn Sie die Bibliotheksfunktionen nutzen. __rng_seed und __rng8 werden als intrinsische Funktionen vom Compiler erzeugt; ein Programm mit nur diesen beiden benötigt kein rng.c-Objekt.
Anwendungsbeispiel
rng_seed(0x1234);
nextword=rng_next16(); // The same two-draw word: 546.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieses Beispiel vergleicht den Wortalias mit rng16 nach identischen Startwerten. NEXT16 und RNG16 zeigen jeweils 00546, zusammengesetzt aus zwei Byteziehungen in High-/Low-Reihenfolge.
Das vollständige Programm zeigt Dezimalergebnisse auf Weiß: schwarze Schrift auf DMG, blaue auf CGB. FAILED muss 00000 anzeigen. Die Bilder zeigen die tatsächliche Emulatorausgabe dieses Beispiels.
Die Prüfung verglich je Fall 32 Ausgaben und acht anschließende Byteziehungen mit einem unabhängigen Hostmodell: 93 GB- und 18 FC-Fälle, einschließlich konstanter und zur Laufzeit gesetzter Startwerte sowie GB-Grenzfällen für Bereiche, Chancen und Gewichte. Die Lehrbildschirme wurden nach 240 Emulatorframes geprüft. Echte Hardware und statistische Qualität wurden nicht getestet.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
kitaqgb/lib/rpg.h:209
Alias the two-step 16-bit generator.
kitaqgb/lib/rng.c:30
u16 rng_next16()
{
return rng16();
}rng_next8
Zieht das nächste Byte mit derselben Operation wie rng8. Der Name betont das Fortschalten der Folge. Beide Namen nacheinander aufzurufen verbraucht zwei aufeinanderfolgende Ziehungen desselben gemeinsamen Generators.
Syntax
u8 rng_next8();Rückgabewert
Ein u8-Ergebnis (0–255) nach einmaligem Fortschalten des gemeinsamen Generators. Dies beschreibt Typ und Grenzen, nicht gleiche Wahrscheinlichkeit für jedes Byte.
Bedingungen und Grenzen
Diese Aufrufe teilen einen persistenten Zustand. Reproduktion erfordert dasselbe Zielsystem, denselben Startwert und dieselbe Aufrufreihenfolge einschließlich anderer Hilfsfunktionen. Führen Sie Startwertsetzung und Ziehungen in einem Ausführungskontext aus; die Prüfungen belegen keine sichere gleichzeitige Nutzung aus einem Interrupthandler.
GB und FC verwenden unterschiedliche Algorithmen und versprechen bei gleichem Startwert keine gleiche Folge. Dies sind deterministische Spielgeneratoren, keine Quellen kryptografischer Zufälligkeit. Die Tests prüfen Implementierungsverhalten, nicht statistische Qualität oder Periode.
Binden Sie rpg.h ein und kompilieren Sie lib/rng.c mit dem Spiel, wenn Sie die Bibliotheksfunktionen nutzen. __rng_seed und __rng8 werden als intrinsische Funktionen vom Compiler erzeugt; ein Programm mit nur diesen beiden benötigt kein rng.c-Objekt.
Anwendungsbeispiel
rng_seed(0x1234);
nextbyte=rng_next8(); // One draw, just like rng8(): 2.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieses Beispiel prüft den Bytealias mit gleichem Startwert. NEXT8 und RNG8 zeigen jeweils 00002, da das Programm vor jedem Vergleich den Startwert erneut setzt. Ohne diese Rücksetzungen würden sie aufeinanderfolgende Werte verbrauchen.
Das vollständige Programm zeigt Dezimalergebnisse auf Weiß: schwarze Schrift auf DMG, blaue auf CGB. FAILED muss 00000 anzeigen. Die Bilder zeigen die tatsächliche Emulatorausgabe dieses Beispiels.
Die Prüfung verglich je Fall 32 Ausgaben und acht anschließende Byteziehungen mit einem unabhängigen Hostmodell: 93 GB- und 18 FC-Fälle, einschließlich konstanter und zur Laufzeit gesetzter Startwerte sowie GB-Grenzfällen für Bereiche, Chancen und Gewichte. Die Lehrbildschirme wurden nach 240 Emulatorframes geprüft. Echte Hardware und statistische Qualität wurden nicht getestet.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Ruft rand_range mit derselben ausgeschlossenen Obergrenze auf. Dieser Name ordnet die begrenzte Auswahl den anderen rng_-Funktionen zu. Byteziehung und Modulooperation sind identisch, einschließlich des Ergebnisses ohne Ziehung bei Grenze null.
Syntax
u8 rng_range(u8 max);Parameter
maxAusgeschlossene Obergrenze als u8 (0–255). Für max > 0 ist das Ergebnis kleiner als max. Der Parameter kann 256 nicht darstellen; verwenden Sie rng8 für den gesamten Bytebereich ohne Modulo-Reduktion.
Rückgabewert
Für max > 0 ein u8 von 0 bis max−1 nach einer Ziehung. Für max == 0 null ohne Ziehung. Selbst max == 1 verbraucht eine Ziehung, obwohl das Ergebnis immer null ist.
Bedingungen und Grenzen
Modulo-Reduktion kann bestimmte Ergebnisse bevorzugen, wenn der Eingabebereich nicht durch die Grenze teilbar ist. Auch der zugrunde liegende Generator muss nicht gleichverteilt sein. Behandeln Sie begrenzte Ergebnisse und Chancenschwellen als Spielnäherungen statt als exakte Wahrscheinlichkeiten.
Diese Aufrufe teilen einen persistenten Zustand. Reproduktion erfordert dasselbe Zielsystem, denselben Startwert und dieselbe Aufrufreihenfolge einschließlich anderer Hilfsfunktionen. Führen Sie Startwertsetzung und Ziehungen in einem Ausführungskontext aus; die Prüfungen belegen keine sichere gleichzeitige Nutzung aus einem Interrupthandler.
GB und FC verwenden unterschiedliche Algorithmen und versprechen bei gleichem Startwert keine gleiche Folge. Dies sind deterministische Spielgeneratoren, keine Quellen kryptografischer Zufälligkeit. Die Tests prüfen Implementierungsverhalten, nicht statistische Qualität oder Periode.
Binden Sie rpg.h ein und kompilieren Sie lib/rng.c mit dem Spiel, wenn Sie die Bibliotheksfunktionen nutzen. __rng_seed und __rng8 werden als intrinsische Funktionen vom Compiler erzeugt; ein Programm mit nur diesen beiden benötigt kein rng.c-Objekt.
Anwendungsbeispiel
rng_seed(0x1234);
alias=rng_range(10); // The same exclusive upper bound and result, 2.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieses Beispiel vergleicht zwei Namen der begrenzten Auswahl. Ein erneuter Startwert vor jedem Aufruf lässt ALIAS 10 und RANGE 10 jeweils 00002 anzeigen. Die Obergrenze 10 selbst ist ausgeschlossen.
Das vollständige Programm zeigt Dezimalergebnisse auf Weiß: schwarze Schrift auf DMG, blaue auf CGB. FAILED muss 00000 anzeigen. Die Bilder zeigen die tatsächliche Emulatorausgabe dieses Beispiels.
Die Prüfung verglich je Fall 32 Ausgaben und acht anschließende Byteziehungen mit einem unabhängigen Hostmodell: 93 GB- und 18 FC-Fälle, einschließlich konstanter und zur Laufzeit gesetzter Startwerte sowie GB-Grenzfällen für Bereiche, Chancen und Gewichte. Die Lehrbildschirme wurden nach 240 Emulatorframes geprüft. Echte Hardware und statistische Qualität wurden nicht getestet.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Setzt den Startwert über die GB-Bibliotheksschnittstelle. Als Wrapper um __rng_seed setzt dies denselben Zustand zurück, den rng8, rng16 und Auswahlhilfen teilen; es wird kein separater Generator erzeugt.
Syntax
void rng_seed(u16 seed);Parameter
seedVorzeichenloser 16-Bit-Startwert in 0–65535. Beide Bytes werden unverändert gespeichert. Wählen und notieren Sie den Startwert vor der Folge von Spielziehungen, die Sie reproduzieren möchten.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Zustand null ist zulässig. Bei der nächsten Byteziehung ersetzt ihn der GB-Generator vor dem Fortschalten durch 0x5AA5; __rng_seed(0) gefolgt von __rng8() liefert daher 122. Wiederholtes Setzen des Startwerts startet die Folge neu, statt Zufälligkeit hinzuzufügen.
Diese Aufrufe teilen einen persistenten Zustand. Reproduktion erfordert dasselbe Zielsystem, denselben Startwert und dieselbe Aufrufreihenfolge einschließlich anderer Hilfsfunktionen. Führen Sie Startwertsetzung und Ziehungen in einem Ausführungskontext aus; die Prüfungen belegen keine sichere gleichzeitige Nutzung aus einem Interrupthandler.
GB und FC verwenden unterschiedliche Algorithmen und versprechen bei gleichem Startwert keine gleiche Folge. Dies sind deterministische Spielgeneratoren, keine Quellen kryptografischer Zufälligkeit. Die Tests prüfen Implementierungsverhalten, nicht statistische Qualität oder Periode.
Binden Sie rpg.h ein und kompilieren Sie lib/rng.c mit dem Spiel, wenn Sie die Bibliotheksfunktionen nutzen. __rng_seed und __rng8 werden als intrinsische Funktionen vom Compiler erzeugt; ein Programm mit nur diesen beiden benötigt kein rng.c-Objekt.
Anwendungsbeispiel
rng_seed(0x1234); // Reset the same generator used by the intrinsics.
wrapped=rng8(); // One byte draw: 2 after the preceding seed.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieses Beispiel vergleicht die Byteziehung der Bibliothek mit der intrinsischen Funktion. Nach rng_seed(0x1234) zeigt RNG8 wie FIRST den Wert 00002. Das Setzen des Startwerts verbraucht die erste Ziehung nicht.
Das vollständige Programm zeigt Dezimalergebnisse auf Weiß: schwarze Schrift auf DMG, blaue auf CGB. FAILED muss 00000 anzeigen. Die Bilder zeigen die tatsächliche Emulatorausgabe dieses Beispiels.
Die Prüfung verglich je Fall 32 Ausgaben und acht anschließende Byteziehungen mit einem unabhängigen Hostmodell: 93 GB- und 18 FC-Fälle, einschließlich konstanter und zur Laufzeit gesetzter Startwerte sowie GB-Grenzfällen für Bereiche, Chancen und Gewichte. Die Lehrbildschirme wurden nach 240 Emulatorframes geprüft. Echte Hardware und statistische Qualität wurden nicht getestet.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Führt dieselbe Integritätsprüfung wie save_exists aus, ohne Nutzdaten auszulesen.
Syntax
u8 save_check(u8 slot);Parameter
slotSlotnummer 0..3.
Rückgabewert
Gibt bei Gültigkeit 1 zurück, sonst 0. Auch ein Spielstand mit Länge null kann gültig sein.
Bedingungen und Grenzen
Standardmäßig gibt es vier 512-Byte-Slots mit je sechs Headerbytes und bis zu 506 Nutzdatenbytes. Das Beispiel verwendet MBC5 mit 8 KiB SRAM. Aufrufe enden mit deaktiviertem RAM, ohne die vorherige Bank oder den Aktivierungszustand wiederherzustellen.
Anwendungsbeispiel
result[4]=save_check(0);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Speichern Sie drei Bytes, 7/42/255, und prüfen Sie falsche Länge, ungültigen Slot und beschädigte Prüfsumme. Erfolgreiches Laden ergibt das mittlere Byte 42; fehlgeschlagenes Lesen erhält Zielwert 77; die Prüfung nach dem Löschen liefert 0.


Vollständiges Beispielprogramm
Build-Befehl
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=8kImplementierung und Quelltext
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
Setzt alle 512 Bytes eines Slots auf null, um seinen Spielstand ungültig zu machen.
Syntax
void save_clear(u8 slot);Parameter
slotSlotnummer 0..3.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Standardmäßig gibt es vier 512-Byte-Slots mit je sechs Headerbytes und bis zu 506 Nutzdatenbytes. Das Beispiel verwendet MBC5 mit 8 KiB SRAM. Aufrufe enden mit deaktiviertem RAM, ohne die vorherige Bank oder den Aktivierungszustand wiederherzustellen.
Ignoriert Slots außerhalb von 0..3 und lässt andere Slots unverändert.
Anwendungsbeispiel
save_clear(0);result[16]=save_check(0);result[17]=save_write(3,payload,0);result[18]=save_exists(3);save_clear(3);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Speichern Sie drei Bytes, 7/42/255, und prüfen Sie falsche Länge, ungültigen Slot und beschädigte Prüfsumme. Erfolgreiches Laden ergibt das mittlere Byte 42; fehlgeschlagenes Lesen erhält Zielwert 77; die Prüfung nach dem Löschen liefert 0.


Vollständiges Beispielprogramm
Build-Befehl
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=8kImplementierung und Quelltext
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
Prüft Header, Länge und Prüfsumme eines Slots auf einen verwendbaren Spielstand.
Syntax
u8 save_exists(u8 slot);Parameter
slotSlotnummer 0..3.
Rückgabewert
Gibt bei Gültigkeit 1 zurück, sonst 0. Auch ein Spielstand mit Länge null kann gültig sein.
Bedingungen und Grenzen
Standardmäßig gibt es vier 512-Byte-Slots mit je sechs Headerbytes und bis zu 506 Nutzdatenbytes. Das Beispiel verwendet MBC5 mit 8 KiB SRAM. Aufrufe enden mit deaktiviertem RAM, ohne die vorherige Bank oder den Aktivierungszustand wiederherzustellen.
Anwendungsbeispiel
result[0]=save_exists(0);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Speichern Sie drei Bytes, 7/42/255, und prüfen Sie falsche Länge, ungültigen Slot und beschädigte Prüfsumme. Erfolgreiches Laden ergibt das mittlere Byte 42; fehlgeschlagenes Lesen erhält Zielwert 77; die Prüfung nach dem Löschen liefert 0.


Vollständiges Beispielprogramm
Build-Befehl
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=8kImplementierung und Quelltext
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
Wählt RAM-Bank null, aktiviert sie kurz und deaktiviert sie anschließend.
Syntax
void save_init();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Standardmäßig gibt es vier 512-Byte-Slots mit je sechs Headerbytes und bis zu 506 Nutzdatenbytes. Das Beispiel verwendet MBC5 mit 8 KiB SRAM. Aufrufe enden mit deaktiviertem RAM, ohne die vorherige Bank oder den Aktivierungszustand wiederherzustellen.
Löscht keine Spielstände, erkennt keine Modulhardware und formatiert keine Slots.
Anwendungsbeispiel
save_init();save_clear(0);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Speichern Sie drei Bytes, 7/42/255, und prüfen Sie falsche Länge, ungültigen Slot und beschädigte Prüfsumme. Erfolgreiches Laden ergibt das mittlere Byte 42; fehlgeschlagenes Lesen erhält Zielwert 77; die Prüfung nach dem Löschen liefert 0.


Vollständiges Beispielprogramm
Build-Befehl
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=8kImplementierung und Quelltext
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
Lädt gespeicherte Daten mit derselben Prüfung wie save_read.
Syntax
u8 save_load(u8 slot, void* data, u16 len);Parameter
slotSlotnummer 0..3.
dataBeschreibbares Ziel mit len Bytes.
lenNutzdatenlänge 0..506 Bytes. Beim Lesen muss sie genau mit der gespeicherten Länge übereinstimmen.
Rückgabewert
Gibt bei erfolgreichem Laden 1 zurück, sonst 0; die angeforderte Länge muss der gespeicherten entsprechen.
Bedingungen und Grenzen
Standardmäßig gibt es vier 512-Byte-Slots mit je sechs Headerbytes und bis zu 506 Nutzdatenbytes. Das Beispiel verwendet MBC5 mit 8 KiB SRAM. Aufrufe enden mit deaktiviertem RAM, ohne die vorherige Bank oder den Aktivierungszustand wiederherzustellen.
Die additive 8-Bit-Prüfsumme erkennt nicht jede Beschädigung. Schreibvorgänge sind bei Stromausfall nicht atomar; eine Erfolgsmeldung allein garantiert daher keine dauerhafte physische Speicherung.
Anwendungsbeispiel
readback[1]=0;result[10]=save_load(0,readback,3);result[11]=readback[1];Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Speichern Sie drei Bytes, 7/42/255, und prüfen Sie falsche Länge, ungültigen Slot und beschädigte Prüfsumme. Erfolgreiches Laden ergibt das mittlere Byte 42; fehlgeschlagenes Lesen erhält Zielwert 77; die Prüfung nach dem Löschen liefert 0.


Vollständiges Beispielprogramm
Build-Befehl
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=8kImplementierung und Quelltext
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
Prüft Header, exakte Länge und Prüfsumme und kopiert Daten erst nach erfolgreicher Prüfung.
Syntax
u8 save_read(u8 slot, void* data, u16 len);Parameter
slotSlotnummer 0..3.
dataBeschreibbares Ziel mit len Bytes.
lenNutzdatenlänge 0..506 Bytes. Beim Lesen muss sie genau mit der gespeicherten Länge übereinstimmen.
Rückgabewert
Gibt bei Erfolg 1 zurück, bei fehlgeschlagener Prüfung 0; ein Fehlschlag lässt das Ziel unverändert.
Bedingungen und Grenzen
Standardmäßig gibt es vier 512-Byte-Slots mit je sechs Headerbytes und bis zu 506 Nutzdatenbytes. Das Beispiel verwendet MBC5 mit 8 KiB SRAM. Aufrufe enden mit deaktiviertem RAM, ohne die vorherige Bank oder den Aktivierungszustand wiederherzustellen.
Die additive 8-Bit-Prüfsumme erkennt nicht jede Beschädigung. Schreibvorgänge sind bei Stromausfall nicht atomar; eine Erfolgsmeldung allein garantiert daher keine dauerhafte physische Speicherung.
Anwendungsbeispiel
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];Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Speichern Sie drei Bytes, 7/42/255, und prüfen Sie falsche Länge, ungültigen Slot und beschädigte Prüfsumme. Erfolgreiches Laden ergibt das mittlere Byte 42; fehlgeschlagenes Lesen erhält Zielwert 77; die Prüfung nach dem Löschen liefert 0.


Vollständiges Beispielprogramm
Build-Befehl
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=8kImplementierung und Quelltext
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
Schreibt Daten, Länge und Prüfsumme in einen Slot.
Syntax
u8 save_write(u8 slot, const void* data, u16 len);Parameter
slotSlotnummer 0..3.
dataLesbare Quelle mit len Bytes.
lenNutzdatenlänge 0..506 Bytes. Beim Lesen muss sie genau mit der gespeicherten Länge übereinstimmen.
Rückgabewert
Gibt bei gültigen Argumenten 1 zurück, bei ungültigem Slot oder ungültiger Länge 0; führt keine Rückleseprüfung durch.
Bedingungen und Grenzen
Standardmäßig gibt es vier 512-Byte-Slots mit je sechs Headerbytes und bis zu 506 Nutzdatenbytes. Das Beispiel verwendet MBC5 mit 8 KiB SRAM. Aufrufe enden mit deaktiviertem RAM, ohne die vorherige Bank oder den Aktivierungszustand wiederherzustellen.
Die additive 8-Bit-Prüfsumme erkennt nicht jede Beschädigung. Schreibvorgänge sind bei Stromausfall nicht atomar; eine Erfolgsmeldung allein garantiert daher keine dauerhafte physische Speicherung.
Anwendungsbeispiel
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);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Speichern Sie drei Bytes, 7/42/255, und prüfen Sie falsche Länge, ungültigen Slot und beschädigte Prüfsumme. Erfolgreiches Laden ergibt das mittlere Byte 42; fehlgeschlagenes Lesen erhält Zielwert 77; die Prüfung nach dem Löschen liefert 0.


Vollständiges Beispielprogramm
Build-Befehl
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=8kImplementierung und Quelltext
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
Wählt ein Skript und setzt Wartezähler, Auswahlergebnis und gespeicherte Rücksprungposition zurück.
Syntax
void script_run(u8 bank, const u8* script);Parameter
bankROM-Bank des Anweisungsstroms.
scriptBeginn eines gültigen terminierten Datenstroms; dieser Aufruf bereitet ihn vor, ohne Befehle auszuführen.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Opcodes: 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). Wörter sind Little-Endian. Halten Sie Zeichenketten, Zeigertabellen und Anweisungen lesbar und innerhalb ihrer eingeblendeten Banken.
Anwendungsbeispiel
flag_clear(19);script_run(1,(const u8*)&entry);result[0]=flag_get(19);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Springen Sie von Bank 1 zu Bank 2, setzen Sie Flag 19 und warten Sie. Die ersten beiden Warteaufrufe liefern 1; das Zielflag wird 1; der Abschluss nach WAIT liefert 2. Das Flag belegt, dass die Ausführung die andere Bank erreicht hat.


Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Verarbeitet Befehle, bis Ausgabe, Auswahl, Warten oder Abschluss die Kontrolle zurückgibt.
Syntax
u8 script_step();Rückgabewert
0=Kontrollrückgabe durch TEXT/CHOICE; 1=Warten; 2=beendet oder inaktiv. Unbekannte Opcodes beenden ebenfalls mit 2.
Bedingungen und Grenzen
Opcodes: 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). Wörter sind Little-Endian. Halten Sie Zeichenketten, Zeigertabellen und Anweisungen lesbar und innerhalb ihrer eingeblendeten Banken.
WAIT n gibt beim Dekodieren 1 zurück und wartet danach weitere n Aufrufe. CALL_EVENT hat nur einen gespeicherten Rücksprungplatz. CHOICE benötigt eine Anzahl ungleich null und blockiert intern bis zur Auswahl. Eine Sprungschleife ohne Kontrollrückgabe blockiert die Spielschleife; stellen Sie sicher, dass ein Endbefehl oder ein Befehl zur Kontrollrückgabe erreicht wird.
Anwendungsbeispiel
result[3]=script_step();result[4]=flag_get(19);result[5]=script_step();result[6]=script_step();result[7]=script_step();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Springen Sie von Bank 1 zu Bank 2, setzen Sie Flag 19 und warten Sie. Die ersten beiden Warteaufrufe liefern 1; das Zielflag wird 1; der Abschluss nach WAIT liefert 2. Das Flag belegt, dass die Ausführung die andere Bank erreicht hat.


Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Lässt die angegebene Anzahl der nächsten script_step-Aufrufe warten.
Syntax
void script_wait_frames(u8 n);Parameter
nAnzahl wartender Aufrufe, 0..255; null hebt das Warten auf.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Dies entspricht nur dann einer Frame-Anzahl, wenn script_step einmal pro Frame aufgerufen wird; die Funktion wartet selbst nicht auf VBlank.
Anwendungsbeispiel
script_wait_frames(2);result[1]=script_step();result[2]=script_step();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Springen Sie von Bank 1 zu Bank 2, setzen Sie Flag 19 und warten Sie. Die ersten beiden Warteaufrufe liefern 1; das Zielflag wird 1; der Abschluss nach WAIT liefert 2. Das Flag belegt, dass die Ausführung die andere Bank erreicht hat.


Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Zeichnet eine vertikale Liste im aktiven Textbereich und wartet auf eine Auswahl. UP/DOWN bewegen den Cursor umlaufend, A bestätigt und B bricht ab. Die Schleife zeichnet die Auswahl neu und fragt nach einem VBlank-Wartevorgang einmal die Eingabe ab. Liefert einen Index ab null oder bei Abbruch beziehungsweise leerer Liste 255.
Syntax
u8 text_choice(const u8* const* choices, u8 count);Parameter
choicesZeiger auf ein Array mit count lesbaren Zeichenkettenzeigern. Jede Zeichenkette endet mit null und enthält rohe Kachel-IDs; Auswahltexte interpretieren keine Dialogsteuercodes. Halten Sie Zeigertabelle und Texte bis zum Auswahlende eingeblendet.
countAnzahl der Auswahlmöglichkeiten. Null liefert sofort 255, ohne die Zeigertabelle zu lesen. Andernfalls benötigen Sie mindestens count Innenzeilen und genügend Breite für eine Cursorzelle plus den längsten Text. Es gibt weder Clipping noch Scrollen.
Rückgabewert
Index von 0 bis count−1 bei Bestätigung mit A. 255 bedeutet Abbruch mit B oder count gleich null; unterscheiden Sie dies bei Bedarf im aufrufenden Code. Die Funktion schließt den Textbereich nicht und löscht die Liste nicht.
Bedingungen und Grenzen
Verwenden Sie ein gültiges BG-Rechteck und laden Sie Schrift- und Rahmenkacheln vorher. Der Softwaretextbereich verwendet die durch LCDC-Bit 3 gewählte BG-Karte und aktiviert nicht die Hardware-Window-Ebene. Nutzen Sie auf CGB VBK 0 für Kachelnummern und setzen Sie Farbattribute getrennt. Die Beispiele liefern ASCII-zugeordnete Schrift sowie Rahmen-, Cursor- und Seitenmarkierungskacheln. Dialoge und Auswahltexte verwenden Byte-Kachel-IDs ohne UTF-8-Decodierung. Für andere Zeichen liefern Sie Glyphenkacheln und codieren Texte mit deren IDs; Dialogsteuerbytes müssen reserviert bleiben.
Öffnen und dimensionieren Sie den Bereich vorher. Die Auswahlroutine nutzt seine gespeicherte Position, ohne den offenen Zustand zu prüfen. Texte beginnen zwei Spalten innerhalb der linken und eine Zeile unter der oberen Kante; der Cursor steht direkt links daneben. Die Auswahltexte verwenden nicht die Dialogzeichengeschwindigkeit.
Die Eingabeschleife reagiert auf neue Tastendrücke, UP vor DOWN und A vor B. Gehaltene Richtungen wiederholen die Bewegung nicht; lassen Sie los und drücken Sie erneut. Da die vorige Tastenmaske mit null beginnt, kann eine gehaltene Taste beim Eintritt sofort wirken. Gleichzeitige Bewegung und A liefern den neuen Index, obwohl der zuletzt gezeichnete Cursor noch die vorherige Position zeigen kann.
Diese Hilfsfunktionen blockieren: Während des Wartens rufen sie weder Spielaktualisierung noch Musikdienst oder Zeichenschleife auf. Bei ausgeschaltetem LCD kehrt __wait_vblank sofort zurück; Zeichengeschwindigkeit und WAIT erzeugen dann keine Frame-Verzögerung. Lassen Sie das LCD für zeitgesteuerte Dialoge und framegetaktete Eingaben eingeschaltet. Verwenden Sie eine spielseitige Zustandsmaschine, wenn während des Gesprächs andere Arbeit weiterlaufen muss.
Die zugrunde liegenden sicheren Kachelschreibzugriffe warten bei aktivem LCD auf beschreibbare Modi und verwenden DI/EI um die Schreibzugriffe. Sie können Interrupts aktivieren, statt einen anfänglich deaktivierten Zustand zu erhalten. Rufen Sie diese blockierenden Helfer nicht aus Interrupt-Handlern auf und verlassen Sie sich nicht auf die Erhaltung dieses Zustands.
Jedes vollständige Beispiel bindet text.c einmal ein. Bauen Sie mit den Include-Verzeichnissen der Bibliothek und Handbuchbeispiele; fügen Sie lib/text.c nicht zusätzlich als Quelldatei hinzu. Das Far-Stream-Beispiel nutzt MBC5 mit 64 KiB ROM, damit die Daten in Bank 2 enthalten sind.
Anwendungsbeispiel
selected=text_choice(dialogue_choices,3);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Drücken Sie einmal DOWN und dann A. In der Aufnahme steht der Rechtspfeilcursor neben SHIELD bei Kachel (2,4), und SELECTED zeigt 1. Die Texte beginnen bei (3,3), (3,4) und (3,5). Rahmen, Cursor und Texte sind auf CGB grün, auf DMG schwarz; Ergebnis und Hinweise bleiben schwarz.
Die Emulatorprüfungen vergleichen die vollständige BG-Karte und vier Beispielbilder. Weitere Läufe decken Öffnen/Schließen, gewöhnliche und bankbezogene Steuerströme, Zeitwarten, explizites und automatisches Seitenwarten, A/B/START-Fortschaltung, gehaltene Tasten, umlaufende Auswahl, leere Listen und gleichzeitige Eingabeprioritäten ab. Prüfpunkte vor und nach geskripteten Eingaben belegen das tatsächliche Blockieren beim Seitenwarten. Physische Hardware und Interruptparallelität sind nicht getestet.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Füllt einen rechteckigen Bereich der Hintergrund-Tilemap mit TEXT_TILE_FILL. Damit können Sie eine Beschriftung, ein Zahlenfeld oder einen Teil eines Panels löschen. Der aktive Textcursor, der Öffnungszustand und die Abmessungen des Textbereichs bleiben unverändert.
Syntax
void text_clear_rect(u8 x, u8 y, u8 w, u8 h);Parameter
xStartspalte in 8×8-Zellen der Hintergrundkarte. Die gesamte Ausgabe muss innerhalb der Spalten 0–31 liegen. Ohne Hintergrund-Scrolling sind die Spalten 0–19 sichtbar.
yStartzeile in 8×8-Zellen der Hintergrundkarte, 0–31. Ohne Hintergrund-Scrolling sind die Zeilen 0–17 sichtbar. Ein Rechteck muss auch in vertikaler Richtung vollständig in die Karte passen.
wBreite in Tile-Zellen. Bei text_window sind beide Randspalten enthalten; innen bleiben max(w−2, 0) Spalten. Bei text_clear_rect ist dies die Anzahl der zu füllenden Zellen pro Zeile.
hHöhe in Tile-Zellen. Bei text_window sind oberer und unterer Rand enthalten; innen bleiben max(h−2, 0) Zeilen. Bei text_clear_rect ist dies die Anzahl der zu füllenden Zeilen.
Rückgabewert
Kein Rückgabewert. Die Funktion beschreibt die Tilemap-Zellen vor der Rückkehr; sie liefert weder eine Zeichenanzahl noch einen Statuscode.
Bedingungen und Grenzen
Diese Funktionen zeichnen auf die durch LCDC-Bit 3 gewählte BG-Karte. Das Textfenster ist ein Softwarebereich auf dieser Karte, nicht die Hardware-Window-Ebene. Halten Sie CGB-VBK für Tile-Nummern auf 0; diese Aufrufe setzen weder Farbattribute noch Paletten oder Scrolling.
Laden Sie Schrift und Rahmengrafiken vor dem Zeichnen. Die Standard-Rahmen-IDs sind 1–6, das Füll-Tile ist 0 und die Dezimalziffern beginnen bei ASCII 0 (Tile 48). Das Minuszeichen verwendet ASCII - (Tile 45). Das Beispiel enthält sechs Rahmen-Tiles und die Schrift des Handbuchs mit zu ASCII passenden Glyphen-IDs.
Halten Sie Rechtecke und Text innerhalb der 32×32-Karte. Die Rechteckfüllung begrenzt Breite und Höhe nicht auf den Kartenrand. Bei Breite oder Höhe null wird nichts gefüllt; text_window merkt sich den Bereich trotzdem als geöffnet, jedoch ohne nutzbaren Innenraum.
Die öffentlichen Zahlenfunktionen verwenden genau die Breite des neuen Werts. Rechts verbleibende Zellen werden nicht gelöscht. Wird an derselben Position 7 über 12345 geschrieben, erscheint 72345. Löschen Sie das reservierte Fünf-Zellen-Feld vor der Ausgabe mit text_clear_rect, damit nur 7 erscheint. Für ein vorzeichenbehaftetes 16-Bit-Feld sind sechs Zellen nötig.
Die Intrinsics für Tile-Schreibzugriffe prüfen den LCD-Zustand: Bei ausgeschaltetem LCD schreiben sie sofort; andernfalls warten sie auf beschreibbare LCD-Modi und umgeben die Zugriffe mit DI/EI. Dieser Pfad kann bei der Rückkehr Interrupts aktivieren. Verlassen Sie sich daher nicht darauf, dass ein deaktivierter Interruptzustand erhalten bleibt. Die Beispiele und Byte-Tests hier schreiben bei ausgeschaltetem LCD.
Das vollständige Beispiel bindet text.c genau einmal ein, damit die Bibliotheksimplementierung mit dem Programm kompiliert wird. Übergeben Sie lib/text.c für dieses Beispiel nicht zusätzlich als separate Eingabe. Definieren Sie angepasste TEXT_*-Tile-Konstanten vor dem Einbinden von rpg.h und der Implementierung. Verwenden Sie überall, wo die Bibliothek kompiliert wird, dieselben Definitionen.
Anwendungsbeispiel
text_clear_rect(7,5,5,1);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Anfangs steht im Rahmen in Zeile 5 KEEP ERASE KEEP. Das Löschen von fünf Zellen ab (7,5) entfernt ERASE; beide KEEP-Beschriftungen und der Rahmen bleiben erhalten. Auch die Zeile CLEAN löscht vor der Ausgabe von 7 ein Zahlenfeld mit fünf Zellen.
Die Prüfung vergleicht alle sichtbaren Pixel und sämtliche 1024 Bytes der BG-Karte in beiden Beispielbildern. Separate DMG/CGB-ROMs prüfen alle 256 vorzeichenlosen Byte-Werte, Dezimalstellenübergänge und vorzeichenbehaftete Extremwerte. Punkte neben jeder Zahl bleiben als Wächter erhalten. Die Layoutprüfungen umfassen leere und schmale Rechtecke, Platzierung am Kartenrand, rohe Tile-Bytes mit Steuercodewerten sowie den Fenstercursor nach absoluten Schreibzugriffen. Dies sind Emulatortests, keine Tests auf physischer Hardware.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Löscht den aktiven Textbereich einschließlich Rahmen mit TEXT_TILE_FILL und markiert ihn als geschlossen. Ein erneuter Aufruf im geschlossenen Zustand tut nichts. Die Hintergrundkacheln vor dem Öffnen werden nicht wiederhergestellt.
Syntax
void text_close();Rückgabewert
Kein Rückgabewert. Zeichnen und blockierende Wartevorgänge erfolgen vor der Rückkehr.
Bedingungen und Grenzen
Verwenden Sie ein gültiges BG-Rechteck und laden Sie Schrift- und Rahmenkacheln vorher. Der Softwaretextbereich verwendet die durch LCDC-Bit 3 gewählte BG-Karte und aktiviert nicht die Hardware-Window-Ebene. Nutzen Sie auf CGB VBK 0 für Kachelnummern und setzen Sie Farbattribute getrennt. Die Beispiele liefern ASCII-zugeordnete Schrift sowie Rahmen-, Cursor- und Seitenmarkierungskacheln. Dialoge und Auswahltexte verwenden Byte-Kachel-IDs ohne UTF-8-Decodierung. Für andere Zeichen liefern Sie Glyphenkacheln und codieren Texte mit deren IDs; Dialogsteuerbytes müssen reserviert bleiben.
Gewöhnliche Zeichen werden bei geschlossenem Bereich oder ohne nutzbaren Innenraum ignoriert. Steuerbytes werden weiterhin ausgewertet: WAIT kann blockieren, Seitenbefehle können warten oder den gespeicherten Bereich löschen. text_print auf einem geschlossenen Bereich ist daher nicht grundsätzlich wirkungslos.
Diese Hilfsfunktionen blockieren: Während des Wartens rufen sie weder Spielaktualisierung noch Musikdienst oder Zeichenschleife auf. Bei ausgeschaltetem LCD kehrt __wait_vblank sofort zurück; Zeichengeschwindigkeit und WAIT erzeugen dann keine Frame-Verzögerung. Lassen Sie das LCD für zeitgesteuerte Dialoge und framegetaktete Eingaben eingeschaltet. Verwenden Sie eine spielseitige Zustandsmaschine, wenn während des Gesprächs andere Arbeit weiterlaufen muss.
Die zugrunde liegenden sicheren Kachelschreibzugriffe warten bei aktivem LCD auf beschreibbare Modi und verwenden DI/EI um die Schreibzugriffe. Sie können Interrupts aktivieren, statt einen anfänglich deaktivierten Zustand zu erhalten. Rufen Sie diese blockierenden Helfer nicht aus Interrupt-Handlern auf und verlassen Sie sich nicht auf die Erhaltung dieses Zustands.
Jedes vollständige Beispiel bindet text.c einmal ein. Bauen Sie mit den Include-Verzeichnissen der Bibliothek und Handbuchbeispiele; fügen Sie lib/text.c nicht zusätzlich als Quelldatei hinzu. Das Far-Stream-Beispiel nutzt MBC5 mit 64 KiB ROM, damit die Daten in Bank 2 enthalten sind.
Anwendungsbeispiel
text_close();
text_print("HIDDEN"); // With the area closed, ordinary characters are not drawn.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel öffnet bei (1,9) einen Bereich von 18×3 Zellen, schreibt ERASE ME, schließt ihn und versucht HIDDEN zu schreiben. Unter CLOSED AREA müssen Zellen x=1–18 und y=9–11 leer sein; weder Text noch Rahmen dürfen bleiben. Der blaue Dialog darüber bleibt sichtbar.
Die Emulatorprüfungen vergleichen die vollständige BG-Karte und vier Beispielbilder. Weitere Läufe decken Öffnen/Schließen, gewöhnliche und bankbezogene Steuerströme, Zeitwarten, explizites und automatisches Seitenwarten, A/B/START-Fortschaltung, gehaltene Tasten, umlaufende Auswahl, leere Listen und gleichzeitige Eingabeprioritäten ab. Prüfpunkte vor und nach geskripteten Eingaben belegen das tatsächliche Blockieren beim Seitenwarten. Physische Hardware und Interruptparallelität sind nicht getestet.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Öffnet einen softwareseitigen Textbereich auf der Hintergrundkarte. Speichert Position und Größe, setzt den Zeichencursor auf die erste Innenzelle, zeichnet den Rahmen und leert das Innere. Ein weiterer Bereich ersetzt den aktiven Bereich und Cursor, löscht aber keinen bereits an anderer Stelle gezeichneten Bereich.
Syntax
void text_open(u8 x, u8 y, u8 w, u8 h);Parameter
xLinke Spalte des Bereichs in 8×8-BG-Kartenzellen. Die gesamte Breite muss in Spalten 0–31 liegen.
yObere Zeile des Bereichs in 8×8-BG-Kartenzellen. Die gesamte Höhe muss in Zeilen 0–31 liegen.
wGesamtbreite in Zellen einschließlich linker und rechter Rahmenkante. Für eine innere Zeichenspalte sind mindestens drei Zellen nötig.
hGesamthöhe in Zellen einschließlich oberer und unterer Rahmenkante. Für eine innere Zeichenzeile sind mindestens drei Zellen nötig.
Rückgabewert
Kein Rückgabewert. Zeichnen und blockierende Wartevorgänge erfolgen vor der Rückkehr.
Bedingungen und Grenzen
Verwenden Sie ein gültiges BG-Rechteck und laden Sie Schrift- und Rahmenkacheln vorher. Der Softwaretextbereich verwendet die durch LCDC-Bit 3 gewählte BG-Karte und aktiviert nicht die Hardware-Window-Ebene. Nutzen Sie auf CGB VBK 0 für Kachelnummern und setzen Sie Farbattribute getrennt. Die Beispiele liefern ASCII-zugeordnete Schrift sowie Rahmen-, Cursor- und Seitenmarkierungskacheln. Dialoge und Auswahltexte verwenden Byte-Kachel-IDs ohne UTF-8-Decodierung. Für andere Zeichen liefern Sie Glyphenkacheln und codieren Texte mit deren IDs; Dialogsteuerbytes müssen reserviert bleiben.
Diese Hilfsfunktionen blockieren: Während des Wartens rufen sie weder Spielaktualisierung noch Musikdienst oder Zeichenschleife auf. Bei ausgeschaltetem LCD kehrt __wait_vblank sofort zurück; Zeichengeschwindigkeit und WAIT erzeugen dann keine Frame-Verzögerung. Lassen Sie das LCD für zeitgesteuerte Dialoge und framegetaktete Eingaben eingeschaltet. Verwenden Sie eine spielseitige Zustandsmaschine, wenn während des Gesprächs andere Arbeit weiterlaufen muss.
Die zugrunde liegenden sicheren Kachelschreibzugriffe warten bei aktivem LCD auf beschreibbare Modi und verwenden DI/EI um die Schreibzugriffe. Sie können Interrupts aktivieren, statt einen anfänglich deaktivierten Zustand zu erhalten. Rufen Sie diese blockierenden Helfer nicht aus Interrupt-Handlern auf und verlassen Sie sich nicht auf die Erhaltung dieses Zustands.
Jedes vollständige Beispiel bindet text.c einmal ein. Bauen Sie mit den Include-Verzeichnissen der Bibliothek und Handbuchbeispiele; fügen Sie lib/text.c nicht zusätzlich als Quelldatei hinzu. Das Far-Stream-Beispiel nutzt MBC5 mit 64 KiB ROM, damit die Daten in Bank 2 enthalten sind.
Anwendungsbeispiel
text_open(1,2,18,5);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
DIALOGUE FLOW öffnet bei (1,2) einen Rahmen von 18×5 Zellen mit 16×3 Innenzellen. NEAR, READY und BANK 2 belegen die drei Zeilen. Sichtbare Rahmenlinien reichen von Pixel x=11 bis 147 und y=19 bis 51. Rahmen und Text sind auf CGB blau, auf DMG schwarz. Der später geöffnete Löschtestbereich lässt diesen Rahmen sichtbar.
Die Emulatorprüfungen vergleichen die vollständige BG-Karte und vier Beispielbilder. Weitere Läufe decken Öffnen/Schließen, gewöhnliche und bankbezogene Steuerströme, Zeitwarten, explizites und automatisches Seitenwarten, A/B/START-Fortschaltung, gehaltene Tasten, umlaufende Auswahl, leere Listen und gleichzeitige Eingabeprioritäten ab. Prüfpunkte vor und nach geskripteten Eingaben belegen das tatsächliche Blockieren beim Seitenwarten. Physische Hardware und Interruptparallelität sind nicht getestet.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Liest einen Steuerstrom über einen gewöhnlichen Zeiger und schreibt dessen Zeichenkacheln am aktiven Fenstercursor. Verarbeitet Zeilenumbrüche, Zeit- und Seitenwartebefehle und bricht an der Innenbreite um. Kehrt erst bei END zurück; Seitenwarten kann daher bis zu einem Tastendruck blockieren.
Syntax
void text_print(const u8* str);Parameter
strLesbarer Zeiger auf einen mit TEXT_CTRL_END (0) terminierten Strom. Halten Sie ihn während blockierender Wartezeiten vollständig eingeblendet, einschließlich aller Operanden nach WAIT. Pufferlänge und Gültigkeit werden nicht geprüft.
Rückgabewert
Kein Rückgabewert. Zeichnen und blockierende Wartevorgänge erfolgen vor der Rückkehr.
Bedingungen und Grenzen
Verwenden Sie ein gültiges BG-Rechteck und laden Sie Schrift- und Rahmenkacheln vorher. Der Softwaretextbereich verwendet die durch LCDC-Bit 3 gewählte BG-Karte und aktiviert nicht die Hardware-Window-Ebene. Nutzen Sie auf CGB VBK 0 für Kachelnummern und setzen Sie Farbattribute getrennt. Die Beispiele liefern ASCII-zugeordnete Schrift sowie Rahmen-, Cursor- und Seitenmarkierungskacheln. Dialoge und Auswahltexte verwenden Byte-Kachel-IDs ohne UTF-8-Decodierung. Für andere Zeichen liefern Sie Glyphenkacheln und codieren Texte mit deren IDs; Dialogsteuerbytes müssen reserviert bleiben.
Steuerbytes: 0x00 beendet den Strom; 0x0A wechselt zur nächsten Innenzeile; 0x01 liest das folgende Byte als Anzahl von VBlank-Wartevorgängen einschließlich null; 0x02 wartet auf Seitenwechsel, leert das Innere und setzt den Cursor zurück. Andere Bytes sind Kachel-IDs. Ein WAIT-Operand null ist kein END-Marker.
Ein Umbruch unter die letzte Innenzeile zeigt die Seitenwartemarkierung, wartet auf A, B oder START, leert das Innere und setzt in der ersten Zelle fort. Die Seite wird ersetzt, nicht zeilenweise gescrollt. Explizites 0x02 wartet ohne zusätzliche Markierung. Die Seitenabfrage beginnt ohne gespeicherte Tasten; eine schon beim Wartebeginn gehaltene Taste kann daher weiterschalten.
Gewöhnliche Zeichen werden bei geschlossenem Bereich oder ohne nutzbaren Innenraum ignoriert. Steuerbytes werden weiterhin ausgewertet: WAIT kann blockieren, Seitenbefehle können warten oder den gespeicherten Bereich löschen. text_print auf einem geschlossenen Bereich ist daher nicht grundsätzlich wirkungslos.
Diese Hilfsfunktionen blockieren: Während des Wartens rufen sie weder Spielaktualisierung noch Musikdienst oder Zeichenschleife auf. Bei ausgeschaltetem LCD kehrt __wait_vblank sofort zurück; Zeichengeschwindigkeit und WAIT erzeugen dann keine Frame-Verzögerung. Lassen Sie das LCD für zeitgesteuerte Dialoge und framegetaktete Eingaben eingeschaltet. Verwenden Sie eine spielseitige Zustandsmaschine, wenn während des Gesprächs andere Arbeit weiterlaufen muss.
Die zugrunde liegenden sicheren Kachelschreibzugriffe warten bei aktivem LCD auf beschreibbare Modi und verwenden DI/EI um die Schreibzugriffe. Sie können Interrupts aktivieren, statt einen anfänglich deaktivierten Zustand zu erhalten. Rufen Sie diese blockierenden Helfer nicht aus Interrupt-Handlern auf und verlassen Sie sich nicht auf die Erhaltung dieses Zustands.
Jedes vollständige Beispiel bindet text.c einmal ein. Bauen Sie mit den Include-Verzeichnissen der Bibliothek und Handbuchbeispiele; fügen Sie lib/text.c nicht zusätzlich als Quelldatei hinzu. Das Far-Stream-Beispiel nutzt MBC5 mit 64 KiB ROM, damit die Daten in Bank 2 enthalten sind.
Anwendungsbeispiel
text_print(dialogue_near);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Der gewöhnliche Strom schreibt NEAR, Zeilenumbruch, READY und einen Zwölffach-Wartebefehl vor END. NEAR beginnt bei Kachel (2,3), READY bei (2,4). Der folgende bankbezogene Strom nutzt denselben Cursor weiter; sein erster Umbruch setzt BANK 2 daher in die dritte Innenzeile.
Die Emulatorprüfungen vergleichen die vollständige BG-Karte und vier Beispielbilder. Weitere Läufe decken Öffnen/Schließen, gewöhnliche und bankbezogene Steuerströme, Zeitwarten, explizites und automatisches Seitenwarten, A/B/START-Fortschaltung, gehaltene Tasten, umlaufende Auswahl, leere Listen und gleichzeitige Eingabeprioritäten ab. Prüfpunkte vor und nach geskripteten Eingaben belegen das tatsächliche Blockieren beim Seitenwarten. Physische Hardware und Interruptparallelität sind nicht getestet.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Interpretiert denselben Dialogsteuerstrom, liest aber jedes Byte mit __farpeek8 aus der angegebenen ROM-Bank. Verwenden Sie dies für Dialoge außerhalb der aktuell eingeblendeten Quellbank. Zeichenplatzierung, Geschwindigkeit, Umbruch und Seitensteuerung entsprechen text_print.
Syntax
void text_print_far(u8 bank, const u8* str);Parameter
bankVorzeichenlose 8-Bit-Nummer der ROM-Quellbank. Das Beispiel speichert den Strom in Bank 2 und prüft, dass der aufrufende Code nach der Ausgabe weiterhin eine Markierung in Bank 1 lesen kann.
strCPU-Adresse des Stroms in der angegebenen Bank. Die Adresse schreitet fort, die Banknummer bleibt gleich; das Überschreiten des umschaltbaren ROM-Fensters setzt nicht automatisch in der nächsten Bank fort.
Rückgabewert
Kein Rückgabewert. Zeichnen und blockierende Wartevorgänge erfolgen vor der Rückkehr.
Bedingungen und Grenzen
Verwenden Sie ein gültiges BG-Rechteck und laden Sie Schrift- und Rahmenkacheln vorher. Der Softwaretextbereich verwendet die durch LCDC-Bit 3 gewählte BG-Karte und aktiviert nicht die Hardware-Window-Ebene. Nutzen Sie auf CGB VBK 0 für Kachelnummern und setzen Sie Farbattribute getrennt. Die Beispiele liefern ASCII-zugeordnete Schrift sowie Rahmen-, Cursor- und Seitenmarkierungskacheln. Dialoge und Auswahltexte verwenden Byte-Kachel-IDs ohne UTF-8-Decodierung. Für andere Zeichen liefern Sie Glyphenkacheln und codieren Texte mit deren IDs; Dialogsteuerbytes müssen reserviert bleiben.
Steuerbytes: 0x00 beendet den Strom; 0x0A wechselt zur nächsten Innenzeile; 0x01 liest das folgende Byte als Anzahl von VBlank-Wartevorgängen einschließlich null; 0x02 wartet auf Seitenwechsel, leert das Innere und setzt den Cursor zurück. Andere Bytes sind Kachel-IDs. Ein WAIT-Operand null ist kein END-Marker.
Ein Umbruch unter die letzte Innenzeile zeigt die Seitenwartemarkierung, wartet auf A, B oder START, leert das Innere und setzt in der ersten Zelle fort. Die Seite wird ersetzt, nicht zeilenweise gescrollt. Explizites 0x02 wartet ohne zusätzliche Markierung. Die Seitenabfrage beginnt ohne gespeicherte Tasten; eine schon beim Wartebeginn gehaltene Taste kann daher weiterschalten.
Gewöhnliche Zeichen werden bei geschlossenem Bereich oder ohne nutzbaren Innenraum ignoriert. Steuerbytes werden weiterhin ausgewertet: WAIT kann blockieren, Seitenbefehle können warten oder den gespeicherten Bereich löschen. text_print auf einem geschlossenen Bereich ist daher nicht grundsätzlich wirkungslos.
Diese Hilfsfunktionen blockieren: Während des Wartens rufen sie weder Spielaktualisierung noch Musikdienst oder Zeichenschleife auf. Bei ausgeschaltetem LCD kehrt __wait_vblank sofort zurück; Zeichengeschwindigkeit und WAIT erzeugen dann keine Frame-Verzögerung. Lassen Sie das LCD für zeitgesteuerte Dialoge und framegetaktete Eingaben eingeschaltet. Verwenden Sie eine spielseitige Zustandsmaschine, wenn während des Gesprächs andere Arbeit weiterlaufen muss.
Die zugrunde liegenden sicheren Kachelschreibzugriffe warten bei aktivem LCD auf beschreibbare Modi und verwenden DI/EI um die Schreibzugriffe. Sie können Interrupts aktivieren, statt einen anfänglich deaktivierten Zustand zu erhalten. Rufen Sie diese blockierenden Helfer nicht aus Interrupt-Handlern auf und verlassen Sie sich nicht auf die Erhaltung dieses Zustands.
Jedes vollständige Beispiel bindet text.c einmal ein. Bauen Sie mit den Include-Verzeichnissen der Bibliothek und Handbuchbeispiele; fügen Sie lib/text.c nicht zusätzlich als Quelldatei hinzu. Das Far-Stream-Beispiel nutzt MBC5 mit 64 KiB ROM, damit die Daten in Bank 2 enthalten sind.
Anwendungsbeispiel
text_print_far(2,dialogue_far);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel liest Zeilenumbruch und BANK 2 aus ROM-Bank 2. BANK RESTORED zeigt durch anschließendes Lesen der Markierung in Bank 1 des Aufrufers den Wert 161. Die sichtbare BANK-2-Zeile beginnt bei Kachel (2,5), die Rückkehrbestätigung steht bei (16,14).
Die Emulatorprüfungen vergleichen die vollständige BG-Karte und vier Beispielbilder. Weitere Läufe decken Öffnen/Schließen, gewöhnliche und bankbezogene Steuerströme, Zeitwarten, explizites und automatisches Seitenwarten, A/B/START-Fortschaltung, gehaltene Tasten, umlaufende Auswahl, leere Listen und gleichzeitige Eingabeprioritäten ab. Prüfpunkte vor und nach geskripteten Eingaben belegen das tatsächliche Blockieren beim Seitenwarten. Physische Hardware und Interruptparallelität sind nicht getestet.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet einen vorzeichenbehafteten 16-Bit-Wert als Dezimalzahl. Negative Werte beginnen mit dem Minus-Tile, gefolgt vom Betrag; null und positive Werte erhalten kein Vorzeichen. Die längste Ausgabe ist -32768 mit sechs Zellen.
Syntax
void text_print_s16(u8 x, u8 y, s16 value);Parameter
xStartspalte in 8×8-Zellen der Hintergrundkarte. Die gesamte Ausgabe muss innerhalb der Spalten 0–31 liegen. Ohne Hintergrund-Scrolling sind die Spalten 0–19 sichtbar.
yStartzeile in 8×8-Zellen der Hintergrundkarte, 0–31. Ohne Hintergrund-Scrolling sind die Zeilen 0–17 sichtbar. Ein Rechteck muss auch in vertikaler Richtung vollständig in die Karte passen.
valueVorzeichenbehafteter Wert von −32768 bis 32767. Das Beispiel castet das 16-Bit-Muster 32768 (0x8000) nach s16, um −32768 anzuzeigen.
Rückgabewert
Kein Rückgabewert. Die Funktion beschreibt die Tilemap-Zellen vor der Rückkehr; sie liefert weder eine Zeichenanzahl noch einen Statuscode.
Bedingungen und Grenzen
Diese Funktionen zeichnen auf die durch LCDC-Bit 3 gewählte BG-Karte. Das Textfenster ist ein Softwarebereich auf dieser Karte, nicht die Hardware-Window-Ebene. Halten Sie CGB-VBK für Tile-Nummern auf 0; diese Aufrufe setzen weder Farbattribute noch Paletten oder Scrolling.
Laden Sie Schrift und Rahmengrafiken vor dem Zeichnen. Die Standard-Rahmen-IDs sind 1–6, das Füll-Tile ist 0 und die Dezimalziffern beginnen bei ASCII 0 (Tile 48). Das Minuszeichen verwendet ASCII - (Tile 45). Das Beispiel enthält sechs Rahmen-Tiles und die Schrift des Handbuchs mit zu ASCII passenden Glyphen-IDs.
Halten Sie Rechtecke und Text innerhalb der 32×32-Karte. Die Rechteckfüllung begrenzt Breite und Höhe nicht auf den Kartenrand. Bei Breite oder Höhe null wird nichts gefüllt; text_window merkt sich den Bereich trotzdem als geöffnet, jedoch ohne nutzbaren Innenraum.
Die öffentlichen Zahlenfunktionen verwenden genau die Breite des neuen Werts. Rechts verbleibende Zellen werden nicht gelöscht. Wird an derselben Position 7 über 12345 geschrieben, erscheint 72345. Löschen Sie das reservierte Fünf-Zellen-Feld vor der Ausgabe mit text_clear_rect, damit nur 7 erscheint. Für ein vorzeichenbehaftetes 16-Bit-Feld sind sechs Zellen nötig.
Die Intrinsics für Tile-Schreibzugriffe prüfen den LCD-Zustand: Bei ausgeschaltetem LCD schreiben sie sofort; andernfalls warten sie auf beschreibbare LCD-Modi und umgeben die Zugriffe mit DI/EI. Dieser Pfad kann bei der Rückkehr Interrupts aktivieren. Verlassen Sie sich daher nicht darauf, dass ein deaktivierter Interruptzustand erhalten bleibt. Die Beispiele und Byte-Tests hier schreiben bei ausgeschaltetem LCD.
Das vollständige Beispiel bindet text.c genau einmal ein, damit die Bibliotheksimplementierung mit dem Programm kompiliert wird. Übergeben Sie lib/text.c für dieses Beispiel nicht zusätzlich als separate Eingabe. Definieren Sie angepasste TEXT_*-Tile-Konstanten vor dem Einbinden von rpg.h und der Implementierung. Verwenden Sie überall, wo die Bibliothek kompiliert wird, dieselben Definitionen.
Anwendungsbeispiel
text_print_s16(11,12,(s16)32768);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Die Zeile S16 zeigt -32768 ab (11,12) in sechs Zellen einschließlich Minuszeichen, auf CGB in Grün. Damit wird der kleinste vorzeichenbehaftete 16-Bit-Wert geprüft, dessen positiver Betrag nicht in s16 passt.
Die Prüfung vergleicht alle sichtbaren Pixel und sämtliche 1024 Bytes der BG-Karte in beiden Beispielbildern. Separate DMG/CGB-ROMs prüfen alle 256 vorzeichenlosen Byte-Werte, Dezimalstellenübergänge und vorzeichenbehaftete Extremwerte. Punkte neben jeder Zahl bleiben als Wächter erhalten. Die Layoutprüfungen umfassen leere und schmale Rechtecke, Platzierung am Kartenrand, rohe Tile-Bytes mit Steuercodewerten sowie den Fenstercursor nach absoluten Schreibzugriffen. Dies sind Emulatortests, keine Tests auf physischer Hardware.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet einen vorzeichenlosen 16-Bit-Wert als Dezimalzahl ab der angegebenen Tile-Position. Die Ausgabe belegt eine bis fünf Zellen ohne führende Nullen. Verwenden Sie dies für Punktestände oder Objektanzahlen, die 255 überschreiten können.
Syntax
void text_print_u16(u8 x, u8 y, u16 value);Parameter
xStartspalte in 8×8-Zellen der Hintergrundkarte. Die gesamte Ausgabe muss innerhalb der Spalten 0–31 liegen. Ohne Hintergrund-Scrolling sind die Spalten 0–19 sichtbar.
yStartzeile in 8×8-Zellen der Hintergrundkarte, 0–31. Ohne Hintergrund-Scrolling sind die Zeilen 0–17 sichtbar. Ein Rechteck muss auch in vertikaler Richtung vollständig in die Karte passen.
valueVorzeichenloser Wert von 0 bis 65535.
Rückgabewert
Kein Rückgabewert. Die Funktion beschreibt die Tilemap-Zellen vor der Rückkehr; sie liefert weder eine Zeichenanzahl noch einen Statuscode.
Bedingungen und Grenzen
Diese Funktionen zeichnen auf die durch LCDC-Bit 3 gewählte BG-Karte. Das Textfenster ist ein Softwarebereich auf dieser Karte, nicht die Hardware-Window-Ebene. Halten Sie CGB-VBK für Tile-Nummern auf 0; diese Aufrufe setzen weder Farbattribute noch Paletten oder Scrolling.
Laden Sie Schrift und Rahmengrafiken vor dem Zeichnen. Die Standard-Rahmen-IDs sind 1–6, das Füll-Tile ist 0 und die Dezimalziffern beginnen bei ASCII 0 (Tile 48). Das Minuszeichen verwendet ASCII - (Tile 45). Das Beispiel enthält sechs Rahmen-Tiles und die Schrift des Handbuchs mit zu ASCII passenden Glyphen-IDs.
Halten Sie Rechtecke und Text innerhalb der 32×32-Karte. Die Rechteckfüllung begrenzt Breite und Höhe nicht auf den Kartenrand. Bei Breite oder Höhe null wird nichts gefüllt; text_window merkt sich den Bereich trotzdem als geöffnet, jedoch ohne nutzbaren Innenraum.
Die öffentlichen Zahlenfunktionen verwenden genau die Breite des neuen Werts. Rechts verbleibende Zellen werden nicht gelöscht. Wird an derselben Position 7 über 12345 geschrieben, erscheint 72345. Löschen Sie das reservierte Fünf-Zellen-Feld vor der Ausgabe mit text_clear_rect, damit nur 7 erscheint. Für ein vorzeichenbehaftetes 16-Bit-Feld sind sechs Zellen nötig.
Die Intrinsics für Tile-Schreibzugriffe prüfen den LCD-Zustand: Bei ausgeschaltetem LCD schreiben sie sofort; andernfalls warten sie auf beschreibbare LCD-Modi und umgeben die Zugriffe mit DI/EI. Dieser Pfad kann bei der Rückkehr Interrupts aktivieren. Verlassen Sie sich daher nicht darauf, dass ein deaktivierter Interruptzustand erhalten bleibt. Die Beispiele und Byte-Tests hier schreiben bei ausgeschaltetem LCD.
Das vollständige Beispiel bindet text.c genau einmal ein, damit die Bibliotheksimplementierung mit dem Programm kompiliert wird. Übergeben Sie lib/text.c für dieses Beispiel nicht zusätzlich als separate Eingabe. Definieren Sie angepasste TEXT_*-Tile-Konstanten vor dem Einbinden von rpg.h und der Implementierung. Verwenden Sie überall, wo die Bibliothek kompiliert wird, dieselben Definitionen.
Anwendungsbeispiel
text_print_u16(11,10,65535);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Die Zeile U16 zeigt 65535 bei (11,10) in fünf Zellen, auf CGB in Blau. OVERWRITE zeigt 72345, nachdem 7 über 12345 geschrieben wurde, ohne das Fünf-Zellen-Feld vorher zu löschen.
Die Prüfung vergleicht alle sichtbaren Pixel und sämtliche 1024 Bytes der BG-Karte in beiden Beispielbildern. Separate DMG/CGB-ROMs prüfen alle 256 vorzeichenlosen Byte-Werte, Dezimalstellenübergänge und vorzeichenbehaftete Extremwerte. Punkte neben jeder Zahl bleiben als Wächter erhalten. Die Layoutprüfungen umfassen leere und schmale Rechtecke, Platzierung am Kartenrand, rohe Tile-Bytes mit Steuercodewerten sowie den Fenstercursor nach absoluten Schreibzugriffen. Dies sind Emulatortests, keine Tests auf physischer Hardware.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet einen vorzeichenlosen 8-Bit-Wert als Dezimalzahl ab der angegebenen Tile-Position. Der Wert belegt eine bis drei Zellen ohne führende Nullen; null belegt eine Zelle. Geeignet für kleine Zähler wie Leben oder Munition.
Syntax
void text_print_u8(u8 x, u8 y, u8 value);Parameter
xStartspalte in 8×8-Zellen der Hintergrundkarte. Die gesamte Ausgabe muss innerhalb der Spalten 0–31 liegen. Ohne Hintergrund-Scrolling sind die Spalten 0–19 sichtbar.
yStartzeile in 8×8-Zellen der Hintergrundkarte, 0–31. Ohne Hintergrund-Scrolling sind die Zeilen 0–17 sichtbar. Ein Rechteck muss auch in vertikaler Richtung vollständig in die Karte passen.
valueVorzeichenloser Wert von 0 bis 255. Ausdrücke mit größerer Bitbreite werden durch den Funktionsparameter in u8 umgewandelt.
Rückgabewert
Kein Rückgabewert. Die Funktion beschreibt die Tilemap-Zellen vor der Rückkehr; sie liefert weder eine Zeichenanzahl noch einen Statuscode.
Bedingungen und Grenzen
Diese Funktionen zeichnen auf die durch LCDC-Bit 3 gewählte BG-Karte. Das Textfenster ist ein Softwarebereich auf dieser Karte, nicht die Hardware-Window-Ebene. Halten Sie CGB-VBK für Tile-Nummern auf 0; diese Aufrufe setzen weder Farbattribute noch Paletten oder Scrolling.
Laden Sie Schrift und Rahmengrafiken vor dem Zeichnen. Die Standard-Rahmen-IDs sind 1–6, das Füll-Tile ist 0 und die Dezimalziffern beginnen bei ASCII 0 (Tile 48). Das Minuszeichen verwendet ASCII - (Tile 45). Das Beispiel enthält sechs Rahmen-Tiles und die Schrift des Handbuchs mit zu ASCII passenden Glyphen-IDs.
Halten Sie Rechtecke und Text innerhalb der 32×32-Karte. Die Rechteckfüllung begrenzt Breite und Höhe nicht auf den Kartenrand. Bei Breite oder Höhe null wird nichts gefüllt; text_window merkt sich den Bereich trotzdem als geöffnet, jedoch ohne nutzbaren Innenraum.
Die öffentlichen Zahlenfunktionen verwenden genau die Breite des neuen Werts. Rechts verbleibende Zellen werden nicht gelöscht. Wird an derselben Position 7 über 12345 geschrieben, erscheint 72345. Löschen Sie das reservierte Fünf-Zellen-Feld vor der Ausgabe mit text_clear_rect, damit nur 7 erscheint. Für ein vorzeichenbehaftetes 16-Bit-Feld sind sechs Zellen nötig.
Die Intrinsics für Tile-Schreibzugriffe prüfen den LCD-Zustand: Bei ausgeschaltetem LCD schreiben sie sofort; andernfalls warten sie auf beschreibbare LCD-Modi und umgeben die Zugriffe mit DI/EI. Dieser Pfad kann bei der Rückkehr Interrupts aktivieren. Verlassen Sie sich daher nicht darauf, dass ein deaktivierter Interruptzustand erhalten bleibt. Die Beispiele und Byte-Tests hier schreiben bei ausgeschaltetem LCD.
Das vollständige Beispiel bindet text.c genau einmal ein, damit die Bibliotheksimplementierung mit dem Programm kompiliert wird. Übergeben Sie lib/text.c für dieses Beispiel nicht zusätzlich als separate Eingabe. Definieren Sie angepasste TEXT_*-Tile-Konstanten vor dem Einbinden von rpg.h und der Implementierung. Verwenden Sie überall, wo die Bibliothek kompiliert wird, dieselben Definitionen.
Anwendungsbeispiel
text_print_u8(11,8,255);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Die Zeile U8 zeigt 255 ab (11,8) in genau drei Zellen, auf CGB in Blau. OVERWRITE und CLEAN zeigen, warum das Feld beim Ersetzen durch einen kürzeren Wert ausdrücklich gelöscht werden muss.
Die Prüfung vergleicht alle sichtbaren Pixel und sämtliche 1024 Bytes der BG-Karte in beiden Beispielbildern. Separate DMG/CGB-ROMs prüfen alle 256 vorzeichenlosen Byte-Werte, Dezimalstellenübergänge und vorzeichenbehaftete Extremwerte. Punkte neben jeder Zahl bleiben als Wächter erhalten. Die Layoutprüfungen umfassen leere und schmale Rechtecke, Platzierung am Kartenrand, rohe Tile-Bytes mit Steuercodewerten sowie den Fenstercursor nach absoluten Schreibzugriffen. Dies sind Emulatortests, keine Tests auf physischer Hardware.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet eine nullterminierte Folge von Tile-Nummern waagerecht ab einer absoluten Position auf der Hintergrundkarte. Dabei gibt es weder Begrenzung auf das Textfenster noch Zeilenumbruch, Auswertung von Textsteuercodes oder Zeichenverzögerung. Der von text_print verwendete Cursor bleibt unverändert.
Syntax
void text_print_xy(u8 x, u8 y, const u8* str);Parameter
xStartspalte in 8×8-Zellen der Hintergrundkarte. Die gesamte Ausgabe muss innerhalb der Spalten 0–31 liegen. Ohne Hintergrund-Scrolling sind die Spalten 0–19 sichtbar.
yStartzeile in 8×8-Zellen der Hintergrundkarte, 0–31. Ohne Hintergrund-Scrolling sind die Zeilen 0–17 sichtbar. Ein Rechteck muss auch in vertikaler Richtung vollständig in die Karte passen.
strLesbarer Zeiger auf Tile-Bytes mit abschließender 0. Jedes Byte wird direkt als Tile-Nummer verwendet. Ein ASCII-String erscheint nur dann als Text, wenn die passenden Glyphen unter den entsprechenden Tile-IDs liegen. Die Quelle muss bis zur Rückkehr eingeblendet und lesbar bleiben. Diese Funktionen decodieren kein UTF-8 und laden keine Glyphen. Mehrbyte-Text benötigt vor der Anzeige eine vom Spiel definierte Codierung und passende Tile-Daten.
Rückgabewert
Kein Rückgabewert. Die Funktion beschreibt die Tilemap-Zellen vor der Rückkehr; sie liefert weder eine Zeichenanzahl noch einen Statuscode.
Bedingungen und Grenzen
Diese Funktionen zeichnen auf die durch LCDC-Bit 3 gewählte BG-Karte. Das Textfenster ist ein Softwarebereich auf dieser Karte, nicht die Hardware-Window-Ebene. Halten Sie CGB-VBK für Tile-Nummern auf 0; diese Aufrufe setzen weder Farbattribute noch Paletten oder Scrolling.
Laden Sie Schrift und Rahmengrafiken vor dem Zeichnen. Die Standard-Rahmen-IDs sind 1–6, das Füll-Tile ist 0 und die Dezimalziffern beginnen bei ASCII 0 (Tile 48). Das Minuszeichen verwendet ASCII - (Tile 45). Das Beispiel enthält sechs Rahmen-Tiles und die Schrift des Handbuchs mit zu ASCII passenden Glyphen-IDs.
Halten Sie Rechtecke und Text innerhalb der 32×32-Karte. Die Rechteckfüllung begrenzt Breite und Höhe nicht auf den Kartenrand. Bei Breite oder Höhe null wird nichts gefüllt; text_window merkt sich den Bereich trotzdem als geöffnet, jedoch ohne nutzbaren Innenraum.
Die Intrinsics für Tile-Schreibzugriffe prüfen den LCD-Zustand: Bei ausgeschaltetem LCD schreiben sie sofort; andernfalls warten sie auf beschreibbare LCD-Modi und umgeben die Zugriffe mit DI/EI. Dieser Pfad kann bei der Rückkehr Interrupts aktivieren. Verlassen Sie sich daher nicht darauf, dass ein deaktivierter Interruptzustand erhalten bleibt. Die Beispiele und Byte-Tests hier schreiben bei ausgeschaltetem LCD.
Das vollständige Beispiel bindet text.c genau einmal ein, damit die Bibliotheksimplementierung mit dem Programm kompiliert wird. Übergeben Sie lib/text.c für dieses Beispiel nicht zusätzlich als separate Eingabe. Definieren Sie angepasste TEXT_*-Tile-Konstanten vor dem Einbinden von rpg.h und der Implementierung. Verwenden Sie überall, wo die Bibliothek kompiliert wird, dieselben Definitionen.
Anwendungsbeispiel
text_print_xy(2,3,"HELLO!");Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
HELLO! beginnt bei Tile (2,3), Pixel (16,24), innerhalb des roten CGB-Rahmens. Die Position auf der BG-Karte ist absolut: Das Öffnen des Textbereichs addiert keinen Versatz zu x oder y.
Die Prüfung vergleicht alle sichtbaren Pixel und sämtliche 1024 Bytes der BG-Karte in beiden Beispielbildern. Separate DMG/CGB-ROMs prüfen alle 256 vorzeichenlosen Byte-Werte, Dezimalstellenübergänge und vorzeichenbehaftete Extremwerte. Punkte neben jeder Zahl bleiben als Wächter erhalten. Die Layoutprüfungen umfassen leere und schmale Rechtecke, Platzierung am Kartenrand, rohe Tile-Bytes mit Steuercodewerten sowie den Fenstercursor nach absoluten Schreibzugriffen. Dies sind Emulatortests, keine Tests auf physischer Hardware.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Legt die Anzahl der VBlank-Wartevorgänge nach jedem gewöhnlichen Zeichen von text_print oder text_print_far fest. Null entfernt diese Wartezeiten pro Zeichen. Öffnen und Schließen setzen die Einstellung nicht zurück. Explizite WAIT-Befehle warten auch bei Zeichengeschwindigkeit null.
Syntax
void text_set_speed(u8 speed);Parameter
speedVBlank-Wartevorgänge nach jedem dargestellten Zeichen, 0–255. Dies zählt Wartevorgänge, nicht Millisekunden. Die Einstellung beeinflusst weder text_print_xy noch Zahlenhilfsfunktionen oder Auswahlliste.
Rückgabewert
Kein Rückgabewert. Zeichnen und blockierende Wartevorgänge erfolgen vor der Rückkehr.
Bedingungen und Grenzen
Verwenden Sie ein gültiges BG-Rechteck und laden Sie Schrift- und Rahmenkacheln vorher. Der Softwaretextbereich verwendet die durch LCDC-Bit 3 gewählte BG-Karte und aktiviert nicht die Hardware-Window-Ebene. Nutzen Sie auf CGB VBK 0 für Kachelnummern und setzen Sie Farbattribute getrennt. Die Beispiele liefern ASCII-zugeordnete Schrift sowie Rahmen-, Cursor- und Seitenmarkierungskacheln. Dialoge und Auswahltexte verwenden Byte-Kachel-IDs ohne UTF-8-Decodierung. Für andere Zeichen liefern Sie Glyphenkacheln und codieren Texte mit deren IDs; Dialogsteuerbytes müssen reserviert bleiben.
Diese Hilfsfunktionen blockieren: Während des Wartens rufen sie weder Spielaktualisierung noch Musikdienst oder Zeichenschleife auf. Bei ausgeschaltetem LCD kehrt __wait_vblank sofort zurück; Zeichengeschwindigkeit und WAIT erzeugen dann keine Frame-Verzögerung. Lassen Sie das LCD für zeitgesteuerte Dialoge und framegetaktete Eingaben eingeschaltet. Verwenden Sie eine spielseitige Zustandsmaschine, wenn während des Gesprächs andere Arbeit weiterlaufen muss.
Die zugrunde liegenden sicheren Kachelschreibzugriffe warten bei aktivem LCD auf beschreibbare Modi und verwenden DI/EI um die Schreibzugriffe. Sie können Interrupts aktivieren, statt einen anfänglich deaktivierten Zustand zu erhalten. Rufen Sie diese blockierenden Helfer nicht aus Interrupt-Handlern auf und verlassen Sie sich nicht auf die Erhaltung dieses Zustands.
Jedes vollständige Beispiel bindet text.c einmal ein. Bauen Sie mit den Include-Verzeichnissen der Bibliothek und Handbuchbeispiele; fügen Sie lib/text.c nicht zusätzlich als Quelldatei hinzu. Das Far-Stream-Beispiel nutzt MBC5 mit 64 KiB ROM, damit die Daten in Bank 2 enthalten sind.
Anwendungsbeispiel
text_set_speed(2);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Ablaufbeispiel nutzt Geschwindigkeit 2 für gewöhnliche und bankübergreifende Dialoge sowie WAIT-Operand 12. Das fertige Bild zeigt den Text nach dem Warten. Eine getrennte Frame-Aufzeichnung prüft Geschwindigkeit 3, einen expliziten Fünffach-Wartebefehl und vier Wartevorgänge bei geschlossenem Bereich. Das abschließende Bild allein dient nicht als Timingnachweis.
Die Emulatorprüfungen vergleichen die vollständige BG-Karte und vier Beispielbilder. Weitere Läufe decken Öffnen/Schließen, gewöhnliche und bankbezogene Steuerströme, Zeitwarten, explizites und automatisches Seitenwarten, A/B/START-Fortschaltung, gehaltene Tasten, umlaufende Auswahl, leere Listen und gleichzeitige Eingabeprioritäten ab. Prüfpunkte vor und nach geskripteten Eingaben belegen das tatsächliche Blockieren beim Seitenwarten. Physische Hardware und Interruptparallelität sind nicht getestet.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet einen umrahmten Textbereich auf die Hintergrund-Tilemap und aktiviert ihn für die Textausgabe im Fenster. Dieser Alias von text_open setzt den Fenstercursor auf die erste innere Zelle, zeichnet den Rahmen neu und löscht den Innenbereich. Die aktuelle Zeichenverzögerung bleibt erhalten.
Syntax
void text_window(u8 x, u8 y, u8 w, u8 h);Parameter
xStartspalte in 8×8-Zellen der Hintergrundkarte. Die gesamte Ausgabe muss innerhalb der Spalten 0–31 liegen. Ohne Hintergrund-Scrolling sind die Spalten 0–19 sichtbar.
yStartzeile in 8×8-Zellen der Hintergrundkarte, 0–31. Ohne Hintergrund-Scrolling sind die Zeilen 0–17 sichtbar. Ein Rechteck muss auch in vertikaler Richtung vollständig in die Karte passen.
wBreite in Tile-Zellen. Bei text_window sind beide Randspalten enthalten; innen bleiben max(w−2, 0) Spalten. Bei text_clear_rect ist dies die Anzahl der zu füllenden Zellen pro Zeile.
hHöhe in Tile-Zellen. Bei text_window sind oberer und unterer Rand enthalten; innen bleiben max(h−2, 0) Zeilen. Bei text_clear_rect ist dies die Anzahl der zu füllenden Zeilen.
Rückgabewert
Kein Rückgabewert. Die Funktion beschreibt die Tilemap-Zellen vor der Rückkehr; sie liefert weder eine Zeichenanzahl noch einen Statuscode.
Bedingungen und Grenzen
Diese Funktionen zeichnen auf die durch LCDC-Bit 3 gewählte BG-Karte. Das Textfenster ist ein Softwarebereich auf dieser Karte, nicht die Hardware-Window-Ebene. Halten Sie CGB-VBK für Tile-Nummern auf 0; diese Aufrufe setzen weder Farbattribute noch Paletten oder Scrolling.
Laden Sie Schrift und Rahmengrafiken vor dem Zeichnen. Die Standard-Rahmen-IDs sind 1–6, das Füll-Tile ist 0 und die Dezimalziffern beginnen bei ASCII 0 (Tile 48). Das Minuszeichen verwendet ASCII - (Tile 45). Das Beispiel enthält sechs Rahmen-Tiles und die Schrift des Handbuchs mit zu ASCII passenden Glyphen-IDs.
Halten Sie Rechtecke und Text innerhalb der 32×32-Karte. Die Rechteckfüllung begrenzt Breite und Höhe nicht auf den Kartenrand. Bei Breite oder Höhe null wird nichts gefüllt; text_window merkt sich den Bereich trotzdem als geöffnet, jedoch ohne nutzbaren Innenraum.
Die Intrinsics für Tile-Schreibzugriffe prüfen den LCD-Zustand: Bei ausgeschaltetem LCD schreiben sie sofort; andernfalls warten sie auf beschreibbare LCD-Modi und umgeben die Zugriffe mit DI/EI. Dieser Pfad kann bei der Rückkehr Interrupts aktivieren. Verlassen Sie sich daher nicht darauf, dass ein deaktivierter Interruptzustand erhalten bleibt. Die Beispiele und Byte-Tests hier schreiben bei ausgeschaltetem LCD.
Das vollständige Beispiel bindet text.c genau einmal ein, damit die Bibliotheksimplementierung mit dem Programm kompiliert wird. Übergeben Sie lib/text.c für dieses Beispiel nicht zusätzlich als separate Eingabe. Definieren Sie angepasste TEXT_*-Tile-Konstanten vor dem Einbinden von rpg.h und der Implementierung. Verwenden Sie überall, wo die Bibliothek kompiliert wird, dieselben Definitionen.
Anwendungsbeispiel
text_window(1,2,18,5);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel öffnet bei (1,2) einen Bereich mit 18×5 Zellen und einem Innenraum von 16×3 Zellen. Der mitgelieferte Rahmen hat ein Pixel breite Linien; seine sichtbaren äußeren Linien reichen von x=11 bis 147 und y=19 bis 51 Pixel. Auf CGB ist er rot, auf DMG schwarz.
Die Prüfung vergleicht alle sichtbaren Pixel und sämtliche 1024 Bytes der BG-Karte in beiden Beispielbildern. Separate DMG/CGB-ROMs prüfen alle 256 vorzeichenlosen Byte-Werte, Dezimalstellenübergänge und vorzeichenbehaftete Extremwerte. Punkte neben jeder Zahl bleiben als Wächter erhalten. Die Layoutprüfungen umfassen leere und schmale Rechtecke, Platzierung am Kartenrand, rohe Tile-Bytes mit Steuercodewerten sowie den Fenstercursor nach absoluten Schreibzugriffen. Dies sind Emulatortests, keine Tests auf physischer Hardware.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Markiert Zellen, deren Manhattan-Distanz einschließlich der Grenzen zwischen atk_min und atk_max liegt.
Syntax
u8 unit_attack_range(unit_t* u, u8* out_mask);Parameter
uGültiges unit_t: Zellposition, move in Schritten, einschließlich geltender atk_min/atk_max-Bereich sowie hp und acted für die Handlungsberechtigung.
out_maskwidth*height beschreibbare Bytes; erhält je Zelle null oder eins.
Rückgabewert
Gibt bei verfügbarer Karte 1 zurück, bei Abmessungen von null 0.
Bedingungen und Grenzen
Koordinaten bezeichnen Zellen der aktuellen Karte: 8×8 Pixel bei gewöhnlichen Kacheln, 16×16 Pixel bei Metakacheln.
Ignoriert Hindernisse, Sichtlinien und verbündete Einheiten. Halten Sie ausgewertete Distanzen bei höchstens 255. Überschreitet die Mindestreichweite die Höchstreichweite, werden alle Zellen null.
Anwendungsbeispiel
result[46]=unit_attack_range(&hero,mask);result[47]=mask[12];result[48]=mask[14];Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das linke Raster zeigt Bewegungskosten innerhalb von drei Schritten, das rechte eine kürzeste Route von S nach G. Grüne Sternchen markieren neun Schritte um eine rote Wand aus drei Zellen; blaue Ziffern zeigen Kosten. Auf dem DMG erscheint dieselbe Anordnung schwarz. RAM-Prüfungen zeigen außerdem, dass die Angriffsmaske Wände ignoriert.


Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Prüft, ob eine Einheit noch Trefferpunkte hat und noch nicht gehandelt hat.
Syntax
u8 unit_can_act(const unit_t* u);Parameter
uGültiges unit_t: Zellposition, move in Schritten, einschließlich geltender atk_min/atk_max-Bereich sowie hp und acted für die Handlungsberechtigung.
Rückgabewert
Gibt 1 zurück, wenn hp ungleich null und acted gleich null ist, sonst 0. Verändert die Einheit nicht.
Anwendungsbeispiel
result[11]=unit_can_act(&hero);hero.acted=1;result[12]=unit_can_act(&hero);hero.acted=0;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das linke Raster zeigt Bewegungskosten innerhalb von drei Schritten, das rechte eine kürzeste Route von S nach G. Grüne Sternchen markieren neun Schritte um eine rote Wand aus drei Zellen; blaue Ziffern zeigen Kosten. Auf dem DMG erscheint dieselbe Anordnung schwarz. RAM-Prüfungen zeigen außerdem, dass die Angriffsmaske Wände ignoriert.


Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Erzeugt eine Maske der innerhalb des Bewegungsbudgets der Einheit erreichbaren Zellen.
Syntax
u8 unit_move_range(unit_t* u, u8* out_mask);Parameter
uGültiges unit_t: Zellposition, move in Schritten, einschließlich geltender atk_min/atk_max-Bereich sowie hp und acted für die Handlungsberechtigung.
out_maskwidth*height beschreibbare Bytes; erhält je Zelle null oder eins.
Rückgabewert
Gibt bei verfügbarer Karte 1 zurück, bei Abmessungen von null 0. Der Ursprung der Einheit muss innerhalb der Karte liegen.
Bedingungen und Grenzen
Koordinaten bezeichnen Zellen der aktuellen Karte: 8×8 Pixel bei gewöhnlichen Kacheln, 16×16 Pixel bei Metakacheln.
Die Suche verwendet etwa 4 KiB gemeinsamen, nicht reentranten Arbeitsspeicher. Begrenzen Sie Karten auf 1024 Zellen und untersuchte Entfernungen auf 254. Distanz 0xFF bedeutet „nicht erreicht“; eine Route mit 255 Schritten ist daher nicht darstellbar. Kosten- und Maskenausgaben benötigen width*height beschreibbare Bytes.
Der Ursprung wird auch bei Blockierung als erreichbar gesetzt. Trefferpunkte, acted und andere Einheiten beeinflussen die Bewegungsmaske nicht.
Anwendungsbeispiel
result[43]=unit_move_range(&hero,mask);result[44]=mask[12];result[45]=mask[14];Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das linke Raster zeigt Bewegungskosten innerhalb von drei Schritten, das rechte eine kürzeste Route von S nach G. Grüne Sternchen markieren neun Schritte um eine rote Wand aus drei Zellen; blaue Ziffern zeigen Kosten. Auf dem DMG erscheint dieselbe Anordnung schwarz. RAM-Prüfungen zeigen außerdem, dass die Angriffsmaske Wände ignoriert.


Vollständiges Beispielprogramm
Build-Befehl
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=noneImplementierung und Quelltext
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
Wählt einen Elementindex aus einer Liste relativer Bytegewichte. Die Funktion summiert die Gewichte, reduziert eine rng16-Ziehung modulo dieser Summe und sucht das erste kumulierte Intervall, das das Ergebnis enthält. Bei [1, 3, 6] gehören den Indizes 0, 1 und 2 die Intervalle 0, 1–3 und 4–9.
Syntax
u8 weighted_choice(const u8* weights, u8 count);Parameter
weightsZeiger auf count lesbare u8-Gewichte. Das Array wird nicht geändert. Bei positiver Summe werden Elemente mit Gewicht null übersprungen. Bei count == 0 wird der Zeiger nicht gelesen und darf null sein; andernfalls ist ein gültiges Array erforderlich.
countAnzahl der Gewichte in 0–255. Höchstens 255 Gewichte zu je 255 ergeben 65025 und passen in den u16-Akkumulator. Die Funktion durchläuft die Liste zuerst zur Summierung und danach bis zum ausgewählten Intervall.
Rückgabewert
Bei positiver Summe ein Index von 0 bis count−1 nach zwei Byteziehungen. Ist count null oder sind alle Gewichte null, wird null ohne Ziehung geliefert. Dieser Ersatzwert ist von einer gültigen Auswahl des Index 0 nicht unterscheidbar. Prüfen Sie leere oder reine Nulllisten selbst, wenn dieser Unterschied wichtig ist.
Bedingungen und Grenzen
Gewichte bestimmen relative Intervallgrößen, keine garantierten beobachteten Prozentsätze. Sowohl die rng16-Verteilung als auch die Reduktion modulo der Summe beeinflussen tatsächliche Häufigkeiten. Eine positive Summe verbraucht stets zwei Byteziehungen, selbst wenn nur ein Element ein Gewicht ungleich null hat.
Diese Aufrufe teilen einen persistenten Zustand. Reproduktion erfordert dasselbe Zielsystem, denselben Startwert und dieselbe Aufrufreihenfolge einschließlich anderer Hilfsfunktionen. Führen Sie Startwertsetzung und Ziehungen in einem Ausführungskontext aus; die Prüfungen belegen keine sichere gleichzeitige Nutzung aus einem Interrupthandler.
GB und FC verwenden unterschiedliche Algorithmen und versprechen bei gleichem Startwert keine gleiche Folge. Dies sind deterministische Spielgeneratoren, keine Quellen kryptografischer Zufälligkeit. Die Tests prüfen Implementierungsverhalten, nicht statistische Qualität oder Periode.
Binden Sie rpg.h ein und kompilieren Sie lib/rng.c mit dem Spiel, wenn Sie die Bibliotheksfunktionen nutzen. __rng_seed und __rng8 werden als intrinsische Funktionen vom Compiler erzeugt; ein Programm mit nur diesen beiden benötigt kein rng.c-Objekt.
Anwendungsbeispiel
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.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Dieses Beispiel gibt drei Elementen die Gewichte 1, 3 und 6. Das erzeugte Wort 546 ergibt Rest 6 im Intervall 4–9 des Index 2; WEIGHT INDEX zeigt 00002. EMPTY LIST zeigt 00000 als Ersatzwert für eine leere Liste, nicht als erfolgreiche Auswahl von Element 0.
Das vollständige Programm zeigt Dezimalergebnisse auf Weiß: schwarze Schrift auf DMG, blaue auf CGB. FAILED muss 00000 anzeigen. Die Bilder zeigen die tatsächliche Emulatorausgabe dieses Beispiels.
Die Prüfung verglich je Fall 32 Ausgaben und acht anschließende Byteziehungen mit einem unabhängigen Hostmodell: 93 GB- und 18 FC-Fälle, einschließlich konstanter und zur Laufzeit gesetzter Startwerte sowie GB-Grenzfällen für Bereiche, Chancen und Gewichte. Die Lehrbildschirme wurden nach 240 Emulatorframes geprüft. Echte Hardware und statistische Qualität wurden nicht getestet.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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 — Szenenregistrierung, -wechsel und -aktualisierung
Ruft die Handler enter, update, draw und exit einer Szenentabelle auf, um zwischen Bildschirmen wie Titelanzeige und Spiel zu wechseln.
scene_change
Verlässt die aktive Szene, sofern vorhanden, und betritt die angeforderte Szene.
Syntax
void scene_change(u8 scene_id);Parameter
scene_idIndex der zu betretenden Szene, von 0 bis count−1.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
IDs außerhalb des gültigen Bereichs werden ignoriert. Ein gültiger Wechsel führt exit aus, speichert die neue ID und das Wechselflag und führt dann enter aus. Auch die Wahl derselben ID führt exit und enter aus. Die Szenentabelle gehört dem aufrufenden Code. Halten Sie die Tabelle und die Ziele ihrer gewöhnlichen Funktionszeiger während der gesamten Verwendung gültig. Null-Callbacks werden übersprungen. Wechseln Sie innerhalb von enter- oder exit-Callbacks nicht rekursiv die Szene und ersetzen Sie dort nicht die Tabelle.
Bauen Sie dieses vollständige Beispiel mit der standardmäßigen Legacy-ABI. Seine Callbacks verwenden Funktionszeigeraufrufe, die der Compiler mit --abi=stack als nicht unterstützt abweist. Dieselbe Einschränkung gilt bei Verwendung eines Alias.
Anwendungsbeispiel
scene_change(0);scene_change(9);result[11]=events;result[12]=scene_was_changed();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Programm aktiviert Szene 0, ignoriert die ungültige ID 9, wechselt von 0→1 und betritt mit 1→1 dieselbe Szene erneut. Dabei prüft es die Reihenfolge der Callbacks.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Ruft den draw-Callback der aktiven Szene einmal auf.
Syntax
void scene_draw();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Ohne aktive Szene oder bei einem Null-Callback für draw bleibt der Aufruf ohne Wirkung. Das Wechselflag wird nicht gelöscht. Planen Sie Bildschirmübertragungen und Frame-Timing im Callback oder in der umgebenden Spielschleife. Die Szenentabelle gehört dem aufrufenden Code. Halten Sie die Tabelle und die Ziele ihrer gewöhnlichen Funktionszeiger während der gesamten Verwendung gültig. Null-Callbacks werden übersprungen. Wechseln Sie innerhalb von enter- oder exit-Callbacks nicht rekursiv die Szene und ersetzen Sie dort nicht die Tabelle.
Bauen Sie dieses vollständige Beispiel mit der standardmäßigen Legacy-ABI. Seine Callbacks verwenden Funktionszeigeraufrufe, die der Compiler mit --abi=stack als nicht unterstützt abweist. Dieselbe Einschränkung gilt bei Verwendung eines Alias.
Anwendungsbeispiel
scene_draw();result[15]=events;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Die Ereignisfolge enthält die 12 aus dem draw-Aufruf von Szene 0 und die 22 aus dem draw-Aufruf von Szene 1.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Liest die gespeicherte aktuelle Szenen-ID.
Syntax
u8 scene_get_current();Rückgabewert
Gibt die gespeicherte 8-Bit-ID zurück; auch nach der Initialisierung ist sie null.
Bedingungen und Grenzen
Der Rückgabewert null allein belegt nicht, dass Szene 0 aktiv ist. Halten Sie fest, ob seit der Initialisierung bereits der erste Aufruf von scene_change() erfolgt ist.
Bauen Sie dieses vollständige Beispiel mit der standardmäßigen Legacy-ABI. Seine Callbacks verwenden Funktionszeigeraufrufe, die der Compiler mit --abi=stack als nicht unterstützt abweist. Dieselbe Einschränkung gilt bei Verwendung eines Alias.
Anwendungsbeispiel
result[16]=scene_get_current();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel liest nach der Aktivierung von Szene 0 den Wert null und nach dem Wechsel zu Szene 1 den Wert eins.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Registriert eine Szenentabelle, ohne eine Szene zu aktivieren.
Syntax
void scene_init(const SceneDef* scenes, u8 count);Parameter
scenesArray aus
SceneDef-Einträgen mit den Callbacks enter, update, draw und exit.countAnzahl der Einträge; bei null gibt es keine gültigen Szenen-IDs.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Setzt die gespeicherte ID und das Wechselflag auf null zurück. enter wird nicht aufgerufen; aktivieren Sie eine Szene mit scene_change(). Die Szenentabelle gehört dem aufrufenden Code. Halten Sie die Tabelle und die Ziele ihrer gewöhnlichen Funktionszeiger während der gesamten Verwendung gültig. Null-Callbacks werden übersprungen. Wechseln Sie innerhalb von enter- oder exit-Callbacks nicht rekursiv die Szene und ersetzen Sie dort nicht die Tabelle.
Bauen Sie dieses vollständige Beispiel mit der standardmäßigen Legacy-ABI. Seine Callbacks verwenden Funktionszeigeraufrufe, die der Compiler mit --abi=stack als nicht unterstützt abweist. Dieselbe Einschränkung gilt bei Verwendung eines Alias.
Anwendungsbeispiel
scene_init(scenes,2);scene_update();scene_draw();result[9]=events;result[10]=scene_was_changed();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel registriert zwei Szenen und prüft, dass Aufrufe von update und draw vor der Aktivierung keine Ereignisse auslösen.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Ersetzt die Szenentabelle und lässt keine Szene aktiv.
Syntax
void scene_set_table(const SceneDef* scenes, u8 count);Parameter
scenesArray aus
SceneDef-Einträgen mit den Callbacks enter, update, draw und exit.countAnzahl der Einträge; bei null gibt es keine gültigen Szenen-IDs.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Setzt den Zustand wie scene_init() zurück, ohne den bisherigen exit-Callback oder einen neuen enter-Callback aufzurufen. Die Szenentabelle gehört dem aufrufenden Code. Halten Sie die Tabelle und die Ziele ihrer gewöhnlichen Funktionszeiger während der gesamten Verwendung gültig. Null-Callbacks werden übersprungen. Wechseln Sie innerhalb von enter- oder exit-Callbacks nicht rekursiv die Szene und ersetzen Sie dort nicht die Tabelle.
Bauen Sie dieses vollständige Beispiel mit der standardmäßigen Legacy-ABI. Seine Callbacks verwenden Funktionszeigeraufrufe, die der Compiler mit --abi=stack als nicht unterstützt abweist. Dieselbe Einschränkung gilt bei Verwendung eines Alias.
Anwendungsbeispiel
scene_set_table(scenes,2);result[23]=events;result[24]=scene_was_changed();scene_draw();result[25]=events;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Nach neun Ereignissen wird die Tabelle ersetzt: Der Zähler bleibt bei neun, das Wechselflag wird null, und der folgende draw-Aufruf bleibt ohne Wirkung.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Ruft den update-Callback der aktiven Szene einmal auf.
Syntax
void scene_update();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Ohne aktive Szene bleibt der Aufruf ohne Wirkung. Andernfalls wird das Wechselflag vor dem Callback gelöscht, sodass ein innerhalb von update ausgelöster Wechsel anschließend weiterhin erkennbar ist. Die Szenentabelle gehört dem aufrufenden Code. Halten Sie die Tabelle und die Ziele ihrer gewöhnlichen Funktionszeiger während der gesamten Verwendung gültig. Null-Callbacks werden übersprungen. Wechseln Sie innerhalb von enter- oder exit-Callbacks nicht rekursiv die Szene und ersetzen Sie dort nicht die Tabelle.
Bauen Sie dieses vollständige Beispiel mit der standardmäßigen Legacy-ABI. Seine Callbacks verwenden Funktionszeigeraufrufe, die der Compiler mit --abi=stack als nicht unterstützt abweist. Dieselbe Einschränkung gilt bei Verwendung eines Alias.
Anwendungsbeispiel
scene_update();result[13]=events;result[14]=scene_was_changed();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Die update-Funktion von Szene 0 protokolliert Ereignis 11. Nach dieser regulären Aktualisierung wird das zuvor gesetzte Wechselflag von eins auf null zurückgesetzt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Prüft, ob derzeit ein Szenenwechsel vermerkt ist.
Syntax
u8 scene_was_changed();Rückgabewert
Gibt bei gesetztem Wechselflag 1 zurück, andernfalls 0.
Bedingungen und Grenzen
Das Lesen löscht das Flag nicht. Initialisierung, Tabellenwechsel und der Beginn einer Aktualisierung der aktiven Szene löschen es. Eine ungültige Szenen-ID lässt es unverändert.
Bauen Sie dieses vollständige Beispiel mit der standardmäßigen Legacy-ABI. Seine Callbacks verwenden Funktionszeigeraufrufe, die der Compiler mit --abi=stack als nicht unterstützt abweist. Dieselbe Einschränkung gilt bei Verwendung eines Alias.
Anwendungsbeispiel
result[17]=scene_was_changed();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Die Prüfungen erwarten eins unmittelbar nach einem Wechsel, null nach einer regulären Aktualisierung und null nach dem Ersetzen der Tabelle.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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 — Hintergrund, Fenster und geteiltes Scrollen
Steuert sofortige und gepufferte Hintergrund-/Fensterverschiebung sowie bis zu acht Rasteraufteilungen. Unterscheiden Sie die von Lesefunktionen verwalteten aktuellen Werte, tatsächliche Hardwareregister und vorgemerkte Werte.
Scroll_BgAdd
Addiert vorzeichenbehaftete Verschiebungen zu den nachgeführten Hintergrundkoordinaten und wendet sie sofort an.
Syntax
void Scroll_BgAdd(s8 dx, s8 dy);Parameter
dxVorzeichenbehaftete horizontale Pixelverschiebung, −128 bis 127.
dyVorzeichenbehaftete vertikale Pixelverschiebung, −128 bis 127.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Es wird nicht gewartet. Sofortige Zuweisungen und Additionen gleichen das betroffene vorgemerkte Koordinatenpaar an die aktuellen Werte an und löschen dessen Änderungsflag. Auch das sofortige Setzen nur einer Achse verwirft den vorgemerkten Wert der anderen Achse desselben Paars. Ergebnisse laufen modulo 256 um. Additionen gehen von den nachgeführten aktuellen Werten aus, nicht von vorgemerkten Werten oder temporären Rasterregisterwerten. Diese Funktion umhüllt __scroll_bg_add.
Anwendungsbeispiel
Scroll_BgAdd(-20,3);result[22]=M_SCX;result[23]=M_SCY;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Lernen Sie mit den Scroll-Funktionen sofortige Aktualisierung, Vormerken, Übertragen, Addition und Sichtbarkeit. Die Übertragung ändert BG X von 250 auf 16 und WX von 23 auf 39. Das Fensterbit hat nach dem Anzeigen den Wert 32 und nach dem Ausblenden 0.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Überträgt geänderte Hintergrund- und Fensterkoordinaten in den nachgeführten Zustand und die Hardware und löscht anschließend ihre Vormerkflags.
Syntax
void Scroll_Flush();Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Ein unverändertes Koordinatenpaar bleibt unangetastet. Es werden weder Interrupts maskiert noch wird auf VBlank gewartet; der aufrufende Code muss den passenden Zeitpunkt sicherstellen. Diese Funktion umhüllt __scroll_flush.
Anwendungsbeispiel
Scroll_Flush();result[18]=M_SCX;result[19]=M_SCY;result[20]=M_WX;result[21]=M_WY;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Lernen Sie mit den Scroll-Funktionen sofortige Aktualisierung, Vormerken, Übertragen, Addition und Sichtbarkeit. Die Übertragung ändert BG X von 250 auf 16 und WX von 23 auf 39. Das Fensterbit hat nach dem Anzeigen den Wert 32 und nach dem Ausblenden 0.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Liest den nachgeführten aktuellen Wert der horizontalen Hintergrundverschiebung.
Syntax
u8 Scroll_GetBgX();Rückgabewert
Gibt den nachgeführten aktuellen Byte-Wert von 0–255 zurück. WX enthält den hardwarebedingten Versatz von sieben Pixeln.
Bedingungen und Grenzen
Dies liest kein Hardwareregister. Noch ausstehende Pufferwerte, direkte Registerzugriffe und temporäre Werte aus Rasteraufteilungen sind nicht enthalten. Diese Funktion umhüllt __scroll_bg_x_get.
Anwendungsbeispiel
result[6]=Scroll_GetBgX();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Lernen Sie mit den Scroll-Funktionen sofortige Aktualisierung, Vormerken, Übertragen, Addition und Sichtbarkeit. Die Übertragung ändert BG X von 250 auf 16 und WX von 23 auf 39. Das Fensterbit hat nach dem Anzeigen den Wert 32 und nach dem Ausblenden 0.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Liest den nachgeführten aktuellen Wert der vertikalen Hintergrundverschiebung.
Syntax
u8 Scroll_GetBgY();Rückgabewert
Gibt den nachgeführten aktuellen Byte-Wert von 0–255 zurück. WX enthält den hardwarebedingten Versatz von sieben Pixeln.
Bedingungen und Grenzen
Dies liest kein Hardwareregister. Noch ausstehende Pufferwerte, direkte Registerzugriffe und temporäre Werte aus Rasteraufteilungen sind nicht enthalten. Diese Funktion umhüllt __scroll_bg_y_get.
Anwendungsbeispiel
result[7]=Scroll_GetBgY();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Lernen Sie mit den Scroll-Funktionen sofortige Aktualisierung, Vormerken, Übertragen, Addition und Sichtbarkeit. Die Übertragung ändert BG X von 250 auf 16 und WX von 23 auf 39. Das Fensterbit hat nach dem Anzeigen den Wert 32 und nach dem Ausblenden 0.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Liest den nachgeführten aktuellen WX-Wert des Fensters.
Syntax
u8 Scroll_GetWindowX();Rückgabewert
Gibt den nachgeführten aktuellen Byte-Wert von 0–255 zurück. WX enthält den hardwarebedingten Versatz von sieben Pixeln.
Bedingungen und Grenzen
Dies liest kein Hardwareregister. Noch ausstehende Pufferwerte, direkte Registerzugriffe und temporäre Werte aus Rasteraufteilungen sind nicht enthalten. Diese Funktion umhüllt __scroll_win_x_get.
Anwendungsbeispiel
result[12]=Scroll_GetWindowX();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Lernen Sie mit den Scroll-Funktionen sofortige Aktualisierung, Vormerken, Übertragen, Addition und Sichtbarkeit. Die Übertragung ändert BG X von 250 auf 16 und WX von 23 auf 39. Das Fensterbit hat nach dem Anzeigen den Wert 32 und nach dem Ausblenden 0.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Liest den nachgeführten aktuellen WY-Wert des Fensters.
Syntax
u8 Scroll_GetWindowY();Rückgabewert
Gibt den nachgeführten aktuellen Byte-Wert von 0–255 zurück. WX enthält den hardwarebedingten Versatz von sieben Pixeln.
Bedingungen und Grenzen
Dies liest kein Hardwareregister. Noch ausstehende Pufferwerte, direkte Registerzugriffe und temporäre Werte aus Rasteraufteilungen sind nicht enthalten. Diese Funktion umhüllt __scroll_win_y_get.
Anwendungsbeispiel
result[13]=Scroll_GetWindowY();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Lernen Sie mit den Scroll-Funktionen sofortige Aktualisierung, Vormerken, Übertragen, Addition und Sichtbarkeit. Die Übertragung ändert BG X von 250 auf 16 und WX von 23 auf 39. Das Fensterbit hat nach dem Anzeigen den Wert 32 und nach dem Ausblenden 0.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Initialisiert die Hintergrundverschiebung mit (0,0) und die Fensterposition mit WX=7, WY=0.
Syntax
void Scroll_Init();Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Synchronisiert aktuelle und vorgemerkte Koordinaten; setzt weder Fenstersichtbarkeit noch Aufteilungstabelle zurück.
Anwendungsbeispiel
Scroll_Init();result[0]=M_SCX;result[1]=M_SCY;result[2]=M_WX;result[3]=M_WY;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Lernen Sie mit den Scroll-Funktionen sofortige Aktualisierung, Vormerken, Übertragen, Addition und Sichtbarkeit. Die Übertragung ändert BG X von 250 auf 16 und WX von 23 auf 39. Das Fensterbit hat nach dem Anzeigen den Wert 32 und nach dem Ausblenden 0.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Setzt beide Hintergrund-Scrollkoordinaten sofort.
Syntax
void Scroll_SetBg(u8 scx, u8 scy);Parameter
scxHorizontale Hintergrundverschiebung, 0–255 Pixel; ein größerer Wert bewegt den Hintergrund nach links.
scyVertikale Hintergrundverschiebung, 0–255 Pixel; ein größerer Wert bewegt den Hintergrund nach oben.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Umhüllt __scroll_bg_set: Synchronisiert aktuelle, vorgemerkte und Hardwarewerte und löscht das BG-Änderungsflag, ohne auf VBlank zu warten.
Anwendungsbeispiel
Scroll_SetBg(8,16);result[28]=M_SCX;result[29]=M_SCY;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Lernen Sie mit den Scroll-Funktionen sofortige Aktualisierung, Vormerken, Übertragen, Addition und Sichtbarkeit. Die Übertragung ändert BG X von 250 auf 16 und WX von 23 auf 39. Das Fensterbit hat nach dem Anzeigen den Wert 32 und nach dem Ausblenden 0.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Merkt beide Hintergrund-Scrollkoordinaten zur späteren Übertragung vor.
Syntax
void Scroll_SetBgBuffered(u8 scx, u8 scy);Parameter
scxHorizontale Hintergrundverschiebung, 0–255 Pixel; ein größerer Wert bewegt den Hintergrund nach links.
scyVertikale Hintergrundverschiebung, 0–255 Pixel; ein größerer Wert bewegt den Hintergrund nach oben.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Ändert weder nachgeführte aktuelle Werte noch Register. Übertragen Sie sie mit __scroll_flush oder Scroll_Flush; das Vormerken selbst wartet nicht auf VBlank. Diese Funktion umhüllt __scroll_bg_set_buffered.
Anwendungsbeispiel
Scroll_SetBgBuffered(16,24);result[14]=M_SCX;result[15]=Scroll_GetBgX();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Lernen Sie mit den Scroll-Funktionen sofortige Aktualisierung, Vormerken, Übertragen, Addition und Sichtbarkeit. Die Übertragung ändert BG X von 250 auf 16 und WX von 23 auf 39. Das Fensterbit hat nach dem Anzeigen den Wert 32 und nach dem Ausblenden 0.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Setzt die horizontale Hintergrundverschiebung sofort.
Syntax
void Scroll_SetBgX(u8 scx);Parameter
scxHorizontale Hintergrundverschiebung, 0–255 Pixel; ein größerer Wert bewegt den Hintergrund nach links.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Es wird nicht gewartet. Sofortige Zuweisungen und Additionen gleichen das betroffene vorgemerkte Koordinatenpaar an die aktuellen Werte an und löschen dessen Änderungsflag. Auch das sofortige Setzen nur einer Achse verwirft den vorgemerkten Wert der anderen Achse desselben Paars. Diese Funktion umhüllt __scroll_bg_x_set.
Anwendungsbeispiel
Scroll_SetBgX(250);result[4]=M_SCX;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Lernen Sie mit den Scroll-Funktionen sofortige Aktualisierung, Vormerken, Übertragen, Addition und Sichtbarkeit. Die Übertragung ändert BG X von 250 auf 16 und WX von 23 auf 39. Das Fensterbit hat nach dem Anzeigen den Wert 32 und nach dem Ausblenden 0.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Setzt die vertikale Hintergrundverschiebung sofort.
Syntax
void Scroll_SetBgY(u8 scy);Parameter
scyVertikale Hintergrundverschiebung, 0–255 Pixel; ein größerer Wert bewegt den Hintergrund nach oben.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Es wird nicht gewartet. Sofortige Zuweisungen und Additionen gleichen das betroffene vorgemerkte Koordinatenpaar an die aktuellen Werte an und löschen dessen Änderungsflag. Auch das sofortige Setzen nur einer Achse verwirft den vorgemerkten Wert der anderen Achse desselben Paars. Diese Funktion umhüllt __scroll_bg_y_set.
Anwendungsbeispiel
Scroll_SetBgY(2);result[5]=M_SCY;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Lernen Sie mit den Scroll-Funktionen sofortige Aktualisierung, Vormerken, Übertragen, Addition und Sichtbarkeit. Die Übertragung ändert BG X von 250 auf 16 und WX von 23 auf 39. Das Fensterbit hat nach dem Anzeigen den Wert 32 und nach dem Ausblenden 0.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Setzt WX und WY des Fensters sofort.
Syntax
void Scroll_SetWindow(u8 wx, u8 wy);Parameter
wxRoher WX-Byte-Wert, 0–255: Addieren Sie 7 zur gewünschten Bildschirm-X-Koordinate; für den linken Rand verwenden Sie 7.
wyOberkante des Fensters in Bildschirm-Y-Pixeln, 0–255; sichtbar sind die Zeilen 0–143.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Es wird nicht gewartet. Sofortige Zuweisungen und Additionen gleichen das betroffene vorgemerkte Koordinatenpaar an die aktuellen Werte an und löschen dessen Änderungsflag. Auch das sofortige Setzen nur einer Achse verwirft den vorgemerkten Wert der anderen Achse desselben Paars. Diese Funktion umhüllt __scroll_win_set.
Anwendungsbeispiel
Scroll_SetWindow(15,8);result[8]=M_WX;result[9]=M_WY;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Lernen Sie mit den Scroll-Funktionen sofortige Aktualisierung, Vormerken, Übertragen, Addition und Sichtbarkeit. Die Übertragung ändert BG X von 250 auf 16 und WX von 23 auf 39. Das Fensterbit hat nach dem Anzeigen den Wert 32 und nach dem Ausblenden 0.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Merkt beide Fensterkoordinaten zur späteren Übertragung vor.
Syntax
void Scroll_SetWindowBuffered(u8 wx, u8 wy);Parameter
wxRoher WX-Byte-Wert, 0–255: Addieren Sie 7 zur gewünschten Bildschirm-X-Koordinate; für den linken Rand verwenden Sie 7.
wyOberkante des Fensters in Bildschirm-Y-Pixeln, 0–255; sichtbar sind die Zeilen 0–143.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Ändert weder nachgeführte aktuelle Werte noch Register. Übertragen Sie sie mit __scroll_flush oder Scroll_Flush; das Vormerken selbst wartet nicht auf VBlank. Diese Funktion umhüllt __scroll_win_set_buffered.
Anwendungsbeispiel
Scroll_SetWindowBuffered(39,32);result[16]=M_WX;result[17]=Scroll_GetWindowX();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Lernen Sie mit den Scroll-Funktionen sofortige Aktualisierung, Vormerken, Übertragen, Addition und Sichtbarkeit. Die Übertragung ändert BG X von 250 auf 16 und WX von 23 auf 39. Das Fensterbit hat nach dem Anzeigen den Wert 32 und nach dem Ausblenden 0.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Setzt sofort nur die rohe WX-Koordinate des Fensters.
Syntax
void Scroll_SetWindowX(u8 wx);Parameter
wxRoher WX-Byte-Wert, 0–255: Addieren Sie 7 zur gewünschten Bildschirm-X-Koordinate; für den linken Rand verwenden Sie 7.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Es wird nicht gewartet. Sofortige Zuweisungen und Additionen gleichen das betroffene vorgemerkte Koordinatenpaar an die aktuellen Werte an und löschen dessen Änderungsflag. Auch das sofortige Setzen nur einer Achse verwirft den vorgemerkten Wert der anderen Achse desselben Paars. Diese Funktion umhüllt __scroll_win_x_set.
Anwendungsbeispiel
Scroll_SetWindowX(23);result[10]=M_WX;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Lernen Sie mit den Scroll-Funktionen sofortige Aktualisierung, Vormerken, Übertragen, Addition und Sichtbarkeit. Die Übertragung ändert BG X von 250 auf 16 und WX von 23 auf 39. Das Fensterbit hat nach dem Anzeigen den Wert 32 und nach dem Ausblenden 0.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Setzt sofort nur die WY-Koordinate des Fensters.
Syntax
void Scroll_SetWindowY(u8 wy);Parameter
wyOberkante des Fensters in Bildschirm-Y-Pixeln, 0–255; sichtbar sind die Zeilen 0–143.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Es wird nicht gewartet. Sofortige Zuweisungen und Additionen gleichen das betroffene vorgemerkte Koordinatenpaar an die aktuellen Werte an und löschen dessen Änderungsflag. Auch das sofortige Setzen nur einer Achse verwirft den vorgemerkten Wert der anderen Achse desselben Paars. Diese Funktion umhüllt __scroll_win_y_set.
Anwendungsbeispiel
Scroll_SetWindowY(16);result[11]=M_WY;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Lernen Sie mit den Scroll-Funktionen sofortige Aktualisierung, Vormerken, Übertragen, Addition und Sichtbarkeit. Die Übertragung ändert BG X von 250 auf 16 und WX von 23 auf 39. Das Fensterbit hat nach dem Anzeigen den Wert 32 und nach dem Ausblenden 0.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Erfasst die grundlegende Fenstersichtbarkeit und aktiviert das erste Rasterzeilenereignis der Aufteilungstabelle.
Syntax
void Scroll_SplitCommit();Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Die gemeinsame Tabelle enthält acht Einträge. Das Anhängen wendet sie weder an noch sortiert es sie; überzählige Einträge werden ignoriert. Bauen Sie die Tabelle an einer sicheren Frame-Grenze mit reset→push→commit neu auf und lassen Sie zwischen Ereignissen genügend Abstand für den Handler. Wegen der Interruptlatenz müssen die geplante Zeile und das erste betroffene Pixel nicht zusammenfallen. Eine nichtleere Tabelle aktiviert VBlank/STAT in IE und führt EI aus. Eine leere Tabelle deaktiviert die LYC-Quelle, stellt aber weder IE noch den CPU-Interruptzustand wieder her. Diese Funktion umhüllt __scroll_split_commit.
Anwendungsbeispiel
Scroll_SplitCommit();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Verwenden Sie die Scroll-Hüllfunktionen für drei Hintergrund-Scrollstreifen. Ereignisse bei LY=64 und 104 setzen X auf 8 und 16, sodass 24×16-Rechtecke bei (32,16), (24,80) und (16,112) erscheinen. Das Bild zeigt den Versatz jedes Streifens.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Fügt einen Eintrag hinzu, der die Hintergrundverschiebung beim gewünschten Rasterzeilenereignis ändert.
Syntax
void Scroll_SplitPush(u8 ly, u8 scx, u8 scy);Parameter
lyRasterzeilennummer des Ereignisses; verwenden Sie 0–143 für sichtbare Ereignisse und fügen Sie sie aufsteigend hinzu. Ein erster Eintrag bei null wird während VBlank angewandt.
scxHorizontale Hintergrundverschiebung, 0–255 Pixel; ein größerer Wert bewegt den Hintergrund nach links.
scyVertikale Hintergrundverschiebung, 0–255 Pixel; ein größerer Wert bewegt den Hintergrund nach oben.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Die gemeinsame Tabelle enthält acht Einträge. Das Anhängen wendet sie weder an noch sortiert es sie; überzählige Einträge werden ignoriert. Bauen Sie die Tabelle an einer sicheren Frame-Grenze mit reset→push→commit neu auf und lassen Sie zwischen Ereignissen genügend Abstand für den Handler. Wegen der Interruptlatenz müssen die geplante Zeile und das erste betroffene Pixel nicht zusammenfallen. Diese Funktion umhüllt __scroll_split_push.
Anwendungsbeispiel
Scroll_SplitPush(64,8,0);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Verwenden Sie die Scroll-Hüllfunktionen für drei Hintergrund-Scrollstreifen. Ereignisse bei LY=64 und 104 setzen X auf 8 und 16, sodass 24×16-Rechtecke bei (32,16), (24,80) und (16,112) erscheinen. Das Bild zeigt den Versatz jedes Streifens.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Fügt ein Ereignis hinzu, das Farbe null der CGB-Hintergrundpalette null ändert.
Syntax
void Scroll_SplitPushBgColor0(u8 ly, u16 rgb15);Parameter
lyRasterzeilennummer des Ereignisses; verwenden Sie 0–143 für sichtbare Ereignisse und fügen Sie sie aufsteigend hinzu. Ein erster Eintrag bei null wird während VBlank angewandt.
rgb1515-Bit-RGB555-Farbe: Rot in Bit 0–4, Grün in Bit 5–9, Blau in Bit 10–14.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Nur für CGB. Belegt über die erweiterte Aufteilungsoperation einen Eintrag der Tabelle mit acht Plätzen. Palettenschreibzugriffe warten auf ein zugängliches PPU-Zeitfenster. In diesem CGB-Beispiel mit Normalgeschwindigkeit werden Ereignisse bei LY=64/112 ab Zeile 66/114 sichtbar. Setzen Sie die Ereigniszeile nicht mit der ersten betroffenen Bildzeile gleich.
Anwendungsbeispiel
Scroll_SplitPushBgColor0(0,0x7C00);Scroll_SplitPushBgColor0(64,0x001F);Scroll_SplitPushBgColor0(112,0x03E0);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Ändern Sie CGB-Hintergrundfarbe null innerhalb eines Frames. Bei Normalgeschwindigkeit zeichnet das Beispiel die Zeilen 0–65 blau, 66–113 rot und 114–143 grün. Die Ereignisse sind bei 0, 64 und 112 geplant; Interruptverarbeitung und Palettenzugriff verursachen Verzögerungen. Der DMG bietet diese Farbpaletten nicht.

Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Fügt einen Aufteilungseintrag hinzu, dessen Flags Operationen für Hintergrund, Fenster, Sichtbarkeit oder Hintergrundfarbe null auswählen.
Syntax
void Scroll_SplitPushEx(u8 ly, u8 scx, u8 scy, u8 wx, u8 wy, u8 flags);Parameter
lyRasterzeilennummer des Ereignisses; verwenden Sie 0–143 für sichtbare Ereignisse und fügen Sie sie aufsteigend hinzu. Ein erster Eintrag bei null wird während VBlank angewandt.
scxHorizontale Hintergrundverschiebung, 0–255 Pixel; ein größerer Wert bewegt den Hintergrund nach links.
scyVertikale Hintergrundverschiebung, 0–255 Pixel; ein größerer Wert bewegt den Hintergrund nach oben.
wxRoher WX-Byte-Wert, 0–255: Addieren Sie 7 zur gewünschten Bildschirm-X-Koordinate; für den linken Rand verwenden Sie 7.
wyOberkante des Fensters in Bildschirm-Y-Pixeln, 0–255; sichtbar sind die Zeilen 0–143.
flagsOperationsbits: BG=1, Fensterposition=2, Anzeigen=4, Ausblenden=8, CGB-Hintergrundpalette 0/Farbe 0=16. Unbekannte Bits werden verworfen. Der Modus für Farbe null nutzt scx/scy als niederwertiges/höherwertiges Byte des RGB15-Werts.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Die gemeinsame Tabelle enthält acht Einträge. Das Anhängen wendet sie weder an noch sortiert es sie; überzählige Einträge werden ignoriert. Bauen Sie die Tabelle an einer sicheren Frame-Grenze mit reset→push→commit neu auf und lassen Sie zwischen Ereignissen genügend Abstand für den Handler. Wegen der Interruptlatenz müssen die geplante Zeile und das erste betroffene Pixel nicht zusammenfallen. Sind beide Sichtbarkeitsbits gesetzt, hat Anzeigen Vorrang. Farbe null ist nur auf dem CGB verfügbar; bei Kombination mit BG-Bewegung dienen dieselben scx/scy-Bytes beiden Zwecken. Diese Funktion umhüllt __scroll_split_push_ex.
Anwendungsbeispiel
Scroll_SplitPushEx(104,16,0,7,0,KQ_SCROLL_SPLIT_USE_BG|KQ_SCROLL_SPLIT_WIN_HIDE);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Verwenden Sie die Scroll-Hüllfunktionen für drei Hintergrund-Scrollstreifen. Ereignisse bei LY=64 und 104 setzen X auf 8 und 16, sodass 24×16-Rechtecke bei (32,16), (24,80) und (16,112) erscheinen. Das Bild zeigt den Versatz jedes Streifens.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Löscht Anzahl und Index der Aufteilungen, deaktiviert ihre Verarbeitung und löscht das LYC-Interruptfreigabebit in STAT.
Syntax
void Scroll_SplitReset();Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Die gemeinsame Tabelle enthält acht Einträge. Das Anhängen wendet sie weder an noch sortiert es sie; überzählige Einträge werden ignoriert. Bauen Sie die Tabelle an einer sicheren Frame-Grenze mit reset→push→commit neu auf und lassen Sie zwischen Ereignissen genügend Abstand für den Handler. Wegen der Interruptlatenz müssen die geplante Zeile und das erste betroffene Pixel nicht zusammenfallen. Löscht weder Tabellenbytes noch IE und deaktiviert keine CPU-Interrupts. Diese Funktion umhüllt __scroll_split_reset.
Anwendungsbeispiel
Scroll_SplitReset();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Verwenden Sie die Scroll-Hüllfunktionen für drei Hintergrund-Scrollstreifen. Ereignisse bei LY=64 und 104 setzen X auf 8 und 16, sodass 24×16-Rechtecke bei (32,16), (24,80) und (16,112) erscheinen. Das Bild zeigt den Versatz jedes Streifens.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Addiert vorzeichenbehaftete Verschiebungen zu den nachgeführten Fensterkoordinaten und wendet sie sofort an.
Syntax
void Scroll_WindowAdd(s8 dx, s8 dy);Parameter
dxVorzeichenbehaftete horizontale Pixelverschiebung, −128 bis 127.
dyVorzeichenbehaftete vertikale Pixelverschiebung, −128 bis 127.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Es wird nicht gewartet. Sofortige Zuweisungen und Additionen gleichen das betroffene vorgemerkte Koordinatenpaar an die aktuellen Werte an und löschen dessen Änderungsflag. Auch das sofortige Setzen nur einer Achse verwirft den vorgemerkten Wert der anderen Achse desselben Paars. Ergebnisse laufen modulo 256 um. Additionen gehen von den nachgeführten aktuellen Werten aus, nicht von vorgemerkten Werten oder temporären Rasterregisterwerten. Diese Funktion umhüllt __scroll_win_add.
Anwendungsbeispiel
Scroll_WindowAdd(4,-40);result[24]=M_WX;result[25]=M_WY;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Lernen Sie mit den Scroll-Funktionen sofortige Aktualisierung, Vormerken, Übertragen, Addition und Sichtbarkeit. Die Übertragung ändert BG X von 250 auf 16 und WX von 23 auf 39. Das Fensterbit hat nach dem Anzeigen den Wert 32 und nach dem Ausblenden 0.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Löscht das Fensterbit in LCDC und den nachgeführten Sichtbarkeitszustand des Fensters.
Syntax
void Scroll_WindowHide();Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Ändert weder Koordinaten noch Kartenauswahl. Sichtbarkeit setzt außerdem ein eingeschaltetes LCD, aktivierte Hintergrund-/Fensterfunktionen und eine Fensterposition im sichtbaren Bereich voraus. Diese Funktion umhüllt __scroll_win_hide.
Anwendungsbeispiel
Scroll_WindowHide();result[27]=M_LCDC&32;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Lernen Sie mit den Scroll-Funktionen sofortige Aktualisierung, Vormerken, Übertragen, Addition und Sichtbarkeit. Die Übertragung ändert BG X von 250 auf 16 und WX von 23 auf 39. Das Fensterbit hat nach dem Anzeigen den Wert 32 und nach dem Ausblenden 0.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Aktiviert das Fensterbit in LCDC und den nachgeführten Sichtbarkeitszustand des Fensters.
Syntax
void Scroll_WindowShow();Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Ändert weder Koordinaten noch Kartenauswahl. Sichtbarkeit setzt außerdem ein eingeschaltetes LCD, aktivierte Hintergrund-/Fensterfunktionen und eine Fensterposition im sichtbaren Bereich voraus. Diese Funktion umhüllt __scroll_win_show.
Anwendungsbeispiel
Scroll_WindowShow();result[26]=M_LCDC&32;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Lernen Sie mit den Scroll-Funktionen sofortige Aktualisierung, Vormerken, Übertragen, Addition und Sichtbarkeit. Die Übertragung ändert BG X von 250 auf 16 und WX von 23 auf 39. Das Fensterbit hat nach dem Anzeigen den Wert 32 und nach dem Ausblenden 0.


Vollständiges Beispielprogramm
Build-Befehl
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=64kAnwendungsbeispiel
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei einer Kamera an (8,16) erscheint das rote 32×24-Rechteck an Bildschirmposition (24,16). Das Fenster zeigt einen blauen 64×64-Rahmen bei (96,80) und ein grünes 16×16-Quadrat bei (112,96). Auf dem DMG sind alle Formen schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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 — Spielbretter, Zuglisten und Rücknahme
Bietet ein Brett mit Byte-Werten, eine begrenzte Zugliste und einen Rücknahmestapel. Das Spiel kombiniert diese Operationen, um Züge oder Rücknahmedatensätze auf sein Brett anzuwenden.
slg_board_clear
Füllt jede Zelle des Bretts mit dem gewünschten Wert.
Syntax
void slg_board_clear(SLGBoard* board, u8 value);Parameter
boardZu bearbeitendes
SLGBoard; die Initialisierung benötigt Speicher, der nicht NULL ist.valueZu speichernder Byte-Wert; das Spiel legt seine Bedeutung fest, etwa Figuren- oder Geländetyp.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Der aufrufende Code stellt den Speicher bereit. Die Initialisierung reserviert und löscht ihn nicht. Brettkoordinaten werden in Zellen angegeben.
Anwendungsbeispiel
slg_board_clear(&board,0);result[1]=cells[0];result[2]=cells[11];Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel trennt die Aufgaben von Brett, Zugliste und Rücknahmedatensätzen. Die Brettinitialisierung behält 9 bei; ein dritter Eintrag in einer Liste mit zwei Plätzen liefert 0. Das Entnehmen allein lässt den Brettwert bei 8; erst das ausdrückliche Anwenden des Datensatzes stellt 7 wieder her.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Liest eine Zelle; bei einem NULL-Brett oder Koordinaten außerhalb des Bereichs wird null zurückgegeben.
Syntax
u8 slg_board_get(const SLGBoard* board, u8 x, u8 y);Parameter
boardZu bearbeitendes
SLGBoard; die Initialisierung benötigt Speicher, der nicht NULL ist.xZellenspalte von links, beginnend bei null; das Aufzeichnen eines Zugs prüft die Brettgrenzen nicht.
yZellenzeile von oben, beginnend bei null; das Aufzeichnen eines Zugs prüft die Brettgrenzen nicht.
Rückgabewert
Byte-Wert der Zelle oder null bei ungültiger Abfrage. Null allein unterscheidet nicht zwischen einer leeren Zelle und einer ungültigen Koordinate.
Bedingungen und Grenzen
Der aufrufende Code stellt den Speicher bereit. Die Initialisierung reserviert und löscht ihn nicht. Brettkoordinaten werden in Zellen angegeben.
Anwendungsbeispiel
result[3]=slg_board_get(&board,1,1);result[4]=slg_board_get(&board,4,1);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel trennt die Aufgaben von Brett, Zugliste und Rücknahmedatensätzen. Die Brettinitialisierung behält 9 bei; ein dritter Eintrag in einer Liste mit zwei Plätzen liefert 0. Das Entnehmen allein lässt den Brettwert bei 8; erst das ausdrückliche Anwenden des Datensatzes stellt 7 wieder her.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Verknüpft Brettabmessungen und ein Zellenarray; der vorhandene Inhalt bleibt erhalten.
Syntax
void slg_board_init(SLGBoard* board, u8 width, u8 height, u8* cells);Parameter
boardZu bearbeitendes
SLGBoard; die Initialisierung benötigt Speicher, der nicht NULL ist.widthBrettbreite in Zellen, zugleich der Abstand zwischen den Zeilenanfängen.
heightAnzahl der Brettzeilen.
cellsBeschreibbares, zeilenweise angeordnetes Array mit mindestens
width*heightZellenbytes.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Der aufrufende Code stellt den Speicher bereit. Die Initialisierung reserviert und löscht ihn nicht. Brettkoordinaten werden in Zellen angegeben.
Anwendungsbeispiel
cells[0]=9;slg_board_init(&board,4,3,cells);result[0]=slg_board_get(&board,0,0);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel trennt die Aufgaben von Brett, Zugliste und Rücknahmedatensätzen. Die Brettinitialisierung behält 9 bei; ein dritter Eintrag in einer Liste mit zwei Plätzen liefert 0. Das Entnehmen allein lässt den Brettwert bei 8; erst das ausdrückliche Anwenden des Datensatzes stellt 7 wieder her.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Schreibt eine gültige Brettzelle; ein NULL-Brett oder Koordinaten außerhalb des Bereichs werden ignoriert.
Syntax
void slg_board_set(SLGBoard* board, u8 x, u8 y, u8 value);Parameter
boardZu bearbeitendes
SLGBoard; die Initialisierung benötigt Speicher, der nicht NULL ist.xZellenspalte von links, beginnend bei null; das Aufzeichnen eines Zugs prüft die Brettgrenzen nicht.
yZellenzeile von oben, beginnend bei null; das Aufzeichnen eines Zugs prüft die Brettgrenzen nicht.
valueZu speichernder Byte-Wert; das Spiel legt seine Bedeutung fest, etwa Figuren- oder Geländetyp.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Der aufrufende Code stellt den Speicher bereit. Die Initialisierung reserviert und löscht ihn nicht. Brettkoordinaten werden in Zellen angegeben.
Anwendungsbeispiel
slg_board_set(&board,1,1,7);slg_board_set(&board,4,1,9);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel trennt die Aufgaben von Brett, Zugliste und Rücknahmedatensätzen. Die Brettinitialisierung behält 9 bei; ein dritter Eintrag in einer Liste mit zwei Plätzen liefert 0. Das Entnehmen allein lässt den Brettwert bei 8; erst das ausdrückliche Anwenden des Datensatzes stellt 7 wieder her.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Setzt die Zuganzahl zurück, ohne die gespeicherten Datensätze zu löschen.
Syntax
void slg_move_list_clear(SLGMoveList* list);Parameter
listZu bearbeitende Zugliste; die Initialisierung benötigt einen Zeiger, der nicht NULL ist.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Der aufrufende Code stellt den Speicher bereit. Die Initialisierung reserviert und löscht ihn nicht. Brettkoordinaten werden in Zellen angegeben.
Anwendungsbeispiel
slg_move_list_clear(&moves);result[10]=moves.count;result[11]=move_data[0].value;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel trennt die Aufgaben von Brett, Zugliste und Rücknahmedatensätzen. Die Brettinitialisierung behält 9 bei; ein dritter Eintrag in einer Liste mit zwei Plätzen liefert 0. Das Entnehmen allein lässt den Brettwert bei 8; erst das ausdrückliche Anwenden des Datensatzes stellt 7 wieder her.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Verknüpft Zugspeicher und Kapazität und setzt die Anzahl auf null.
Syntax
void slg_move_list_init(SLGMoveList* list, SLGMove* items, u8 capacity);Parameter
listZu bearbeitende Zugliste; die Initialisierung benötigt einen Zeiger, der nicht NULL ist.
itemsArray des aufrufenden Codes mit Platz für mindestens
capacityDatensätze vom TypSLGMove.capacityMaximale Anzahl der Datensätze; null erlaubt keine Ergänzungen. Jeder Datensatz enthält drei Bytes: x, y und Wert.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Der aufrufende Code stellt den Speicher bereit. Die Initialisierung reserviert und löscht ihn nicht. Brettkoordinaten werden in Zellen angegeben.
Anwendungsbeispiel
slg_move_list_init(&moves,move_data,2);result[5]=moves.count;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel trennt die Aufgaben von Brett, Zugliste und Rücknahmedatensätzen. Die Brettinitialisierung behält 9 bei; ein dritter Eintrag in einer Liste mit zwei Plätzen liefert 0. Das Entnehmen allein lässt den Brettwert bei 8; erst das ausdrückliche Anwenden des Datensatzes stellt 7 wieder her.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Hängt Koordinaten und einen Wert an die Zugliste an, ohne das Brett zu verändern.
Syntax
u8 slg_move_list_push(SLGMoveList* list, u8 x, u8 y, u8 value);Parameter
listZu bearbeitende Zugliste; die Initialisierung benötigt einen Zeiger, der nicht NULL ist.
xZellenspalte von links, beginnend bei null; das Aufzeichnen eines Zugs prüft die Brettgrenzen nicht.
yZellenzeile von oben, beginnend bei null; das Aufzeichnen eines Zugs prüft die Brettgrenzen nicht.
valueZu speichernder Byte-Wert; das Spiel legt seine Bedeutung fest, etwa Figuren- oder Geländetyp.
Rückgabewert
1 bei erfolgreichem Anhängen, 0 bei NULL oder vollem Speicher; ein Fehlschlag lässt Anzahl und vorhandene Datensätze unverändert.
Bedingungen und Grenzen
Der aufrufende Code stellt den Speicher bereit. Die Initialisierung reserviert und löscht ihn nicht. Brettkoordinaten werden in Zellen angegeben.
Anwendungsbeispiel
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;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel trennt die Aufgaben von Brett, Zugliste und Rücknahmedatensätzen. Die Brettinitialisierung behält 9 bei; ein dritter Eintrag in einer Liste mit zwei Plätzen liefert 0. Das Entnehmen allein lässt den Brettwert bei 8; erst das ausdrückliche Anwenden des Datensatzes stellt 7 wieder her.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Verknüpft den Rücknahmespeicher und seine Kapazität und beginnt mit einem leeren Stapel.
Syntax
void slg_undo_init(SLGUndoStack* stack, SLGMove* items, u8 capacity);Parameter
stackZu bearbeitender Rücknahmestapel; die Initialisierung benötigt einen Zeiger, der nicht NULL ist.
itemsArray des aufrufenden Codes mit Platz für mindestens
capacityDatensätze vom TypSLGMove.capacityMaximale Anzahl der Datensätze; null erlaubt keine Ergänzungen. Jeder Datensatz enthält drei Bytes: x, y und Wert.
Rückgabewert
Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.
Bedingungen und Grenzen
Der aufrufende Code stellt den Speicher bereit. Die Initialisierung reserviert und löscht ihn nicht. Brettkoordinaten werden in Zellen angegeben.
Anwendungsbeispiel
slg_undo_init(&undo,undo_data,2);result[12]=undo.count;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel trennt die Aufgaben von Brett, Zugliste und Rücknahmedatensätzen. Die Brettinitialisierung behält 9 bei; ein dritter Eintrag in einer Liste mit zwei Plätzen liefert 0. Das Entnehmen allein lässt den Brettwert bei 8; erst das ausdrückliche Anwenden des Datensatzes stellt 7 wieder her.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Entfernt und liefert den neuesten Rücknahmedatensatz; der aufrufende Code wendet ihn auf das Brett an.
Syntax
u8 slg_undo_pop(SLGUndoStack* stack, SLGMove* out_move);Parameter
stackZu bearbeitender Rücknahmestapel; die Initialisierung benötigt einen Zeiger, der nicht NULL ist.
out_moveZiel für den entnommenen Datensatz; NULL verwirft ihn ohne Kopie.
Rückgabewert
1, wenn ein Datensatz entnommen wurde, 0 bei einem NULL-Zeiger oder leeren Stapel; ein leerer Stapel lässt die Ausgabe unverändert.
Bedingungen und Grenzen
Der aufrufende Code stellt den Speicher bereit. Die Initialisierung reserviert und löscht ihn nicht. Brettkoordinaten werden in Zellen angegeben.
Anwendungsbeispiel
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);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel trennt die Aufgaben von Brett, Zugliste und Rücknahmedatensätzen. Die Brettinitialisierung behält 9 bei; ein dritter Eintrag in einer Liste mit zwei Plätzen liefert 0. Das Entnehmen allein lässt den Brettwert bei 8; erst das ausdrückliche Anwenden des Datensatzes stellt 7 wieder her.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Legt den bisherigen Zellwert auf den Rücknahmestapel, ohne das Brett zu verändern.
Syntax
u8 slg_undo_push(SLGUndoStack* stack, u8 x, u8 y, u8 old_value);Parameter
stackZu bearbeitender Rücknahmestapel; die Initialisierung benötigt einen Zeiger, der nicht NULL ist.
xZellenspalte von links, beginnend bei null; das Aufzeichnen eines Zugs prüft die Brettgrenzen nicht.
yZellenzeile von oben, beginnend bei null; das Aufzeichnen eines Zugs prüft die Brettgrenzen nicht.
old_valueBisheriger Byte-Wert der Zelle; die Funktion liest ihn nicht automatisch vom Brett.
Rückgabewert
1 bei erfolgreichem Anhängen, 0 bei NULL oder vollem Speicher; ein Fehlschlag lässt Anzahl und vorhandene Datensätze unverändert.
Bedingungen und Grenzen
Der aufrufende Code stellt den Speicher bereit. Die Initialisierung reserviert und löscht ihn nicht. Brettkoordinaten werden in Zellen angegeben.
Anwendungsbeispiel
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);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel trennt die Aufgaben von Brett, Zugliste und Rücknahmedatensätzen. Die Brettinitialisierung behält 9 bei; ein dritter Eintrag in einer Liste mit zwei Plätzen liefert 0. Das Entnehmen allein lässt den Brettwert bei 8; erst das ausdrückliche Anwenden des Datensatzes stellt 7 wieder her.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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-Reservierung, Positionierung, Metasprites und Animation
Sprites sind bewegliche Hardwareobjekte, meist 8×8 oder 8×16 Pixel groß, die durch Einträge im Object Attribute Memory (OAM) beschrieben werden. Reservieren Sie Einträge, setzen Sie Position, Tile und Attribute im Arbeitspuffer und übertragen Sie ihn anschließend. Ein Metasprite fasst mehrere Einträge zu einem Objekt zusammen. GB bietet 40 Einträge mit höchstens 10 pro Zeile; FC bietet 64 mit höchstens 8 pro Zeile.
GB-Attribute: Bit 4 wählt OBP1 auf DMG, Bits 5/6 spiegeln X/Y, Bit 7 legt das Sprite hinter Hintergrundpixel mit Farbindex ungleich null. Auf CGB wählen Bits 0..2 die Objektpalette und Bit 3 die VRAM-Bank der Tile-Daten; das DMG-Palettenbit wählt keine nativen CGB-Farben.
Das Beispiel nutzt die vollständige GB-Bibliothek. KQ_SPRITE_MINIMAL_RUNTIME entfernt sprite_free, sprite_set_pos, sprite_count_used, beide Zeilenabfragen, metasprite_draw und anim_update aus sprite.c. Definieren Sie es nicht, wenn Sie diese Funktionen verwenden.
anim_update
Erhöht den SpriteAnim-Zähler und gibt die gewählte Tile-Nummer zurück. Nach ticks_per_frame Aufrufen folgt das nächste fortlaufende Tile; nach frame_count Bildern beginnt die Folge von vorn. Der Aufrufer übernimmt das Ergebnis mit sprite_set_tile.
Syntax
u8 anim_update(SpriteAnim* anim);Parameter
animBeschreibbarer SpriteAnim-Zustand mit first_tile, frame_count, frame, ticks und ticks_per_frame. Bei Grenzen ungleich null muss frame kleiner als frame_count und ticks kleiner als ticks_per_frame sein.
Rückgabewert
Gewählte 8-Bit-Tile-Nummer; 0 bei einem Nullzeiger. Die Funktion schreibt nicht in das OAM.
Bedingungen und Grenzen
frame_count=0 liefert first_tile ohne Fortschritt; ticks_per_frame=0 hält das aktuelle Bild fest. Der Zähler zählt Aufrufe, keine Videobilder. Tile-Nummern laufen nach 255 über und steigen auch im 8×16-Modus jeweils nur um eins.
Das Beispiel nutzt die vollständige GB-Bibliothek. KQ_SPRITE_MINIMAL_RUNTIME entfernt sprite_free, sprite_set_pos, sprite_count_used, beide Zeilenabfragen, metasprite_draw und anim_update aus sprite.c. Definieren Sie es nicht, wenn Sie diese Funktionen verwenden.
Anwendungsbeispiel
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);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei first_tile=128, zwei Bildern und zwei Aufrufen pro Bild liefert die erste Aktualisierung Pfeil-Tile 128 und die zweite Quadrat-Tile 129. Das Quadrat neben ANIMATION zeigt, dass das Ergebnis ins OAM übernommen wurde.
Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.
NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.
Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.
Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Die lokalen Unterschiede dieser API stehen bei den Änderungen und Prüfungen vom 2026-10-03.
Platziert eine angegebene Anzahl von Sprite-Teilen in aufeinanderfolgenden Einträgen. Jeder Teil enthält vorzeichenbehaftete Versätze, Tile und Attribute. Freie Einträge werden aktiviert, aktive überschrieben; am Eintragslimit endet die Ausgabe.
Syntax
u8 metasprite_draw(u8 first_id, u8 x, u8 y, const MetaSpritePart* parts, u8 count);Parameter
first_idEintrags-ID von 0 bis SPRITE_MAX-1, standardmäßig 0..39 auf GB und 0..63 auf FC. Ungültige IDs werden ignoriert.
xHorizontale Position in Pixeln als vorzeichenloses Byte; keine Tile-Koordinate.
yY-Bildschirmkoordinate in Pixeln. Die GB-Funktion addiert vor dem Speichern im OAM den Wert 16.
partsLesbares Array mit mindestens count MetaSpritePart-Einträgen. Jeder vier Byte große Eintrag enthält vorzeichenbehaftete dx/dy-Werte, Tile und Attribute; es gibt keine Endmarkierung.
countAnzahl der Teile als vorzeichenloses Byte. Null bewirkt keine Schreibzugriffe. Beim Erreichen von SPRITE_MAX werden nur die bis dahin passenden Teile geschrieben.
Rückgabewert
Zahl geschriebener Teile von 0 bis count. Daran lässt sich erkennen, ob die Ausgabe am Eintragslimit gekürzt wurde.
Bedingungen und Grenzen
Position, Tile, Attribute und Ausblenden ändern nur den Arbeitspuffer. Sie reservieren keine Einträge und aktualisieren das Hardware-OAM nicht sofort. Übertragen Sie das vorbereitete Bild mit sprite_flush_oam.
Die vorzeichenbehafteten Byte-Versätze werden zur Basisposition addiert; das Ergebnis läuft auf acht Bit über. Das Teilearray muss während des Aufrufs lesbar bleiben. Aktive Einträge werden überschrieben, auch wenn sie zu einem anderen Objekt gehören.
Das Beispiel nutzt die vollständige GB-Bibliothek. KQ_SPRITE_MINIMAL_RUNTIME entfernt sprite_free, sprite_set_pos, sprite_count_used, beide Zeilenabfragen, metasprite_draw und anim_update aus sprite.c. Definieren Sie es nicht, wenn Sie diese Funktionen verwenden.
Anwendungsbeispiel
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.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Nach der Initialisierung sind null Einträge reserviert. Acht Reservierungen liefern 0..7. Ausblenden von Eintrag 6 belässt den Zähler bei 8; zweimalige Freigabe von 7 ergibt 7. Das Paar in Einträgen 10 und 11 erhöht ihn auf 9.
Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.
NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.
Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.
Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Reserviert den ersten freien Sprite-Eintrag und blendet ihn bis zur Positionierung aus. Ein ausgeblendeter Eintrag bleibt reserviert. Legen Sie vor der Anzeige Tile und Attribute fest.
Syntax
u8 sprite_alloc();Rückgabewert
ID des reservierten Eintrags oder 0xFF, wenn alle Einträge aktiv sind.
Bedingungen und Grenzen
Position, Tile, Attribute und Ausblenden ändern nur den Arbeitspuffer. Sie reservieren keine Einträge und aktualisieren das Hardware-OAM nicht sofort. Übertragen Sie das vorbereitete Bild mit sprite_flush_oam.
Das Beispiel nutzt die vollständige GB-Bibliothek. KQ_SPRITE_MINIMAL_RUNTIME entfernt sprite_free, sprite_set_pos, sprite_count_used, beide Zeilenabfragen, metasprite_draw und anim_update aus sprite.c. Definieren Sie es nicht, wenn Sie diese Funktionen verwenden.
Anwendungsbeispiel
for(i=0;i<8;i++) sprite_example_expect(sprite_alloc()==i);
sprite_example_expect(sprite_count_used()==8);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Nach der Initialisierung sind null Einträge reserviert. Acht Reservierungen liefern 0..7. Ausblenden von Eintrag 6 belässt den Zähler bei 8; zweimalige Freigabe von 7 ergibt 7. Das Paar in Einträgen 10 und 11 erhöht ihn auf 9.
Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.
NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.
Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.
Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Gibt die Zahl reservierter Einträge zurück, einschließlich ausgeblendeter Sprites und durch metasprite_draw aktivierter Einträge. Gezählt werden Reservierungen, keine sichtbaren Sprites.
Syntax
u8 sprite_count_used();Rückgabewert
Vorzeichenloser Bytewert von 0 bis SPRITE_MAX.
Bedingungen und Grenzen
Das Beispiel nutzt die vollständige GB-Bibliothek. KQ_SPRITE_MINIMAL_RUNTIME entfernt sprite_free, sprite_set_pos, sprite_count_used, beide Zeilenabfragen, metasprite_draw und anim_update aus sprite.c. Definieren Sie es nicht, wenn Sie diese Funktionen verwenden.
Anwendungsbeispiel
sprite_example_expect(sprite_count_used()==9); // After hiding, freeing and drawing the pair.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Nach der Initialisierung sind null Einträge reserviert. Acht Reservierungen liefern 0..7. Ausblenden von Eintrag 6 belässt den Zähler bei 8; zweimalige Freigabe von 7 ergibt 7. Das Paar in Einträgen 10 und 11 erhöht ihn auf 9.
Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.
NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.
Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.
Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Wartet auf VBlank und überträgt dann den OAM-Arbeitspuffer mit sprite_flush_oam_now.
Syntax
void sprite_flush_oam();Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Die GB-Routine führt den DMA-Code im HRAM aus und kopiert 160 Byte aus dem ausgerichteten OAM-Puffer. Währenddessen sperrt sie Interrupts und aktiviert sie danach immer; ein zuvor gesperrter Zustand wird nicht wiederhergestellt.
Das Beispiel nutzt die vollständige GB-Bibliothek. KQ_SPRITE_MINIMAL_RUNTIME entfernt sprite_free, sprite_set_pos, sprite_count_used, beide Zeilenabfragen, metasprite_draw und anim_update aus sprite.c. Definieren Sie es nicht, wenn Sie diese Funktionen verwenden.
Anwendungsbeispiel
while(1) { sprite_flush_oam(); } // Transfer prepared sprites at the next frame boundary.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.
Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.
Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.
Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Überträgt den OAM-Arbeitspuffer sofort an die Hardware. Die Routine wartet nicht auf einen sicheren Anzeigezeitraum; der aufrufende Code bestimmt den Zeitpunkt.
Syntax
void sprite_flush_oam_now();Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Die GB-Routine führt den DMA-Code im HRAM aus und kopiert 160 Byte aus dem ausgerichteten OAM-Puffer. Währenddessen sperrt sie Interrupts und aktiviert sie danach immer; ein zuvor gesperrter Zustand wird nicht wiederhergestellt.
Das Beispiel nutzt die vollständige GB-Bibliothek. KQ_SPRITE_MINIMAL_RUNTIME entfernt sprite_free, sprite_set_pos, sprite_count_used, beide Zeilenabfragen, metasprite_draw und anim_update aus sprite.c. Definieren Sie es nicht, wenn Sie diese Funktionen verwenden.
Anwendungsbeispiel
// Rendering is disabled here; all shadow entries have been prepared.
sprite_flush_oam_now();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.
Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.
Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.
Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Gibt einen reservierten Eintrag frei, blendet ihn aus und verringert die Zahl aktiver Einträge um eins. Ungültige IDs und bereits freie Einträge bleiben ohne Wirkung.
Syntax
void sprite_free(u8 id);Parameter
idEintrags-ID von 0 bis SPRITE_MAX-1, standardmäßig 0..39 auf GB und 0..63 auf FC. Ungültige IDs werden ignoriert.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Position, Tile, Attribute und Ausblenden ändern nur den Arbeitspuffer. Sie reservieren keine Einträge und aktualisieren das Hardware-OAM nicht sofort. Übertragen Sie das vorbereitete Bild mit sprite_flush_oam.
Das Beispiel nutzt die vollständige GB-Bibliothek. KQ_SPRITE_MINIMAL_RUNTIME entfernt sprite_free, sprite_set_pos, sprite_count_used, beide Zeilenabfragen, metasprite_draw und anim_update aus sprite.c. Definieren Sie es nicht, wenn Sie diese Funktionen verwenden.
Anwendungsbeispiel
sprite_free(7);sprite_free(7);
sprite_example_expect(sprite_count_used()==7); // Repeated release is ignored.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Nach der Initialisierung sind null Einträge reserviert. Acht Reservierungen liefern 0..7. Ausblenden von Eintrag 6 belässt den Zähler bei 8; zweimalige Freigabe von 7 ergibt 7. Das Paar in Einträgen 10 und 11 erhöht ihn auf 9.
Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.
NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.
Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.
Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Blendet ein Sprite durch Änderung seiner Position im Arbeitspuffer aus. Reservierung, Tile und Attribute bleiben erhalten. Eine sichtbare Position blendet es ohne erneute Reservierung wieder ein.
Syntax
void sprite_hide(u8 id);Parameter
idEintrags-ID von 0 bis SPRITE_MAX-1, standardmäßig 0..39 auf GB und 0..63 auf FC. Ungültige IDs werden ignoriert.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Position, Tile, Attribute und Ausblenden ändern nur den Arbeitspuffer. Sie reservieren keine Einträge und aktualisieren das Hardware-OAM nicht sofort. Übertragen Sie das vorbereitete Bild mit sprite_flush_oam.
Das Beispiel nutzt die vollständige GB-Bibliothek. KQ_SPRITE_MINIMAL_RUNTIME entfernt sprite_free, sprite_set_pos, sprite_count_used, beide Zeilenabfragen, metasprite_draw und anim_update aus sprite.c. Definieren Sie es nicht, wenn Sie diese Funktionen verwenden.
Anwendungsbeispiel
sprite_hide(6);
sprite_example_expect(sprite_count_used()==8); // Hiding retains allocation.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Nach der Initialisierung sind null Einträge reserviert. Acht Reservierungen liefern 0..7. Ausblenden von Eintrag 6 belässt den Zähler bei 8; zweimalige Freigabe von 7 ergibt 7. Das Paar in Einträgen 10 und 11 erhöht ihn auf 9.
Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.
NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.
Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.
Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Setzt die Sprite-Verwaltung zurück und blendet alle Einträge im OAM-Arbeitspuffer aus. Die im Programm gespeicherte Höhe wird auf 8 Pixel gesetzt. Hardwaregröße und OAM-Übertragung werden separat eingerichtet.
Syntax
void sprite_init();Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Auf GB werden alle vier Bytes jedes Eintrags gelöscht und die Installation der HRAM-DMA-Routine zurückgesetzt. Behalten Sie SPRITE_MAX=40 bei, sofern eine eigene DMA-Quelle nicht weiterhin volle 160 Byte bereitstellt.
Das Beispiel nutzt die vollständige GB-Bibliothek. KQ_SPRITE_MINIMAL_RUNTIME entfernt sprite_free, sprite_set_pos, sprite_count_used, beide Zeilenabfragen, metasprite_draw und anim_update aus sprite.c. Definieren Sie es nicht, wenn Sie diese Funktionen verwenden.
Anwendungsbeispiel
sprite_init();
sprite_example_expect(sprite_count_used()==0);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Nach der Initialisierung sind null Einträge reserviert. Acht Reservierungen liefern 0..7. Ausblenden von Eintrag 6 belässt den Zähler bei 8; zweimalige Freigabe von 7 ergibt 7. Das Paar in Einträgen 10 und 11 erhöht ihn auf 9.
Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.
NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.
Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.
Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Ermittelt aus den verwalteten Y-Positionen und kq_sprite_height die größte Zahl aktiver Sprites auf einer sichtbaren Bildschirmzeile.
Syntax
u8 sprite_max_scanline_count();Rückgabewert
Vorzeichenloser Bytewert von 0 bis SPRITE_MAX.
Bedingungen und Grenzen
Setzen Sie kq_sprite_height auf die Hardwarehöhe 8 oder 16. Transparenz, horizontale Sichtbarkeit und Hardwarepriorität werden nicht berücksichtigt. FC verwendet die Bibliothekskoordinaten; direkte Änderungen durch OAM-Intrinsics gehen nicht in die Schätzung ein.
Das Beispiel nutzt die vollständige GB-Bibliothek. KQ_SPRITE_MINIMAL_RUNTIME entfernt sprite_free, sprite_set_pos, sprite_count_used, beide Zeilenabfragen, metasprite_draw und anim_update aus sprite.c. Definieren Sie es nicht, wenn Sie diese Funktionen verwenden.
Anwendungsbeispiel
sprite_example_expect(sprite_max_scanline_count()==SPRITE_EXAMPLE_LINE_COUNT);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.
Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.
NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.
Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Ersetzt das gesamte Attributbyte. Kombinieren Sie die Konstanten der Plattform für Spiegelung, Palette und Hintergrundpriorität. Nicht gesetzte Bits werden gelöscht.
Syntax
void sprite_set_flags(u8 id, u8 flags);Parameter
idEintrags-ID von 0 bis SPRITE_MAX-1, standardmäßig 0..39 auf GB und 0..63 auf FC. Ungültige IDs werden ignoriert.
flagsVollständiges Attributbyte aus den SPRITE_FLAG_*-Konstanten der Plattform. Mehrere Flags werden mit bitweisem ODER (|) kombiniert.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Position, Tile, Attribute und Ausblenden ändern nur den Arbeitspuffer. Sie reservieren keine Einträge und aktualisieren das Hardware-OAM nicht sofort. Übertragen Sie das vorbereitete Bild mit sprite_flush_oam.
GB-Attribute: Bit 4 wählt OBP1 auf DMG, Bits 5/6 spiegeln X/Y, Bit 7 legt das Sprite hinter Hintergrundpixel mit Farbindex ungleich null. Auf CGB wählen Bits 0..2 die Objektpalette und Bit 3 die VRAM-Bank der Tile-Daten; das DMG-Palettenbit wählt keine nativen CGB-Farben.
Das Beispiel nutzt die vollständige GB-Bibliothek. KQ_SPRITE_MINIMAL_RUNTIME entfernt sprite_free, sprite_set_pos, sprite_count_used, beide Zeilenabfragen, metasprite_draw und anim_update aus sprite.c. Definieren Sie es nicht, wenn Sie diese Funktionen verwenden.
Anwendungsbeispiel
sprite_set_flags(1,SPRITE_FLAG_XFLIP);
sprite_set_flags(2,SPRITE_FLAG_YFLIP);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.
Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.
Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.
Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Verschiebt ein GB-Sprite im OAM-Arbeitspuffer anhand von Bildschirmkoordinaten in Pixeln. Die Funktion addiert die Hardwareversätze von 8 zu X und 16 zu Y.
Syntax
void sprite_set_pos(u8 id, u8 x, u8 y);Parameter
idEintrags-ID von 0 bis SPRITE_MAX-1, standardmäßig 0..39 auf GB und 0..63 auf FC. Ungültige IDs werden ignoriert.
xHorizontale Position in Pixeln als vorzeichenloses Byte; keine Tile-Koordinate.
yY-Bildschirmkoordinate in Pixeln. Die GB-Funktion addiert vor dem Speichern im OAM den Wert 16.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Position, Tile, Attribute und Ausblenden ändern nur den Arbeitspuffer. Sie reservieren keine Einträge und aktualisieren das Hardware-OAM nicht sofort. Übertragen Sie das vorbereitete Bild mit sprite_flush_oam.
Koordinaten werden mit acht Bit addiert und laufen modulo 256 über; die Bibliothek schneidet nicht am Bildschirmrand ab. Gültige Einträge sind auch ohne Reservierung bearbeitbar.
Das Beispiel nutzt die vollständige GB-Bibliothek. KQ_SPRITE_MINIMAL_RUNTIME entfernt sprite_free, sprite_set_pos, sprite_count_used, beide Zeilenabfragen, metasprite_draw und anim_update aus sprite.c. Definieren Sie es nicht, wenn Sie diese Funktionen verwenden.
Anwendungsbeispiel
sprite_set_pos(0,88,SPRITE_EXAMPLE_Y(16)); // Visible top-left: (88,16).Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.
Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.
Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.
Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Ersetzt die Tile-Nummer eines OAM-Eintrags. Damit werden bereits im Tile-Speicher liegende Grafiken ausgewählt; Grafikdaten werden weder geladen noch Sprite-Einträge reserviert.
Syntax
void sprite_set_tile(u8 id, u8 tile);Parameter
idEintrags-ID von 0 bis SPRITE_MAX-1, standardmäßig 0..39 auf GB und 0..63 auf FC. Ungültige IDs werden ignoriert.
tile8-Bit-Tile-Nummer. Die Grafik muss vorher geladen werden. Die Hardware-Regeln für 8×16-Sprites gelten weiterhin; die Nummer wird nicht für Tile-Paare angepasst.
Rückgabewert
Keiner (void).
Bedingungen und Grenzen
Position, Tile, Attribute und Ausblenden ändern nur den Arbeitspuffer. Sie reservieren keine Einträge und aktualisieren das Hardware-OAM nicht sofort. Übertragen Sie das vorbereitete Bild mit sprite_flush_oam.
Das Beispiel nutzt die vollständige GB-Bibliothek. KQ_SPRITE_MINIMAL_RUNTIME entfernt sprite_free, sprite_set_pos, sprite_count_used, beide Zeilenabfragen, metasprite_draw und anim_update aus sprite.c. Definieren Sie es nicht, wenn Sie diese Funktionen verwenden.
Anwendungsbeispiel
sprite_set_tile(5,129); // Select the green square beside ANIMATION.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Bei first_tile=128, zwei Bildern und zwei Aufrufen pro Bild liefert die erste Aktualisierung Pfeil-Tile 128 und die zweite Quadrat-Tile 129. Das Quadrat neben ANIMATION zeigt, dass das Ergebnis ins OAM übernommen wurde.
Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.
NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.
Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.
Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Vergleicht sprite_max_scanline_count mit dem Zeilenlimit von 10 Sprites auf GB beziehungsweise 8 auf FC. Das Ergebnis ist eine Softwareschätzung; das Hardware-Überlaufbit wird nicht gelesen.
Syntax
u8 sprite_warn_scanline_overflow();Rückgabewert
1 bei Überschreitung des Zeilenlimits, sonst 0.
Bedingungen und Grenzen
Setzen Sie kq_sprite_height auf die Hardwarehöhe 8 oder 16. Transparenz, horizontale Sichtbarkeit und Hardwarepriorität werden nicht berücksichtigt. FC verwendet die Bibliothekskoordinaten; direkte Änderungen durch OAM-Intrinsics gehen nicht in die Schätzung ein.
Das Beispiel nutzt die vollständige GB-Bibliothek. KQ_SPRITE_MINIMAL_RUNTIME entfernt sprite_free, sprite_set_pos, sprite_count_used, beide Zeilenabfragen, metasprite_draw und anim_update aus sprite.c. Definieren Sie es nicht, wenn Sie diese Funktionen verwenden.
Anwendungsbeispiel
sprite_example_expect(sprite_warn_scanline_overflow()==1);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.
Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.
NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.
Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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 — Spriteauswahl nach Priorität und Rotation
sprite_order setzt wichtige Objekte zuerst und rotiert die OAM-Reihenfolge bei gleicher Priorität. Es gibt bis zu 40 aus höchstens 255 Kandidaten aus und hilft bei der Zehnobjektgrenze je Zeile. sprite verwaltet Slots und DMA, sprite_order die Kandidatenauswahlreihenfolge.
Binden Sie sprite_order.h ein und kompilieren Sie sprite_order.c genau einmal. Nach der Initialisierung folgen je Frame begin, push für jeden Kandidaten und build. Die Ordnungsbibliothek selbst benötigt weder sprite.c noch globale Variablendefinitionen.
Die Hardware wählt je Rasterzeile die ersten zehn schneidenden Objekte in OAM-Reihenfolge. Niedrigere Prioritätswerte zuerst schützen wichtige Objekte auf vollen Zeilen. Rotation garantiert keine gleiche Anzeigehäufigkeit innerhalb einer Prioritätsstufe. Belegen wichtige Objekte alle zehn Plätze, bleiben niedrig priorisierte Objekte dieser Zeile unsichtbar.
SpriteOrderOamEntry enthält vier Bytes: Y, X, tile und flags. Für die OAM-Kopie aus sprite.h schreiben Sie nach (SpriteOrderOamEntry*)kq_sprite_oam. Behalten Sie SPRITE_MAX bei 40 und vermischen Sie keine vom Allocator verwalteten Slot-IDs mit umgeordneter Ausgabe: build aktualisiert dessen Verwaltung nicht.
sprite_order_begin
Leert die Kandidatenanzahl für den neuen Frame und erhält Speicher, Höhe und Phase. Anders als Neuinitialisierung je Frame bleibt die Rotation erhalten.
Syntax
void sprite_order_begin(SpriteOrder* order);Parameter
orderAdresse eines vom Aufrufer gehaltenen
SpriteOrder. Initialisieren Sie ihn vor Gebrauch und aktualisieren Sie ihn im Hauptcode.
Rückgabewert
Kein Rückgabewert. Null order wird ignoriert. Alte Eintragsbytes und bereits aufgebautes OAM werden nicht gelöscht.
Bedingungen und Grenzen
Binden Sie sprite_order.h ein und kompilieren Sie sprite_order.c genau einmal. Nach der Initialisierung folgen je Frame begin, push für jeden Kandidaten und build. Die Ordnungsbibliothek selbst benötigt weder sprite.c noch globale Variablendefinitionen.
Die Hardware wählt je Rasterzeile die ersten zehn schneidenden Objekte in OAM-Reihenfolge. Niedrigere Prioritätswerte zuerst schützen wichtige Objekte auf vollen Zeilen. Rotation garantiert keine gleiche Anzeigehäufigkeit innerhalb einer Prioritätsstufe. Belegen wichtige Objekte alle zehn Plätze, bleiben niedrig priorisierte Objekte dieser Zeile unsichtbar.
Anwendungsbeispiel
sprite_order_begin(&order_demo);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Die Lektion zeigt vierzehn Objekte in einer Zeile. Zwei Rauten unter HIGH haben hohe, zwölf Quadrate unter NORMAL normale Priorität. CGB nutzt rote Rauten und blaue Quadrate, DMG Grau und Schwarz. Beide Rauten bleiben sichtbar, aber nur acht Quadrate erscheinen. 0..B bezeichnet ihre Positionen: PHASE 04 zeigt 4..B, PHASE 08 zeigt 8..B und 0..3. Der normale Build erhöht PHASE nach jeweils 60 Framewartezeiten. Die veröffentlichten Bilder fixieren die Phase desselben Programms; wechselnde Quadratauswahl wurde auch im laufenden Programm geprüft.



Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Baut 160 Bytes OAM-Kopie in Prioritäts- und zyklischer Reihenfolge auf. Unbenutzte Slots werden durch Nullsetzen verborgen, danach wird die Phase weitergeschaltet. Der Kandidatenspeicher wird nicht umgeordnet.
Syntax
u8 sprite_order_build(SpriteOrder* order, SpriteOrderOamEntry* output, u8 limit);Parameter
orderAdresse eines vom Aufrufer gehaltenen
SpriteOrder. Initialisieren Sie ihn vor Gebrauch und aktualisieren Sie ihn im Hauptcode.outputBeschreibbares Array mit 40
SpriteOrderOamEntry. Alle 160 Bytes werden geschrieben, auch bei limit null oder kleiner als 40.limitMaximale Ausgabeanzahl 0..40; größere Werte werden auf 40 begrenzt. Gilt für das gesamte OAM, nicht je Zeile.
Rückgabewert
Liefert die Ausgabeanzahl 0..40. Eine gültige leere Warteschlange löscht alle Slots und setzt phase=0. Sonst wird phase modulo count normalisiert, dieser zyklische Start je aufsteigender Prioritätsstufe verwendet und phase danach erhöht und umgebrochen. Auch limit null schaltet die Phase weiter. Null order/output, deaktivierter Zustand, ungültige Höhe oder count>capacity liefert null ohne Änderung von Ausgabe oder Phase.
Bedingungen und Grenzen
Die Hardware wählt je Rasterzeile die ersten zehn schneidenden Objekte in OAM-Reihenfolge. Niedrigere Prioritätswerte zuerst schützen wichtige Objekte auf vollen Zeilen. Rotation garantiert keine gleiche Anzeigehäufigkeit innerhalb einer Prioritätsstufe. Belegen wichtige Objekte alle zehn Plätze, bleiben niedrig priorisierte Objekte dieser Zeile unsichtbar.
priority steuert die Auswahlreihenfolge unabhängig vom Attribut hinter dem Hintergrund. Auf DMG gewinnt bei ausgewählten überlappenden Objekten das kleinere X, bei Gleichstand die OAM-Reihenfolge. Normaler CGB-Farbmodus nutzt OAM, eine über OPRI gewählte DMG-Anordnung gilt jedoch weiterhin. Die Bibliothek ändert keine Hardwareprioritätsregeln.
SpriteOrderOamEntry enthält vier Bytes: Y, X, tile und flags. Für die OAM-Kopie aus sprite.h schreiben Sie nach (SpriteOrderOamEntry*)kq_sprite_oam. Behalten Sie SPRITE_MAX bei 40 und vermischen Sie keine vom Allocator verwalteten Slot-IDs mit umgeordneter Ausgabe: build aktualisiert dessen Verwaltung nicht.
build schreibt nur RAM. Stellen Sie ein 160-Byte-Ausgabearray ohne Überlappung mit Zustand oder Kandidatenspeicher bereit. OAM-DMA-Puffer müssen an einer 256-Byte-Grenze beginnen. Beenden Sie den Aufbau vor der VBlank-Übertragung; Interrupts dürfen keinen halbfertigen Puffer übertragen. Das Beispiel nutzt sprite_flush_oam.
Jede Einreichung hat begrenzten Aufwand. Der Aufbau löscht 160 Bytes OAM-Kopie und durchläuft das Kandidatenarray bis zu viermal, ohne es zu sortieren oder einen Sortierpuffer zu benötigen. Das garantiert nicht, dass 255 Kandidaten ins Framebudget passen; reichen Sie nur benötigte Kandidaten ein.
Anwendungsbeispiel
order_demo_state[1]=sprite_order_build(&order_demo,(SpriteOrderOamEntry*)kq_sprite_oam,40);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Die Lektion zeigt vierzehn Objekte in einer Zeile. Zwei Rauten unter HIGH haben hohe, zwölf Quadrate unter NORMAL normale Priorität. CGB nutzt rote Rauten und blaue Quadrate, DMG Grau und Schwarz. Beide Rauten bleiben sichtbar, aber nur acht Quadrate erscheinen. 0..B bezeichnet ihre Positionen: PHASE 04 zeigt 4..B, PHASE 08 zeigt 8..B und 0..3. Der normale Build erhöht PHASE nach jeweils 60 Framewartezeiten. Die veröffentlichten Bilder fixieren die Phase desselben Programms; wechselnde Quadratauswahl wurde auch im laufenden Programm geprüft.



Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Bindet Kandidatenspeicher an den Ordnungszustand und setzt Anzahl sowie Rotationsphase zurück. Für Szenenbeginn oder Speicherwechsel.
Syntax
u8 sprite_order_init(SpriteOrder* order, SpriteOrderItem* items, u8 capacity, u8 height);Parameter
orderAdresse eines vom Aufrufer gehaltenen
SpriteOrder. Initialisieren Sie ihn vor Gebrauch und aktualisieren Sie ihn im Hauptcode.itemsBeschreibbares
SpriteOrderItem-Array mit fünf Bytes pro Eintrag. Reservieren Sie capacity Einträge und halten Sie den Speicher gültig.capacityArraykapazität 1..255 Einträge, weder Byteanzahl noch Hardware-Slotzahl.
heightAlle Objekte teilen dieselbe Höhe. Übergeben Sie 8 oder 16 passend zu LCDCs 8×8-/8×16-Modus; die Bibliothek setzt LCDC nicht. Im 8×16-Modus ignoriert die Hardware das niederwertigste Bit der Kachelnummer.
Rückgabewert
Liefert bei Erfolg 1, sonst 0 für null items, Kapazität null, Höhe ungleich 8/16 oder null order. Bei gültigem order hinterlässt ein Fehler den deaktivierten Zustand items=NULL, capacity=count=phase=0, height=8. Das Eintragsarray bleibt unverändert.
Bedingungen und Grenzen
Binden Sie sprite_order.h ein und kompilieren Sie sprite_order.c genau einmal. Nach der Initialisierung folgen je Frame begin, push für jeden Kandidaten und build. Die Ordnungsbibliothek selbst benötigt weder sprite.c noch globale Variablendefinitionen.
Anwendungsbeispiel
sprite_init();sprite_order_init(&order_demo,order_demo_items,14,8);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Die Lektion zeigt vierzehn Objekte in einer Zeile. Zwei Rauten unter HIGH haben hohe, zwölf Quadrate unter NORMAL normale Priorität. CGB nutzt rote Rauten und blaue Quadrate, DMG Grau und Schwarz. Beide Rauten bleiben sichtbar, aber nur acht Quadrate erscheinen. 0..B bezeichnet ihre Positionen: PHASE 04 zeigt 4..B, PHASE 08 zeigt 8..B und 0..3. Der normale Build erhöht PHASE nach jeweils 60 Framewartezeiten. Die veröffentlichten Bilder fixieren die Phase desselben Programms; wechselnde Quadratauswahl wurde auch im laufenden Programm geprüft.



Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Reicht ein Sprite mit mindestens einem sichtbaren Pixel ein. Vollständig außerhalb liegende Kandidaten werden vor Verbrauch eines OAM-Auswahlplatzes abgelehnt.
Syntax
u8 sprite_order_push(SpriteOrder* order, s16 x, s16 y, u8 tile, u8 flags, u8 priority);Parameter
orderAdresse eines vom Aufrufer gehaltenen
SpriteOrder. Initialisieren Sie ihn vor Gebrauch und aktualisieren Sie ihn im Hauptcode.xVorzeichenbehaftetes Bildschirm-X ab links oben. Linke Kanten −7..159 sind zulässig; ≤−8 oder ≥160 liegt vollständig außerhalb. Für OAM-Koordinaten werden beim Speichern 8 addiert.
yVorzeichenbehaftetes Bildschirm-Y ab links oben. Zulässig: −7..143 bei Höhe 8, −15..143 bei Höhe 16. Beim Speichern werden für OAM 16 addiert.
tileKachelnummer 0..255, unverändert gespeichert. Für 8×16 siehe Höhenhinweise.
flagsHardwareattributbyte, unverändert gespeichert: Spiegelung, Hintergrundpriorität, DMG-/CGB-Palette und CGB-VRAM-Bank behalten ihre Hardwarebedeutung.
prioritySoftwareauswahlpriorität 0..3, null zuerst. Werte ab vier werden abgelehnt. Unabhängig vom Hardware-Flagsbyte.
Rückgabewert
Bei Annahme Rückgabe 1 und count-Erhöhung. Null/deaktivierter Zustand, ungültige Höhe, voller Speicher, ungültige Priorität oder vollständig unsichtbares Objekt ergeben 0 ohne Änderung von items oder count.
Bedingungen und Grenzen
Alle Objekte teilen dieselbe Höhe. Übergeben Sie 8 oder 16 passend zu LCDCs 8×8-/8×16-Modus; die Bibliothek setzt LCDC nicht. Im 8×16-Modus ignoriert die Hardware das niederwertigste Bit der Kachelnummer.
Die Hardware wählt je Rasterzeile die ersten zehn schneidenden Objekte in OAM-Reihenfolge. Niedrigere Prioritätswerte zuerst schützen wichtige Objekte auf vollen Zeilen. Rotation garantiert keine gleiche Anzeigehäufigkeit innerhalb einer Prioritätsstufe. Belegen wichtige Objekte alle zehn Plätze, bleiben niedrig priorisierte Objekte dieser Zeile unsichtbar.
priority steuert die Auswahlreihenfolge unabhängig vom Attribut hinter dem Hintergrund. Auf DMG gewinnt bei ausgewählten überlappenden Objekten das kleinere X, bei Gleichstand die OAM-Reihenfolge. Normaler CGB-Farbmodus nutzt OAM, eine über OPRI gewählte DMG-Anordnung gilt jedoch weiterhin. Die Bibliothek ändert keine Hardwareprioritätsregeln.
Anwendungsbeispiel
sprite_order_push(&order_demo,8,64,128,0,0);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Die Lektion zeigt vierzehn Objekte in einer Zeile. Zwei Rauten unter HIGH haben hohe, zwölf Quadrate unter NORMAL normale Priorität. CGB nutzt rote Rauten und blaue Quadrate, DMG Grau und Schwarz. Beide Rauten bleiben sichtbar, aber nur acht Quadrate erscheinen. 0..B bezeichnet ihre Positionen: PHASE 04 zeigt 4..B, PHASE 08 zeigt 8..B und 0..3. Der normale Build erhöht PHASE nach jeweils 60 Framewartezeiten. Die veröffentlichten Bilder fixieren die Phase desselben Programms; wechselnde Quadratauswahl wurde auch im laufenden Programm geprüft.



Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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 — Start, Bildzähler, Wartefunktionen und Interrupts
Verwaltet Frame-Wartezähler, Callbacks nach dem Warten und die Steuerung maskierbarer CPU-Interrupts.
gb_disable_interrupts
gb_disable_interrupts ist ein Alias für system_disable_interrupts. Deaktiviert CPU-Interrupts auf dem GB.
Deaktiviert maskierbare CPU-Interrupts.
Syntax
void gb_disable_interrupts();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Der Header definiert ein objektartiges Makro, das zum Implementierungsnamen expandiert. Argumente, Rückgabewerte und Zustandszugriffe entsprechen dem Ziel; der Alias fügt keinen eigenen Zustand oder Verarbeitungsschritt hinzu. Verwenden Sie wie im vollständigen Beispiel und Buildbefehl input.h/input.c für Eingaben oder system.h/system.c für Framedienste.
Halten Sie geschützte Aktualisierungen kurz und stellen Sie die Interrupts danach passend wieder her. Die Interruptsperre ist unabhängig von den Voraussetzungen einer Frame-Warteroutine.
Auf dem GB endet das Warten bei ausgeschaltetem LCD sofort. Die umgebende Funktion erhöht dennoch ihren Zähler und ruft ihren Callback auf. Die Initialisierung allein richtet weder das LCD noch die Interruptquellen ein.
Bauen Sie dieses vollständige Beispiel mit der standardmäßigen Legacy-ABI. Seine Callbacks verwenden Funktionszeigeraufrufe, die der Compiler mit --abi=stack als nicht unterstützt abweist. Dieselbe Einschränkung gilt bei Verwendung eines Alias.
Anwendungsbeispiel
gb_disable_interrupts();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel kombiniert Deaktivierung und Aktivierung. Eigene Prüfprogramme kontrollieren zusätzlich den CPU-Interruptzustand.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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 ist ein Alias für system_enable_interrupts. Aktiviert CPU-Interrupts auf dem GB.
Aktiviert maskierbare CPU-Interrupts.
Syntax
void gb_enable_interrupts();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Der Header definiert ein objektartiges Makro, das zum Implementierungsnamen expandiert. Argumente, Rückgabewerte und Zustandszugriffe entsprechen dem Ziel; der Alias fügt keinen eigenen Zustand oder Verarbeitungsschritt hinzu. Verwenden Sie wie im vollständigen Beispiel und Buildbefehl input.h/input.c für Eingaben oder system.h/system.c für Framedienste.
Bereiten Sie Interruptquellen und Handler vor der Aktivierung vor. Auf FC ist dies unabhängig davon, ob NMI aktiviert oder deaktiviert ist.
Auf dem GB endet das Warten bei ausgeschaltetem LCD sofort. Die umgebende Funktion erhöht dennoch ihren Zähler und ruft ihren Callback auf. Die Initialisierung allein richtet weder das LCD noch die Interruptquellen ein.
Bauen Sie dieses vollständige Beispiel mit der standardmäßigen Legacy-ABI. Seine Callbacks verwenden Funktionszeigeraufrufe, die der Compiler mit --abi=stack als nicht unterstützt abweist. Dieselbe Einschränkung gilt bei Verwendung eines Alias.
Anwendungsbeispiel
gb_enable_interrupts();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel stellt die Interrupts wieder her. Das FC-Programm deaktiviert zuerst die APU-Frame- und DMC-IRQ-Quellen, damit eine nicht quittierte IRQ nicht wiederholt bearbeitet wird.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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 ist ein Alias für system_get_frame. Liest den 16-Bit-Softwarezähler der abgeschlossenen Warteaufrufe des Wrappers.
Liest den 16-Bit-Zähler der Frame-Wartefunktion.
Syntax
u16 gb_frame_count();Rückgabewert
Gibt den aktuellen Zählerstand von 0 bis 65535 zurück.
Bedingungen und Grenzen
Der Header definiert ein objektartiges Makro, das zum Implementierungsnamen expandiert. Argumente, Rückgabewerte und Zustandszugriffe entsprechen dem Ziel; der Alias fügt keinen eigenen Zustand oder Verarbeitungsschritt hinzu. Verwenden Sie wie im vollständigen Beispiel und Buildbefehl input.h/input.c für Eingaben oder system.h/system.c für Framedienste.
Der Zähler zählt Wartevorgänge über diese Wrapper-Funktion, nicht automatisch die tatsächlich verstrichenen Hardware-Frames. Beim Überlauf nach 16 Bits beginnt er wieder bei null.
Auf dem GB endet das Warten bei ausgeschaltetem LCD sofort. Die umgebende Funktion erhöht dennoch ihren Zähler und ruft ihren Callback auf. Die Initialisierung allein richtet weder das LCD noch die Interruptquellen ein.
Bauen Sie dieses vollständige Beispiel mit der standardmäßigen Legacy-ABI. Seine Callbacks verwenden Funktionszeigeraufrufe, die der Compiler mit --abi=stack als nicht unterstützt abweist. Dieselbe Einschränkung gilt bei Verwendung eines Alias.
Anwendungsbeispiel
result[3]=gb_frame_count();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel liest nach drei Wartevorgängen drei. Für den Überlauftest wird der Zähler ausdrücklich auf 65535 gesetzt und nach dem nächsten Wartevorgang auf null geprüft.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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 ist ein Alias für system_init. Setzt den Software-Framezähler und die Callback-Registrierung zurück.
Initialisiert die Frame-Verwaltung, indem Zähler und registrierter Callback gelöscht werden.
Syntax
void gb_init();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Der Header definiert ein objektartiges Makro, das zum Implementierungsnamen expandiert. Argumente, Rückgabewerte und Zustandszugriffe entsprechen dem Ziel; der Alias fügt keinen eigenen Zustand oder Verarbeitungsschritt hinzu. Verwenden Sie wie im vollständigen Beispiel und Buildbefehl input.h/input.c für Eingaben oder system.h/system.c für Framedienste.
Der Zähler zählt Wartevorgänge über diese Wrapper-Funktion, nicht automatisch die tatsächlich verstrichenen Hardware-Frames. Beim Überlauf nach 16 Bits beginnt er wieder bei null.
Auf dem GB endet das Warten bei ausgeschaltetem LCD sofort. Die umgebende Funktion erhöht dennoch ihren Zähler und ruft ihren Callback auf. Die Initialisierung allein richtet weder das LCD noch die Interruptquellen ein.
Bauen Sie dieses vollständige Beispiel mit der standardmäßigen Legacy-ABI. Seine Callbacks verwenden Funktionszeigeraufrufe, die der Compiler mit --abi=stack als nicht unterstützt abweist. Dieselbe Einschränkung gilt bei Verwendung eines Alias.
Anwendungsbeispiel
gb_init();result[0]=gb_frame_count();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel bestätigt vor dem Registrieren des Callbacks, dass die anfängliche Frame-Nummer null ist.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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 ist ein Alias für system_set_vblank_callback. Registriert oder entfernt den nach dem Framewarten synchron aufgerufenen Callback.
Registriert, ersetzt oder entfernt die nach einem Frame-Wartevorgang aufgerufene Funktion.
Syntax
void gb_set_vblank_callback(SystemCallback callback);Parameter
callbackAufzurufende Funktion; 0 entfernt den Callback.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Der Header definiert ein objektartiges Makro, das zum Implementierungsnamen expandiert. Argumente, Rückgabewerte und Zustandszugriffe entsprechen dem Ziel; der Alias fügt keinen eigenen Zustand oder Verarbeitungsschritt hinzu. Verwenden Sie wie im vollständigen Beispiel und Buildbefehl input.h/input.c für Eingaben oder system.h/system.c für Framedienste.
Dies ist ein gewöhnlicher Zeiger auf eine Funktion ohne Parameter und Rückgabewert. Er enthält keine Banknummer; der Zielcode muss eingeblendet bleiben, solange Aufrufe möglich sind.
Auf dem GB endet das Warten bei ausgeschaltetem LCD sofort. Die umgebende Funktion erhöht dennoch ihren Zähler und ruft ihren Callback auf. Die Initialisierung allein richtet weder das LCD noch die Interruptquellen ein.
Bauen Sie dieses vollständige Beispiel mit der standardmäßigen Legacy-ABI. Seine Callbacks verwenden Funktionszeigeraufrufe, die der Compiler mit --abi=stack als nicht unterstützt abweist. Dieselbe Einschränkung gilt bei Verwendung eines Alias.
Anwendungsbeispiel
gb_set_vblank_callback(on_frame);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Nach drei Callback-Aufrufen deaktiviert die Registrierung von 0 den Aufruf. Der nächste Wartevorgang erhöht den Frame-Zähler auf vier, während die Callback-Anzahl drei bleibt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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 ist ein Alias für system_wait_vblank. Wartet auf die Framegrenze, erhöht den Software-Framezähler und ruft den registrierten Callback auf.
Wartet auf den nächsten Frame, erhöht den Zähler und ruft anschließend den registrierten Callback auf.
Syntax
void gb_wait_vblank();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Der Header definiert ein objektartiges Makro, das zum Implementierungsnamen expandiert. Argumente, Rückgabewerte und Zustandszugriffe entsprechen dem Ziel; der Alias fügt keinen eigenen Zustand oder Verarbeitungsschritt hinzu. Verwenden Sie wie im vollständigen Beispiel und Buildbefehl input.h/input.c für Eingaben oder system.h/system.c für Framedienste.
Der Callback läuft synchron innerhalb dieser Funktion; seine Registrierung installiert keinen Interrupt-Handler. Der Zähler zählt die Wartevorgänge dieses Wrappers und misst nicht automatisch die verstrichenen Hardware-Frames. Beim 16-Bit-Überlauf beginnt er wieder bei null.
Auf dem GB endet das Warten bei ausgeschaltetem LCD sofort. Die umgebende Funktion erhöht dennoch ihren Zähler und ruft ihren Callback auf. Die Initialisierung allein richtet weder das LCD noch die Interruptquellen ein.
Bauen Sie dieses vollständige Beispiel mit der standardmäßigen Legacy-ABI. Seine Callbacks verwenden Funktionszeigeraufrufe, die der Compiler mit --abi=stack als nicht unterstützt abweist. Dieselbe Einschränkung gilt bei Verwendung eines Alias.
Anwendungsbeispiel
gb_wait_vblank();gb_wait_vblank();gb_wait_vblank();result[1]=frame_calls;result[2]=frame_seen;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Drei Wartevorgänge rufen den Callback dreimal auf; der zuletzt darin gelesene Zählerstand beträgt drei.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Deaktiviert maskierbare CPU-Interrupts.
Syntax
void system_disable_interrupts();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Halten Sie geschützte Aktualisierungen kurz und stellen Sie die Interrupts danach passend wieder her. Die Interruptsperre ist unabhängig von den Voraussetzungen einer Frame-Warteroutine.
Auf dem GB endet das Warten bei ausgeschaltetem LCD sofort. Die umgebende Funktion erhöht dennoch ihren Zähler und ruft ihren Callback auf. Die Initialisierung allein richtet weder das LCD noch die Interruptquellen ein.
Bauen Sie dieses vollständige Beispiel mit der standardmäßigen Legacy-ABI. Seine Callbacks verwenden Funktionszeigeraufrufe, die der Compiler mit --abi=stack als nicht unterstützt abweist. Dieselbe Einschränkung gilt bei Verwendung eines Alias.
Anwendungsbeispiel
system_disable_interrupts();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel kombiniert Deaktivierung und Aktivierung. Eigene Prüfprogramme kontrollieren zusätzlich den CPU-Interruptzustand.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Aktiviert maskierbare CPU-Interrupts.
Syntax
void system_enable_interrupts();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Bereiten Sie Interruptquellen und Handler vor der Aktivierung vor. Auf FC ist dies unabhängig davon, ob NMI aktiviert oder deaktiviert ist.
Auf dem GB endet das Warten bei ausgeschaltetem LCD sofort. Die umgebende Funktion erhöht dennoch ihren Zähler und ruft ihren Callback auf. Die Initialisierung allein richtet weder das LCD noch die Interruptquellen ein.
Bauen Sie dieses vollständige Beispiel mit der standardmäßigen Legacy-ABI. Seine Callbacks verwenden Funktionszeigeraufrufe, die der Compiler mit --abi=stack als nicht unterstützt abweist. Dieselbe Einschränkung gilt bei Verwendung eines Alias.
Anwendungsbeispiel
system_enable_interrupts();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel stellt die Interrupts wieder her. Das FC-Programm deaktiviert zuerst die APU-Frame- und DMC-IRQ-Quellen, damit eine nicht quittierte IRQ nicht wiederholt bearbeitet wird.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Liest den 16-Bit-Zähler der Frame-Wartefunktion.
Syntax
u16 system_get_frame();Rückgabewert
Gibt den aktuellen Zählerstand von 0 bis 65535 zurück.
Bedingungen und Grenzen
Der Zähler zählt Wartevorgänge über diese Wrapper-Funktion, nicht automatisch die tatsächlich verstrichenen Hardware-Frames. Beim Überlauf nach 16 Bits beginnt er wieder bei null.
Auf dem GB endet das Warten bei ausgeschaltetem LCD sofort. Die umgebende Funktion erhöht dennoch ihren Zähler und ruft ihren Callback auf. Die Initialisierung allein richtet weder das LCD noch die Interruptquellen ein.
Bauen Sie dieses vollständige Beispiel mit der standardmäßigen Legacy-ABI. Seine Callbacks verwenden Funktionszeigeraufrufe, die der Compiler mit --abi=stack als nicht unterstützt abweist. Dieselbe Einschränkung gilt bei Verwendung eines Alias.
Anwendungsbeispiel
result[3]=system_get_frame();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel liest nach drei Wartevorgängen drei. Für den Überlauftest wird der Zähler ausdrücklich auf 65535 gesetzt und nach dem nächsten Wartevorgang auf null geprüft.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Liest für kurze Wiederholungsintervalle die unteren acht Bits des Frame-Zählers.
Syntax
u8 system_get_frame8();Rückgabewert
Gibt das niederwertige Byte von 0 bis 255 zurück.
Bedingungen und Grenzen
Der Zähler zählt Wartevorgänge über diese Wrapper-Funktion, nicht automatisch die tatsächlich verstrichenen Hardware-Frames. Beim Überlauf nach 16 Bits beginnt er wieder bei null.
Auf dem GB endet das Warten bei ausgeschaltetem LCD sofort. Die umgebende Funktion erhöht dennoch ihren Zähler und ruft ihren Callback auf. Die Initialisierung allein richtet weder das LCD noch die Interruptquellen ein.
Bauen Sie dieses vollständige Beispiel mit der standardmäßigen Legacy-ABI. Seine Callbacks verwenden Funktionszeigeraufrufe, die der Compiler mit --abi=stack als nicht unterstützt abweist. Dieselbe Einschränkung gilt bei Verwendung eines Alias.
Anwendungsbeispiel
result[4]=system_get_frame8();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel liest nach drei Wartevorgängen drei und beim Überlauf des 16-Bit-Zählers null.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Initialisiert die Frame-Verwaltung, indem Zähler und registrierter Callback gelöscht werden.
Syntax
void system_init();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Der Zähler zählt Wartevorgänge über diese Wrapper-Funktion, nicht automatisch die tatsächlich verstrichenen Hardware-Frames. Beim Überlauf nach 16 Bits beginnt er wieder bei null.
Auf dem GB endet das Warten bei ausgeschaltetem LCD sofort. Die umgebende Funktion erhöht dennoch ihren Zähler und ruft ihren Callback auf. Die Initialisierung allein richtet weder das LCD noch die Interruptquellen ein.
Bauen Sie dieses vollständige Beispiel mit der standardmäßigen Legacy-ABI. Seine Callbacks verwenden Funktionszeigeraufrufe, die der Compiler mit --abi=stack als nicht unterstützt abweist. Dieselbe Einschränkung gilt bei Verwendung eines Alias.
Anwendungsbeispiel
system_init();result[0]=system_get_frame();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das Beispiel bestätigt vor dem Registrieren des Callbacks, dass die anfängliche Frame-Nummer null ist.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Registriert, ersetzt oder entfernt die nach einem Frame-Wartevorgang aufgerufene Funktion.
Syntax
void system_set_vblank_callback(SystemCallback callback);Parameter
callbackAufzurufende Funktion; 0 entfernt den Callback.
Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Dies ist ein gewöhnlicher Zeiger auf eine Funktion ohne Parameter und Rückgabewert. Er enthält keine Banknummer; der Zielcode muss eingeblendet bleiben, solange Aufrufe möglich sind.
Auf dem GB endet das Warten bei ausgeschaltetem LCD sofort. Die umgebende Funktion erhöht dennoch ihren Zähler und ruft ihren Callback auf. Die Initialisierung allein richtet weder das LCD noch die Interruptquellen ein.
Bauen Sie dieses vollständige Beispiel mit der standardmäßigen Legacy-ABI. Seine Callbacks verwenden Funktionszeigeraufrufe, die der Compiler mit --abi=stack als nicht unterstützt abweist. Dieselbe Einschränkung gilt bei Verwendung eines Alias.
Anwendungsbeispiel
system_set_vblank_callback(on_frame);Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Nach drei Callback-Aufrufen deaktiviert die Registrierung von 0 den Aufruf. Der nächste Wartevorgang erhöht den Frame-Zähler auf vier, während die Callback-Anzahl drei bleibt.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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
Wartet auf den nächsten Frame, erhöht den Zähler und ruft anschließend den registrierten Callback auf.
Syntax
void system_wait_vblank();Rückgabewert
Kein Rückgabewert.
Bedingungen und Grenzen
Der Callback läuft synchron innerhalb dieser Funktion; seine Registrierung installiert keinen Interrupt-Handler. Der Zähler zählt die Wartevorgänge dieses Wrappers und misst nicht automatisch die verstrichenen Hardware-Frames. Beim 16-Bit-Überlauf beginnt er wieder bei null.
Auf dem GB endet das Warten bei ausgeschaltetem LCD sofort. Die umgebende Funktion erhöht dennoch ihren Zähler und ruft ihren Callback auf. Die Initialisierung allein richtet weder das LCD noch die Interruptquellen ein.
Bauen Sie dieses vollständige Beispiel mit der standardmäßigen Legacy-ABI. Seine Callbacks verwenden Funktionszeigeraufrufe, die der Compiler mit --abi=stack als nicht unterstützt abweist. Dieselbe Einschränkung gilt bei Verwendung eines Alias.
Anwendungsbeispiel
system_wait_vblank();system_wait_vblank();system_wait_vblank();result[1]=frame_calls;result[2]=frame_seen;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Drei Wartevorgänge rufen den Callback dreimal auf; der zuletzt darin gelesene Zählerstand beträgt drei.


Vollständiges Beispielprogramm
Build-Befehl
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=64kImplementierung und Quelltext
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-Aktualisierungen und Übertragung per Warteschlange
Initialisiert die Warteschlange für aufgeschobene VRAM-Schreibbefehle als leer und löscht die Überlaufmeldung. Löscht weder den Bildschirm noch lädt es Tile-Grafiken oder reserviert physischen VRAM.
GB zählt Befehlsplätze; die Standardkapazität beträgt 32. Jeder Einfügeaufruf belegt einen Platz, auch bei großen Übertragungen oder Länge null. Setzen Sie VRAM_QUEUE_MAX in allen Übersetzungseinheiten einheitlich auf 1 bis 255. Eine leere Warteschlange hat used=0 und free=capacity.
Wartet mit __wait_vblank und ruft anschließend vram_flush_now auf. Geeignet für einen überschaubaren Satz von Bildschirmänderungen. Einmaliges Warten begrenzt die Übertragungsmenge nicht und garantiert keinen Abschluss innerhalb eines VBlank.
Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.
vram_clear_queue
Verwirft ausstehende VRAM-Befehle und löscht das Überlaufflag, ohne die Schreibvorgänge auszuführen.
Syntax
void vram_clear_queue();Rückgabewert
Keiner (void).
Bedingungen und Grenzen
GB zählt Befehlsplätze; die Standardkapazität beträgt 32. Jeder Einfügeaufruf belegt einen Platz, auch bei großen Übertragungen oder Länge null. Setzen Sie VRAM_QUEUE_MAX in allen Übersetzungseinheiten einheitlich auf 1 bis 255. Eine leere Warteschlange hat used=0 und free=capacity.
Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.
Anwendungsbeispiel
vram_clear_queue();
if (vram_get_queue_used()!=0 || vram_get_overflowed()!=0) failures++;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.
Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.
Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.
Im CGB-Modus sind die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat rot. Das Rechteck von 32 × 24 und die Kopie aus zwei Mustern sind blau. Der Block aus 3 × 2 Kacheln und der Balken von 40 × 8 sind grün. Text bleibt schwarz auf Weiß. Neben der Geometrie wird die Farbe jedes gezeichneten Pixels geprüft.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Wartet mit __wait_vblank und ruft anschließend vram_flush_now auf. Geeignet für einen überschaubaren Satz von Bildschirmänderungen. Einmaliges Warten begrenzt die Übertragungsmenge nicht und garantiert keinen Abschluss innerhalb eines VBlank.
Syntax
void vram_flush();Rückgabewert
Keiner (void).
Bedingungen und Grenzen
GB zählt Befehlsplätze; die Standardkapazität beträgt 32. Jeder Einfügeaufruf belegt einen Platz, auch bei großen Übertragungen oder Länge null. Setzen Sie VRAM_QUEUE_MAX in allen Übersetzungseinheiten einheitlich auf 1 bis 255. Eine leere Warteschlange hat used=0 und free=capacity.
Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.
Zieladresse in Bytes im VRAM (0x8000–0x9FFF), in der bei der Ausführung gewählten Bank. Die Übertragung ist fortlaufend, ohne Zeilenumbruch. Der gesamte Zielbereich muss gültig sein. Bei eingeschaltetem LCD können die sicheren Schreibpfade Interrupts einschalten; ein beim Aufruf gesperrter Interruptzustand bleibt nicht erhalten.
Anwendungsbeispiel
vram_flush(); // One small write through the VBlank/NMI path.
if (vram_get_queue_used()!=0) failures++;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.
Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.
Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.
Im CGB-Modus sind die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat rot. Das Rechteck von 32 × 24 und die Kopie aus zwei Mustern sind blau. Der Block aus 3 × 2 Kacheln und der Balken von 40 × 8 sind grün. Text bleibt schwarz auf Weiß. Neben der Geometrie wird die Farbe jedes gezeichneten Pixels geprüft.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Führt alle Befehle in Einfügereihenfolge aus und setzt die belegte Anzahl auf 0. Wartet selbst nicht auf VBlank. Bei eingeschaltetem LCD warten die sicheren VRAM-Intrinsics auf beschreibbare Zeitfenster; eine große Warteschlange kann dennoch mehrere Zeilen oder Frames beanspruchen. Die Überlaufmeldung bleibt erhalten.
Syntax
void vram_flush_now();Rückgabewert
Keiner (void).
Bedingungen und Grenzen
GB zählt Befehlsplätze; die Standardkapazität beträgt 32. Jeder Einfügeaufruf belegt einen Platz, auch bei großen Übertragungen oder Länge null. Setzen Sie VRAM_QUEUE_MAX in allen Übersetzungseinheiten einheitlich auf 1 bis 255. Eine leere Warteschlange hat used=0 und free=capacity.
Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.
Zieladresse in Bytes im VRAM (0x8000–0x9FFF), in der bei der Ausführung gewählten Bank. Die Übertragung ist fortlaufend, ohne Zeilenumbruch. Der gesamte Zielbereich muss gültig sein. Bei eingeschaltetem LCD können die sicheren Schreibpfade Interrupts einschalten; ein beim Aufruf gesperrter Interruptzustand bleibt nicht erhalten.
Anwendungsbeispiel
// 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++;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.
Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.
Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.
Im CGB-Modus sind die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat rot. Das Rechteck von 32 × 24 und die Kopie aus zwei Mustern sind blau. Der Block aus 3 × 2 Kacheln und der Balken von 40 × 8 sind grün. Text bleibt schwarz auf Weiß. Neben der Geometrie wird die Farbe jedes gezeichneten Pixels geprüft.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Liest das Überlaufflag, ohne es zu löschen; es kann einen früheren Fehler festhalten.
Syntax
u8 vram_get_overflowed();Rückgabewert
0 ohne gespeicherten Überlauf; nach einem abgelehnten Eintrag 1 bis zum ausdrücklichen Zurücksetzen. Die Ausführung der Warteschlange löscht diese Meldung nicht.
Bedingungen und Grenzen
GB zählt Befehlsplätze; die Standardkapazität beträgt 32. Jeder Einfügeaufruf belegt einen Platz, auch bei großen Übertragungen oder Länge null. Setzen Sie VRAM_QUEUE_MAX in allen Übersetzungseinheiten einheitlich auf 1 bis 255. Eine leere Warteschlange hat used=0 und free=capacity.
Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.
Anwendungsbeispiel
overflow_seen=vram_get_overflowed();
if (overflow_seen!=1) failures++;
// Reading the latch again does not clear it.
if (vram_get_overflowed()!=1) failures++;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.
Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.
Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.
Im CGB-Modus sind die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat rot. Das Rechteck von 32 × 24 und die Kopie aus zwei Mustern sind blau. Der Block aus 3 × 2 Kacheln und der Balken von 40 × 8 sind grün. Text bleibt schwarz auf Weiß. Neben der Geometrie wird die Farbe jedes gezeichneten Pixels geprüft.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Die lokalen Unterschiede dieser API stehen bei den Änderungen und Prüfungen vom 2026-10-03.
Gibt die Gesamtkapazität des Befehlspuffers unabhängig von seiner aktuellen Belegung zurück.
Syntax
u8 vram_get_queue_capacity();Rückgabewert
Ein vorzeichenloses Byte in den hier beschriebenen plattformspezifischen Einheiten. Die Abfrage verändert oder verarbeitet die Warteschlange nicht.
Bedingungen und Grenzen
GB zählt Befehlsplätze; die Standardkapazität beträgt 32. Jeder Einfügeaufruf belegt einen Platz, auch bei großen Übertragungen oder Länge null. Setzen Sie VRAM_QUEUE_MAX in allen Übersetzungseinheiten einheitlich auf 1 bis 255. Eine leere Warteschlange hat used=0 und free=capacity.
Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.
Anwendungsbeispiel
capacity=vram_get_queue_capacity();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.
Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.
Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.
Im CGB-Modus sind die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat rot. Das Rechteck von 32 × 24 und die Kopie aus zwei Mustern sind blau. Der Block aus 3 × 2 Kacheln und der Balken von 40 × 8 sind grün. Text bleibt schwarz auf Weiß. Neben der Geometrie wird die Farbe jedes gezeichneten Pixels geprüft.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Gibt Gesamtkapazität minus aktuelle Belegung zurück. Prüfen Sie vor dem Einfügen, ob der nächste Eintrag oder ganze Stapel hineinpasst; diese Abfrage reserviert keinen Platz.
Syntax
u8 vram_get_queue_free();Rückgabewert
Ein vorzeichenloses Byte in den hier beschriebenen plattformspezifischen Einheiten. Die Abfrage verändert oder verarbeitet die Warteschlange nicht.
Bedingungen und Grenzen
GB zählt Befehlsplätze; die Standardkapazität beträgt 32. Jeder Einfügeaufruf belegt einen Platz, auch bei großen Übertragungen oder Länge null. Setzen Sie VRAM_QUEUE_MAX in allen Übersetzungseinheiten einheitlich auf 1 bis 255. Eine leere Warteschlange hat used=0 und free=capacity.
Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.
Anwendungsbeispiel
available=vram_get_queue_free();
if (used+available!=capacity) failures++;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.
Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.
Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.
Im CGB-Modus sind die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat rot. Das Rechteck von 32 × 24 und die Kopie aus zwei Mustern sind blau. Der Block aus 3 × 2 Kacheln und der Balken von 40 × 8 sind grün. Text bleibt schwarz auf Weiß. Neben der Geometrie wird die Farbe jedes gezeichneten Pixels geprüft.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Gibt den von ausstehenden Befehlen belegten Pufferumfang zurück, nicht die Bytezahl der späteren Videodaten.
Syntax
u8 vram_get_queue_used();Rückgabewert
Ein vorzeichenloses Byte in den hier beschriebenen plattformspezifischen Einheiten. Die Abfrage verändert oder verarbeitet die Warteschlange nicht.
Bedingungen und Grenzen
GB zählt Befehlsplätze; die Standardkapazität beträgt 32. Jeder Einfügeaufruf belegt einen Platz, auch bei großen Übertragungen oder Länge null. Setzen Sie VRAM_QUEUE_MAX in allen Übersetzungseinheiten einheitlich auf 1 bis 255. Eine leere Warteschlange hat used=0 und free=capacity.
Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.
Anwendungsbeispiel
used=vram_get_queue_used();Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.
Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.
Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.
Im CGB-Modus sind die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat rot. Das Rechteck von 32 × 24 und die Kopie aus zwei Mustern sind blau. Der Block aus 3 × 2 Kacheln und der Balken von 40 × 8 sind grün. Text bleibt schwarz auf Weiß. Neben der Geometrie wird die Farbe jedes gezeichneten Pixels geprüft.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Initialisiert die Warteschlange für aufgeschobene VRAM-Schreibbefehle als leer und löscht die Überlaufmeldung. Löscht weder den Bildschirm noch lädt es Tile-Grafiken oder reserviert physischen VRAM.
Syntax
void vram_init();Rückgabewert
Keiner (void).
Bedingungen und Grenzen
GB zählt Befehlsplätze; die Standardkapazität beträgt 32. Jeder Einfügeaufruf belegt einen Platz, auch bei großen Übertragungen oder Länge null. Setzen Sie VRAM_QUEUE_MAX in allen Übersetzungseinheiten einheitlich auf 1 bis 255. Eine leere Warteschlange hat used=0 und free=capacity.
Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.
Anwendungsbeispiel
vram_init();
if (vram_get_queue_used()!=0 || vram_get_overflowed()!=0) failures++;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.
Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.
Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.
Im CGB-Modus sind die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat rot. Das Rechteck von 32 × 24 und die Kopie aus zwei Mustern sind blau. Der Block aus 3 × 2 Kacheln und der Balken von 40 × 8 sind grün. Text bleibt schwarz auf Weiß. Neben der Geometrie wird die Farbe jedes gezeichneten Pixels geprüft.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Stellt ein Rechteck aus w × h Tile-Nummern von src für die Karte an base bereit. Quellzeilen enthalten jeweils w direkt aufeinanderfolgende Bytes; Zielzeilen haben 32 Bytes Abstand. Der Quellzeiger bleibt gespeichert, daher ändern spätere Quelldatenänderungen vor der Ausführung den sichtbaren Block.
Syntax
u8 vram_queue_bg_block(u16 base, u8 x, u8 y, u8 w, u8 h, const u8* src);Parameter
baseKachel- und Rechteckbefehle wählen die Hintergrundkarte bei der Ausführung anhand von LCDC-Bit 3. Verwenden Sie auf dem CGB VRAM-Bank 0 für Kachelnummern. Blockübertragungen verwenden die angegebene Basisadresse, normalerweise
0x9800oder0x9C00. Der Zeilenabstand beträgt 32 Bytes; Koordinaten werden nicht automatisch begrenzt.x, yLinke obere Position in 8×8-Tiles, nicht Pixeln. Es erfolgt kein Abschneiden. Halten Sie
x + w <= 32und auf GBy + h <= 32, im Tile-Bereich einer FC-Nametable<= 30ein. Ein einzelnes Tile hat Breite und Höhe 1.w, hBreite und Höhe in Tiles als vorzeichenlose Bytes. Der Quellblock enthält zeilenweise
w * hBytes. Nullabmessungen erzeugen keine sichtbaren Schreibzugriffe; der Platzbedarf folgt dennoch den Plattformregeln.srcNahzeiger auf lesbare Bytes, der bis zur Ausführung gespeichert bleibt. Daten und ihre Speicher- oder ROM-Bank müssen während der gesamten Verarbeitung gültig und eingeblendet bleiben; weder Banknummer noch Kopie werden gespeichert. Nichtleere Übertragungen benötigen eine gültige Quelle. Verwenden Sie kein abgelaufenes lokales Array.
Rückgabewert
1, wenn dieser Befehl eingereiht wurde, oder 0 bei fehlendem Platz. Ein Fehler setzt die Überlaufmeldung und erhält vorhandene Befehle. Ein früherer Überlauf lässt einen später erfolgreichen Eintrag nicht automatisch 0 zurückgeben.
Bedingungen und Grenzen
GB zählt Befehlsplätze; die Standardkapazität beträgt 32. Jeder Einfügeaufruf belegt einen Platz, auch bei großen Übertragungen oder Länge null. Setzen Sie VRAM_QUEUE_MAX in allen Übersetzungseinheiten einheitlich auf 1 bis 255. Eine leere Warteschlange hat used=0 und free=capacity.
Kachel- und Rechteckbefehle wählen die Hintergrundkarte bei der Ausführung anhand von LCDC-Bit 3. Verwenden Sie auf dem CGB VRAM-Bank 0 für Kachelnummern. Blockübertragungen verwenden die angegebene Basisadresse, normalerweise 0x9800 oder 0x9C00. Der Zeilenabstand beträgt 32 Bytes; Koordinaten werden nicht automatisch begrenzt.
Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.
Anwendungsbeispiel
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++;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.
Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.
Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.
Im CGB-Modus sind die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat rot. Das Rechteck von 32 × 24 und die Kopie aus zwei Mustern sind blau. Der Block aus 3 × 2 Kacheln und der Balken von 40 × 8 sind grün. Text bleibt schwarz auf Weiß. Neben der Geometrie wird die Farbe jedes gezeichneten Pixels geprüft.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Stellt ein Hintergrundkartenrechteck aus derselben Tile-Nummer in die Warteschlange. Die linke obere Tile-Position ist (x, y), die Größe w × h Tiles. Ein einfarbiges Tile ergibt ein gefülltes Rechteck; ein gemustertes wiederholt sein Muster in jeder Zelle.
Syntax
u8 vram_queue_bg_rect(u8 x, u8 y, u8 w, u8 h, u8 tile);Parameter
x, yLinke obere Position in 8×8-Tiles, nicht Pixeln. Es erfolgt kein Abschneiden. Halten Sie
x + w <= 32und auf GBy + h <= 32, im Tile-Bereich einer FC-Nametable<= 30ein. Ein einzelnes Tile hat Breite und Höhe 1.w, hBreite und Höhe in Tiles als vorzeichenlose Bytes. Der Quellblock enthält zeilenweise
w * hBytes. Nullabmessungen erzeugen keine sichtbaren Schreibzugriffe; der Platzbedarf folgt dennoch den Plattformregeln.tileTile-Kartenbyte von 0 bis 255. Laden Sie die Grafik separat und wählen Sie die passende Mustertabelle beziehungsweise Adressierungsart. Eine Tile-Nummer ist weder Zeiger noch Farbwert.
Rückgabewert
1, wenn dieser Befehl eingereiht wurde, oder 0 bei fehlendem Platz. Ein Fehler setzt die Überlaufmeldung und erhält vorhandene Befehle. Ein früherer Überlauf lässt einen später erfolgreichen Eintrag nicht automatisch 0 zurückgeben.
Bedingungen und Grenzen
GB zählt Befehlsplätze; die Standardkapazität beträgt 32. Jeder Einfügeaufruf belegt einen Platz, auch bei großen Übertragungen oder Länge null. Setzen Sie VRAM_QUEUE_MAX in allen Übersetzungseinheiten einheitlich auf 1 bis 255. Eine leere Warteschlange hat used=0 und free=capacity.
Kachel- und Rechteckbefehle wählen die Hintergrundkarte bei der Ausführung anhand von LCDC-Bit 3. Verwenden Sie auf dem CGB VRAM-Bank 0 für Kachelnummern. Blockübertragungen verwenden die angegebene Basisadresse, normalerweise 0x9800 oder 0x9C00. Der Zeilenabstand beträgt 32 Bytes; Koordinaten werden nicht automatisch begrenzt.
Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.
Anwendungsbeispiel
check_result=vram_queue_bg_rect(2,4,4,3,1); // A filled 32x24 rectangle at (16,32).
if (check_result!=1) failures++;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.
Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.
Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.
Im CGB-Modus sind die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat rot. Das Rechteck von 32 × 24 und die Kopie aus zwei Mustern sind blau. Der Block aus 3 × 2 Kacheln und der Balken von 40 × 8 sind grün. Text bleibt schwarz auf Weiß. Neben der Geometrie wird die Farbe jedes gezeichneten Pixels geprüft.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Stellt einen Schreibbefehl für eine Hintergrund-Tile-Nummer an (x, y) in die Warteschlange. Sichtbar wird die Änderung bei deren Ausführung. Geschrieben wird ein Karteneintrag, weder Pixeldaten noch Palettenattribute.
Syntax
u8 vram_queue_bg_tile(u8 x, u8 y, u8 tile);Parameter
x, yLinke obere Position in 8×8-Tiles, nicht Pixeln. Es erfolgt kein Abschneiden. Halten Sie
x + w <= 32und auf GBy + h <= 32, im Tile-Bereich einer FC-Nametable<= 30ein. Ein einzelnes Tile hat Breite und Höhe 1.tileTile-Kartenbyte von 0 bis 255. Laden Sie die Grafik separat und wählen Sie die passende Mustertabelle beziehungsweise Adressierungsart. Eine Tile-Nummer ist weder Zeiger noch Farbwert.
Rückgabewert
1, wenn dieser Befehl eingereiht wurde, oder 0 bei fehlendem Platz. Ein Fehler setzt die Überlaufmeldung und erhält vorhandene Befehle. Ein früherer Überlauf lässt einen später erfolgreichen Eintrag nicht automatisch 0 zurückgeben.
Bedingungen und Grenzen
GB zählt Befehlsplätze; die Standardkapazität beträgt 32. Jeder Einfügeaufruf belegt einen Platz, auch bei großen Übertragungen oder Länge null. Setzen Sie VRAM_QUEUE_MAX in allen Übersetzungseinheiten einheitlich auf 1 bis 255. Eine leere Warteschlange hat used=0 und free=capacity.
Kachel- und Rechteckbefehle wählen die Hintergrundkarte bei der Ausführung anhand von LCDC-Bit 3. Verwenden Sie auf dem CGB VRAM-Bank 0 für Kachelnummern. Blockübertragungen verwenden die angegebene Basisadresse, normalerweise 0x9800 oder 0x9C00. Der Zeilenabstand beträgt 32 Bytes; Koordinaten werden nicht automatisch begrenzt.
Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.
Anwendungsbeispiel
check_result=vram_queue_bg_tile(2,2,1); // A solid 8x8 tile at pixel (16,16).
if (check_result!=1) failures++;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.
Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.
Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.
Im CGB-Modus sind die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat rot. Das Rechteck von 32 × 24 und die Kopie aus zwei Mustern sind blau. Der Block aus 3 × 2 Kacheln und der Balken von 40 × 8 sind grün. Text bleibt schwarz auf Weiß. Neben der Geometrie wird die Farbe jedes gezeichneten Pixels geprüft.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Stellt eine Kopie von len aufeinanderfolgenden Bytes von src nach dst bereit. Beide Adressen steigen byteweise ohne Tile-Zeilensprung. Übertragbar sind Kartenbytes oder beschreibbare Musterdaten; Formate werden nicht umgewandelt und die Bytezahl eines Tiles wird nicht ermittelt.
Syntax
u8 vram_queue_memcpy(u16 dst, const void* src, u16 len);Parameter
dstZieladresse in Bytes im VRAM (
0x8000–0x9FFF), in der bei der Ausführung gewählten Bank. Die Übertragung ist fortlaufend, ohne Zeilenumbruch. Der gesamte Zielbereich muss gültig sein. Bei eingeschaltetem LCD können die sicheren Schreibpfade Interrupts einschalten; ein beim Aufruf gesperrter Interruptzustand bleibt nicht erhalten.srcNahzeiger auf lesbare Bytes, der bis zur Ausführung gespeichert bleibt. Daten und ihre Speicher- oder ROM-Bank müssen während der gesamten Verarbeitung gültig und eingeblendet bleiben; weder Banknummer noch Kopie werden gespeichert. Nichtleere Übertragungen benötigen eine gültige Quelle. Verwenden Sie kein abgelaufenes lokales Array.
lenAnzahl aufeinanderfolgender Bytes von 0 bis 65535, keine Tile-Anzahl. Der gesamte Bereich muss in gültiger Quelle und beschreibbarem Ziel liegen; die API prüft keine Grenzen und verhindert keinen 16-Bit-Adressüberlauf.
Rückgabewert
1, wenn dieser Befehl eingereiht wurde, oder 0 bei fehlendem Platz. Ein Fehler setzt die Überlaufmeldung und erhält vorhandene Befehle. Ein früherer Überlauf lässt einen später erfolgreichen Eintrag nicht automatisch 0 zurückgeben.
Bedingungen und Grenzen
GB zählt Befehlsplätze; die Standardkapazität beträgt 32. Jeder Einfügeaufruf belegt einen Platz, auch bei großen Übertragungen oder Länge null. Setzen Sie VRAM_QUEUE_MAX in allen Übersetzungseinheiten einheitlich auf 1 bis 255. Eine leere Warteschlange hat used=0 und free=capacity.
Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.
Anwendungsbeispiel
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.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.
Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.
Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.
Im CGB-Modus sind die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat rot. Das Rechteck von 32 × 24 und die Kopie aus zwei Mustern sind blau. Der Block aus 3 × 2 Kacheln und der Balken von 40 × 8 sind grün. Text bleibt schwarz auf Weiß. Neben der Geometrie wird die Farbe jedes gezeichneten Pixels geprüft.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Stellt das Füllen von len aufeinanderfolgenden Bytes ab dst mit dem Byte value bereit. Wiederholt wird ein Byte, kein mehrteiliges Tile-Muster; ein Kartenzeilenabstand von 32 Bytes wird nicht eingefügt.
Syntax
u8 vram_queue_memset(u16 dst, u8 value, u16 len);Parameter
dstZieladresse in Bytes im VRAM (
0x8000–0x9FFF), in der bei der Ausführung gewählten Bank. Die Übertragung ist fortlaufend, ohne Zeilenumbruch. Der gesamte Zielbereich muss gültig sein. Bei eingeschaltetem LCD können die sicheren Schreibpfade Interrupts einschalten; ein beim Aufruf gesperrter Interruptzustand bleibt nicht erhalten.valueEin wiederholtes Byte von 0 bis 255. Seine sichtbare Wirkung hängt davon ab, ob das Ziel Tile-Indizes, Pixelebenen oder eine andere Bytestruktur enthält.
lenAnzahl aufeinanderfolgender Bytes von 0 bis 65535, keine Tile-Anzahl. Der gesamte Bereich muss in gültiger Quelle und beschreibbarem Ziel liegen; die API prüft keine Grenzen und verhindert keinen 16-Bit-Adressüberlauf.
Rückgabewert
1, wenn dieser Befehl eingereiht wurde, oder 0 bei fehlendem Platz. Ein Fehler setzt die Überlaufmeldung und erhält vorhandene Befehle. Ein früherer Überlauf lässt einen später erfolgreichen Eintrag nicht automatisch 0 zurückgeben.
Bedingungen und Grenzen
GB zählt Befehlsplätze; die Standardkapazität beträgt 32. Jeder Einfügeaufruf belegt einen Platz, auch bei großen Übertragungen oder Länge null. Setzen Sie VRAM_QUEUE_MAX in allen Übersetzungseinheiten einheitlich auf 1 bis 255. Eine leere Warteschlange hat used=0 und free=capacity.
Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.
Anwendungsbeispiel
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.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.
Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.
Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.
Im CGB-Modus sind die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat rot. Das Rechteck von 32 × 24 und die Kopie aus zwei Mustern sind blau. Der Block aus 3 × 2 Kacheln und der Balken von 40 × 8 sind grün. Text bleibt schwarz auf Weiß. Neben der Geometrie wird die Farbe jedes gezeichneten Pixels geprüft.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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 ruft vram_queue_bg_tile direkt mit denselben Argumenten auf und gibt dessen Ergebnis zurück. Der Kurzname schreibt einen Hintergrundkarteneintrag; er bearbeitet keine Sprites und lädt keine Tile-Grafiken.
Syntax
u8 vram_queue_tile(u8 x, u8 y, u8 tile);Parameter
x, yLinke obere Position in 8×8-Tiles, nicht Pixeln. Es erfolgt kein Abschneiden. Halten Sie
x + w <= 32und auf GBy + h <= 32, im Tile-Bereich einer FC-Nametable<= 30ein. Ein einzelnes Tile hat Breite und Höhe 1.tileTile-Kartenbyte von 0 bis 255. Laden Sie die Grafik separat und wählen Sie die passende Mustertabelle beziehungsweise Adressierungsart. Eine Tile-Nummer ist weder Zeiger noch Farbwert.
Rückgabewert
1, wenn dieser Befehl eingereiht wurde, oder 0 bei fehlendem Platz. Ein Fehler setzt die Überlaufmeldung und erhält vorhandene Befehle. Ein früherer Überlauf lässt einen später erfolgreichen Eintrag nicht automatisch 0 zurückgeben.
Bedingungen und Grenzen
GB zählt Befehlsplätze; die Standardkapazität beträgt 32. Jeder Einfügeaufruf belegt einen Platz, auch bei großen Übertragungen oder Länge null. Setzen Sie VRAM_QUEUE_MAX in allen Übersetzungseinheiten einheitlich auf 1 bis 255. Eine leere Warteschlange hat used=0 und free=capacity.
Kachel- und Rechteckbefehle wählen die Hintergrundkarte bei der Ausführung anhand von LCDC-Bit 3. Verwenden Sie auf dem CGB VRAM-Bank 0 für Kachelnummern. Blockübertragungen verwenden die angegebene Basisadresse, normalerweise 0x9800 oder 0x9C00. Der Zeilenabstand beträgt 32 Bytes; Koordinaten werden nicht automatisch begrenzt.
Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.
Anwendungsbeispiel
check_result=vram_queue_tile(4,2,1); // The short alias draws at pixel (32,16).
if (check_result!=1) failures++;Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.
Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.
Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.
Im CGB-Modus sind die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat rot. Das Rechteck von 32 × 24 und die Kopie aus zwei Mustern sind blau. Der Block aus 3 × 2 Kacheln und der Balken von 40 × 8 sind grün. Text bleibt schwarz auf Weiß. Neben der Geometrie wird die Farbe jedes gezeichneten Pixels geprüft.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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 ruft direkt vram_queue_memcpy auf. len zählt weiterhin Bytes statt Tiles. Quellzeiger, Warteschlangeneinträge, Rückgabewert und Ausführungszeitpunkt sind identisch.
Syntax
u8 vram_queue_tiles(u16 dst, const void* src, u16 len);Parameter
dstZieladresse in Bytes im VRAM (
0x8000–0x9FFF), in der bei der Ausführung gewählten Bank. Die Übertragung ist fortlaufend, ohne Zeilenumbruch. Der gesamte Zielbereich muss gültig sein. Bei eingeschaltetem LCD können die sicheren Schreibpfade Interrupts einschalten; ein beim Aufruf gesperrter Interruptzustand bleibt nicht erhalten.srcNahzeiger auf lesbare Bytes, der bis zur Ausführung gespeichert bleibt. Daten und ihre Speicher- oder ROM-Bank müssen während der gesamten Verarbeitung gültig und eingeblendet bleiben; weder Banknummer noch Kopie werden gespeichert. Nichtleere Übertragungen benötigen eine gültige Quelle. Verwenden Sie kein abgelaufenes lokales Array.
lenAnzahl aufeinanderfolgender Bytes von 0 bis 65535, keine Tile-Anzahl. Der gesamte Bereich muss in gültiger Quelle und beschreibbarem Ziel liegen; die API prüft keine Grenzen und verhindert keinen 16-Bit-Adressüberlauf.
Rückgabewert
1, wenn dieser Befehl eingereiht wurde, oder 0 bei fehlendem Platz. Ein Fehler setzt die Überlaufmeldung und erhält vorhandene Befehle. Ein früherer Überlauf lässt einen später erfolgreichen Eintrag nicht automatisch 0 zurückgeben.
Bedingungen und Grenzen
GB zählt Befehlsplätze; die Standardkapazität beträgt 32. Jeder Einfügeaufruf belegt einen Platz, auch bei großen Übertragungen oder Länge null. Setzen Sie VRAM_QUEUE_MAX in allen Übersetzungseinheiten einheitlich auf 1 bis 255. Eine leere Warteschlange hat used=0 und free=capacity.
Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.
Anwendungsbeispiel
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.Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.
Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.
Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.
Im CGB-Modus sind die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat rot. Das Rechteck von 32 × 24 und die Kopie aus zwei Mustern sind blau. Der Block aus 3 × 2 Kacheln und der Balken von 40 × 8 sind grün. Text bleibt schwarz auf Weiß. Neben der Geometrie wird die Farbe jedes gezeichneten Pixels geprüft.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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 — Drahtgitterdarstellung für DMG
Monochromes 3D-Linienzeichnen. Übergeben Sie Modelleckpunkte, Kanten und Flächen sowie Objektposition, Rotation und Skalierung. Verwenden Sie Initialisierung, Frame-Beginn, Zeichnen und Übertragung in dieser Reihenfolge. Physik ist getrennt. Winkel haben sechzehn Schritte pro Umdrehung; Modellskalierung 256 bedeutet Originalgröße.
Vec3 enthält x/y/z, Edge die Eckpunktindizes a/b und Face die Dreiecksindizes a/b/c. vertices, edges und faces in Model zeigen auf diese Arrays; die jeweilige Anzahl gibt ihre Länge an. edge_faces enthält die Nachbarflächenindizes f0/f1, bei fehlender Fläche FACE_NONE. MODEL_HIDDEN_LINES in flags fordert flächenbasierte Kantenauswahl an. Die vorzeichenbehaftete projizierte Fläche bestimmt die Ausrichtung; die Eckpunktreihenfolge ist daher wichtig.
Object speichert Modellreferenz, Position x/y/z, Winkel rx/ry/rz, scale_q8 und visible. Objekte können ein Modell teilen; Zeichnen kopiert aber keine Tabellen und schaltet deren ROM-Bänke nicht automatisch um. Referenzierte Daten müssen während des gesamten Zeichnens lesbar bleiben. CGB-Object besitzt zusätzlich einen Farbindex.
Model für Höhe 96 enthält außerdem edge_masks und edge_mask_count. Übergeben Sie eine RAM-Tabelle mit 16-Bit-Kantenmasken, die nach Objekt-Gierwinkel gewählt werden, oder setzen Sie beide Felder bei Nichtgebrauch auf null.
Wire3D_BeginFrame
Beginnt das Zeichnen eines Frames und deaktiviert die Verdeckungsprüfung.
Syntax
void Wire3D_BeginFrame();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96. Löscht vorbereitete Pixel und Verdeckungsmaske und deaktiviert die Verdeckungsfilterung. Angezeigter VRAM-Frame und ausstehende BG-Tile-Warteschlange bleiben unverändert.
Dieses Beispiel verwendet das 128×96-Profil; sein Viewport beginnt auf dem Bildschirm bei (0,0). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet eine vierfach zusammenhängende Bildschirmlinie einschließlich Endpunkten in den Staging-Bereich.
Syntax
void Wire3D_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by);Parameter
axX-Koordinate von Eckpunkt A in Viewport-Pixeln.
ayY-Koordinate von Eckpunkt A in Viewport-Pixeln.
bxX-Koordinate von Eckpunkt B in Viewport-Pixeln.
byY-Koordinate von Eckpunkt B in Viewport-Pixeln.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96. Zeichnet eine zusammenhängende Linie einschließlich Endpunkten in den 128×96-Staging-Bereich. Während DrawScene wird die grobe Verdeckungsverwerfung mit fünf Abtastpunkten verwendet, sonst direkt gezeichnet. Verwenden Sie Viewport-Koordinaten. Nur EndFrame aktualisiert VRAM.
Dieses Beispiel verwendet das 128×96-Profil; sein Viewport beginnt auf dem Bildschirm bei (0,0). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Projiziert zwei Weltendpunkte und zeichnet eine Linie dazwischen.
Syntax
void Wire3D_DrawLine3D(w3ddmg_i16 ax, w3ddmg_i16 ay, w3ddmg_i16 az, w3ddmg_i16 bx, w3ddmg_i16 by, w3ddmg_i16 bz);Parameter
axX-Komponente des Startpunkts in Weltkoordinaten.
ayY-Komponente des Startpunkts in Weltkoordinaten.
azZ-Komponente des Startpunkts in Weltkoordinaten.
bxX-Komponente des Endpunkts in Weltkoordinaten.
byY-Komponente des Endpunkts in Weltkoordinaten.
bzZ-Komponente des Endpunkts in Weltkoordinaten.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96. Projiziert beide Weltendpunkte und zeichnet nur, wenn beide den Tiefenbereich bestehen. Bildet keine Schnittpunkte eines kreuzenden Segments mit Nah- oder Fernebene; projizierte Endpunkte werden einzeln auf die Bildschirmränder begrenzt.
Dieses Beispiel verwendet das 128×96-Profil; sein Viewport beginnt auf dem Bildschirm bei (0,0). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet ein Eckpunkt-Kanten-Modell an der gewünschten Position und mit der gewünschten Rotation in Originalgröße.
Syntax
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);Parameter
modelModell mit Arrays und Anzahlen für Eckpunkte, Kanten und Flächen; seine Tabellen müssen während des Aufrufs lesbar bleiben.
xX-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
yY-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
zZ-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
rxDrehung um X; sechzehn Schritte ergeben eine volle Umdrehung.
ryDrehung um Y; sechzehn Schritte ergeben eine volle Umdrehung.
rzDrehung um Z; sechzehn Schritte ergeben eine volle Umdrehung.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96. Zeichnet ein unskaliertes Modell, indem DrawModelScaled mit Skalierung 256 aufgerufen wird.
Dieses Beispiel verwendet das 128×96-Profil; sein Viewport beginnt auf dem Bildschirm bei (0,0). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Modelle in Originalgröße und halber Größe erscheinen über einer Szene aus einem Objektarray mit denselben Skalierungen und zeigen Projektion und Skalierung.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Skaliert ein Modell, dreht es in Y/X/Z-Reihenfolge, verschiebt und projiziert seine Eckpunkte und zeichnet die Kanten.
Syntax
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);Parameter
modelModell mit Arrays und Anzahlen für Eckpunkte, Kanten und Flächen; seine Tabellen müssen während des Aufrufs lesbar bleiben.
xX-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
yY-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
zZ-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
rxDrehung um X; sechzehn Schritte ergeben eine volle Umdrehung.
ryDrehung um Y; sechzehn Schritte ergeben eine volle Umdrehung.
rzDrehung um Z; sechzehn Schritte ergeben eine volle Umdrehung.
scale_q8Skalierung mit 256 als Einheit; nichtpositive Werte bedeuten ebenfalls Originalgröße.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96. Skaliert bis zu 24 Eckpunkte, dreht sie in Y/X/Z-Reihenfolge, verschiebt und projiziert sie; zeichnet danach bis zu 16 Kanten, gefiltert durch Giermasken und optional nach vorn gerichtete Flächen. Nichtpositive Skalierung wird zur Einheit (256). Nullzeiger für Modell, Eckpunkte oder Kanten werden ignoriert; referenzierte Tabellen müssen lesbar bleiben. Skalierungsprodukte und Verschiebungen müssen in den vorzeichenbehafteten 16-Bit-Bereich passen. Kanten über Tiefengrenzen werden verworfen, nicht zugeschnitten.
Dieses Beispiel verwendet das 128×96-Profil; sein Viewport beginnt auf dem Bildschirm bei (0,0). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Modelle in Originalgröße und halber Größe erscheinen über einer Szene aus einem Objektarray mit denselben Skalierungen und zeigen Projektion und Skalierung.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet bis zu acht Objekte von nah nach fern; nähere Flächen verdecken spätere Kanten.
Syntax
void Wire3D_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count);Parameter
objectsObjektarray mit Positionen, Rotationen, Skalierungen und Sichtbarkeitsflags.
countAnzahl der übergebenen Arrayeinträge; beachten Sie die Verarbeitungsgrenze der jeweiligen Operation.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96. Verarbeitet höchstens die ersten acht Objekte, nach transformierter Ursprungstiefe von nah nach fern sortiert. Zeichnet sichtbare gültige Modelle und markiert anschließend die Begrenzungsrechtecke ihrer Vorderseiten, um spätere Linien zu verwerfen, deren sämtliche Abtastpunkte verdeckt sind. Dies nähert Verdeckung zwischen Objekten an und ist kein Tiefenpuffer. Löscht die eigene Maske, erhält aber vorhandene Staging-Pixel. Nullarrays werden ignoriert; Objekte und Daten müssen lesbar bleiben.
Dieses Beispiel verwendet das 128×96-Profil; sein Viewport beginnt auf dem Bildschirm bei (0,0). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Modelle in Originalgröße und halber Größe erscheinen über einer Szene aus einem Objektarray mit denselben Skalierungen und zeigen Projektion und Skalierung.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Übergibt ausstehende Hintergrund-Schreibzugriffe und vorbereitete Zeichnungen an VRAM.
Syntax
void Wire3D_EndFrame();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96. Wartet auf den nächsten VBlank, führt ausstehende BG-Kartenschreibzugriffe aus und kopiert Staging unter Abfrage der Zugriffsfenster ins VRAM. Das Kopieren verbraucht die vorbereiteten Pixel. Die Übertragung kann über VBlank hinausgehen; dies ist kein atomarer Frame-Wechsel.
Dieses Beispiel verwendet das 128×96-Profil; sein Viewport beginnt auf dem Bildschirm bei (0,0). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Projiziert nach vorn gerichtete Modelldreiecke und löscht vorbereitete Pixel in ihrem Inneren.
Syntax
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);Parameter
modelModell mit Arrays und Anzahlen für Eckpunkte, Kanten und Flächen; seine Tabellen müssen während des Aufrufs lesbar bleiben.
xX-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
yY-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
zZ-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
rxDrehung um X; sechzehn Schritte ergeben eine volle Umdrehung.
ryDrehung um Y; sechzehn Schritte ergeben eine volle Umdrehung.
rzDrehung um Z; sechzehn Schritte ergeben eine volle Umdrehung.
scale_q8Skalierung mit 256 als Einheit; nichtpositive Werte bedeuten ebenfalls Originalgröße.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96. Projiziert bis zu 24 Eckpunkte und löscht das Innere nach vorn gerichteter Dreiecke aus dem Staging-Bereich für ein Modell mit Verdeckungsflags und Flächendaten. Nichtpositive Skalierung bedeutet 256, also Originalgröße. Bis zu 16 Flächen werden betrachtet; Flächen über Tiefengrenzen werden übersprungen. Ersetzt auch gemeinsame Projektionscaches, aktualisiert aber kein VRAM.
Dieses Beispiel verwendet das 128×96-Profil; sein Viewport beginnt auf dem Bildschirm bei (0,0). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Projizierte Flächen löschen einen gefüllten Bereich, sodass erhaltene und gelöschte Bereiche sichtbar werden.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Löscht einen waagerechten Span einschließlich Endpunkten in einer vorbereiteten Zeile.
Syntax
void Wire3D_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1);Parameter
yPixel-Y-Koordinate der zu löschenden Zeile.
x0Unterer X-Endpunkt in Viewport-Pixeln; Reihenfolge und Begrenzung richten sich nach den Hinweisen zu dieser Operation.
x1Oberer X-Endpunkt in Viewport-Pixeln; Reihenfolge und Begrenzung richten sich nach den Hinweisen zu dieser Operation.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96. Ordnet die X-Endpunkte und löscht den vorbereiteten Span einschließlich Endpunkten. Beide müssen in 0..127 liegen; ungültiges Y wird ignoriert. Die Routine begrenzt X nicht automatisch.
Dieses Beispiel verwendet das 128×96-Profil; sein Viewport beginnt auf dem Bildschirm bei (0,0). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Löscht ein Bildschirmdreieck über waagerechte Rasterzeilen-Spans aus dem Staging-Bereich.
Syntax
void Wire3D_EraseTriangle2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by, w3ddmg_u8 cx, w3ddmg_u8 cy);Parameter
axX-Koordinate von Eckpunkt A in Viewport-Pixeln.
ayY-Koordinate von Eckpunkt A in Viewport-Pixeln.
bxX-Koordinate von Eckpunkt B in Viewport-Pixeln.
byY-Koordinate von Eckpunkt B in Viewport-Pixeln.
cxX-Koordinate von Eckpunkt C in Viewport-Pixeln.
cyY-Koordinate von Eckpunkt C in Viewport-Pixeln.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96. Löscht ein Dreieck aus vorbereiteten Pixeln über ganzzahlige Rasterzeilenschnittpunkte. Geben Sie Viewport-Koordinaten an. Entartete Dreiecke werden ignoriert; Verdeckungsmaske und VRAM bleiben unverändert.
Dieses Beispiel verwendet das 128×96-Profil; sein Viewport beginnt auf dem Bildschirm bei (0,0). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Projizierte Flächen löschen einen gefüllten Bereich, sodass erhaltene und gelöschte Bereiche sichtbar werden.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Initialisiert LCD, Tiles und Hintergrundkarte für einen monochromen Drahtgitter-Viewport.
Syntax
void Wire3D_Init();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96. Übernimmt das LCD: Wartet auf VBlank, schaltet es aus, löscht 6144 Tile-Bytes und die BG-Karte, richtet HUD-Tiles und den 128×96-Viewport mit vorzeichenbehafteten Tile-Nummern ein und aktiviert BG mit Scrollwerten null und BGP=0xB4. Setzt Kamera, BG-Warteschlange und Staging-Bereich zurück. Reservieren Sie 0xD000..0xDFFF für Staging und erhalten Sie dessen WRAM-Bankeinblendung. Rufen Sie vor dem Zeichnen BeginFrame auf, um auch den Verdeckungszustand zu initialisieren.
Dieses Beispiel verwendet das 128×96-Profil; sein Viewport beginnt auf dem Bildschirm bei (0,0). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Projiziert einen Weltpunkt durch die Kamera in Viewport-Koordinaten.
Syntax
w3ddmg_u8 Wire3D_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy);Parameter
xX-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
yY-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
zZ-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
sxGültiger beschreibbarer u8-Zeiger für die projizierte X-Koordinate.
syGültiger beschreibbarer u8-Zeiger für die projizierte Y-Koordinate.
Rückgabewert
Liefert 1 bei erfolgreicher Projektion oder 0 bei verworfener Tiefe.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96. Projiziert einen Weltpunkt mit der aktuellen Kamera. Verworfene Tiefe liefert null und lässt die Ausgabe unverändert; bei Erfolg werden auf 128×96 begrenzte Koordinaten geschrieben. Ausgabezeiger müssen gültig sein. Bildschirmbegrenzung ist kein geometrisches Clipping.
Dieses Beispiel verwendet das 128×96-Profil; sein Viewport beginnt auf dem Bildschirm bei (0,0). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Reiht einen Tile-Nummer-Schreibzugriff für eine Hintergrundkartenzelle ein.
Syntax
void Wire3D_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile);Parameter
xX-Tile-Koordinate in der 32×32-Hintergrundkarte.
yY-Tile-Koordinate in der 32×32-Hintergrundkarte.
tileAcht-Bit-Tile-Nummer für die Hintergrundzelle.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96. Reiht einen Tile-Schreibzugriff auf die 32×32-Karte bei 0x9800 für EndFrame ein. Ungültige Kartenkoordinaten und Anfragen über 48 ausstehende Schreibzugriffe hinaus werden ohne Meldung ignoriert. Diese Warteschlange ist von der allgemeinen vram-Bibliothekswarteschlange getrennt.
Dieses Beispiel verwendet das 128×96-Profil; sein Viewport beginnt auf dem Bildschirm bei (0,0). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Wählt eine vorberechnete Kantensichtbarkeitsmaske für den Gierwinkel des Objekts.
Syntax
w3ddmg_u16 Wire3D_SelectEdgeMask(const Wire3DDMG_Model* model, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz);Parameter
modelModell mit Arrays und Anzahlen für Eckpunkte, Kanten und Flächen; seine Tabellen müssen während des Aufrufs lesbar bleiben.
rxDrehung um X; sechzehn Schritte ergeben eine volle Umdrehung.
ryDrehung um Y; sechzehn Schritte ergeben eine volle Umdrehung.
rzDrehung um Z; sechzehn Schritte ergeben eine volle Umdrehung.
Rückgabewert
16-Bit-Kantensichtbarkeitsmaske oder 0xFFFF, wenn keine Tabelle übergeben wurde.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96. Wählt eine vorberechnete Maske aus den unteren vier Bits des Objekt-Gierwinkels; Nicken, Rollen und Kameraausrichtung werden ignoriert. Verwenden Sie 16, 8, 4 oder 2 Bereiche; andere positive Anzahlen wählen Eintrag null, wobei Anzahlen >=16 die ersten 16 verwenden. Fehlende Daten liefern 0xFFFF. Die Maskentabelle muss über die aktuelle Datenzeigereinblendung lesbar bleiben.
Dieses Beispiel verwendet das 128×96-Profil; sein Viewport beginnt auf dem Bildschirm bei (0,0). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Modelle in Originalgröße und halber Größe erscheinen über einer Szene aus einem Objektarray mit denselben Skalierungen und zeigen Projektion und Skalierung.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Speichert Kameraposition und -ausrichtung für spätere Projektionen.
Syntax
void Wire3D_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 pitch, w3ddmg_i8 yaw, w3ddmg_i8 roll);Parameter
xX-Komponente der Kamera in Weltkoordinaten.
yY-Komponente der Kamera in Weltkoordinaten.
zZ-Komponente der Kamera in Weltkoordinaten.
pitchDrehung um X; sechzehn Schritte ergeben eine volle Umdrehung.
yawDrehung um Y; sechzehn Schritte ergeben eine volle Umdrehung.
rollDrehung um Z; sechzehn Schritte ergeben eine volle Umdrehung.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96. Speichert Kameraposition und -winkel für späteres Zeichnen; 16 Winkelschritte ergeben eine Umdrehung. Vorhandene Zeichnungen werden nicht neu projiziert und Eingabebereiche nicht geprüft.
Dieses Beispiel verwendet das 128×96-Profil; sein Viewport beginnt auf dem Bildschirm bei (0,0). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Schreibt die Zuordnung der vier Helligkeitsstufen ins monochrome Hintergrund-Palettenregister BGP.
Syntax
void Wire3D_SetPalette(w3ddmg_u8 bgp);Parameter
bgpBGP-Registerwert mit vier Zwei-Bit-Helligkeitszuordnungen.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96. Schreibt die rohe DMG-BGP-Palettencodierung sofort, ohne Frame-Synchronisierung.
Dieses Beispiel verwendet das 128×96-Profil; sein Viewport beginnt auf dem Bildschirm bei (0,0). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.


Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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 — Farbige Drahtgitterdarstellung für CGB
Verwendung der schnellen Renderingpfade
Der normale 128×96-Renderer schreibt Zeichenadressen schrittweise fort. Für unverdeckte Linien wählt er die Farbebene einmal pro Linie und hält Pixelzahl und Fehlerwert in CPU-Registern. Auch verdeckte Linien wählen die Farbebenen nur einmal pro Linie; Zeichen- und Maskenadressen werden gemeinsam schrittweise fortgeschrieben. Jedes Pixel prüft sein Maskenbit und wird nur geschrieben, wenn es nicht verdeckt ist. Der 160×144-Renderer und FastMap besitzen eigene Pfade. Drehungen um 0, 90, 180 und 270 Grad begrenzen zuerst die Eingaben und verwenden anschließend Koordinatentausch und Vorzeichenwechsel. Die Gesamtleistung hängt auch von Eckpunktzahl, Kantenlänge, Verdeckung und VRAM-Übertragungen ab. Messen Sie einzelne Operationen getrennt von der Zeit bis zum fertigen angezeigten Bild.
Farbige Drahtgitter für CGB. Der 128×96-Pixelrenderer, der 160×144-Tile-Allokator und FastMap mit Umriss-Tiles verwenden unterschiedliche Initialisierungs- und Übertragungsabläufe. Modelleckpunkte, Kanten und Dreiecksflächen gehören dem Aufrufer. Dieses Modul simuliert keine Physik.
Vec3 enthält x/y/z, Edge die Eckpunktindizes a/b und Face die Dreiecksindizes a/b/c. vertices, edges und faces in Model zeigen auf diese Arrays; die jeweilige Anzahl gibt ihre Länge an. edge_faces enthält die Nachbarflächenindizes f0/f1, bei fehlender Fläche FACE_NONE. MODEL_HIDDEN_LINES in flags fordert flächenbasierte Kantenauswahl an. Die vorzeichenbehaftete projizierte Fläche bestimmt die Ausrichtung; die Eckpunktreihenfolge ist daher wichtig.
Object speichert Modellreferenz, Position x/y/z, Winkel rx/ry/rz, scale_q8 und visible. Objekte können ein Modell teilen; Zeichnen kopiert aber keine Tabellen und schaltet deren ROM-Bänke nicht automatisch um. Referenzierte Daten müssen während des gesamten Zeichnens lesbar bleiben. CGB-Object besitzt zusätzlich einen Farbindex.
FastCube-x/y sind Versätze zur Bildschirmmitte; z wählt Größe oder Zeichenreihenfolge. FastCubes ignoriert Winkel, während FastCubeFrame mit rx/ry/rz vier Stempelvarianten wählt. Diese vereinfachten Anzeigen dienen anderen Zwecken als das kameraprojizierte DrawModel.
Wire3DCGB_BeginFrame
Beginnt einen neuen leeren Frame im gewählten Rendermodus.
Syntax
void Wire3DCGB_BeginFrame();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Wählt im normalen Modus die vollständige Staging-Übertragung, löscht alle vorbereiteten Pixel und die Bitmap-Maske, setzt Maskengrenzen zurück und deaktiviert Verdeckung. Im Vollbildmodus werden stattdessen dessen Allokator und Spans zurückgesetzt. Ausstehende BG-Schreibzugriffe bleiben in der Warteschlange. Erfordert einen Build mit vollständiger Laufzeitumgebung.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Beim CGB-Sparse-Start aktualisiert die erste Nutzung jeder Zielbank (die ersten zwei Bilder) den gesamten Ausschnitt und entfernt Initialisierungskacheln. Diese Startkosten sind enthalten. DrawLine2D erfasst keine Sparse-Bereiche: DrawLineClipped2D oder ausdrücklich MarkDirtyRect2D verwenden.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt einfache Linien, Punkte, Löschen und Projektion in einem Frame. Ein roter Rahmen enthält eine blaue Diagonale, einen grünen Punkt und eine grüne waagerechte Linie, ein blaues L sowie eine grüne Null oben rechts.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Beginnt einen gelöschten Frame und macht die bisherigen partiellen Bereiche ungültig, indem sie auf den gesamten Viewport erweitert werden.
Syntax
void Wire3DCGB_BeginFrameFast();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Führt denselben Frame-Reset für normalen oder Vollbildmodus wie BeginFrame aus, markiert aber zuerst beide bisherigen partiellen Verlaufsbereiche als den gesamten Viewport mit 192 Tiles. So verlässt sich eine spätere partielle Übertragung nicht auf veraltete Bankinhalte.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Beim CGB-Sparse-Start aktualisiert die erste Nutzung jeder Zielbank (die ersten zwei Bilder) den gesamten Ausschnitt und entfernt Initialisierungskacheln. Diese Startkosten sind enthalten. DrawLine2D erfasst keine Sparse-Bereiche: DrawLineClipped2D oder ausdrücklich MarkDirtyRect2D verwenden.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Die zuvor gezeichneten roten und blauen Rahmen verschwinden; nur der letzte grüne Rahmen bei (80,8)..(112,32) bleibt. Dies zeigt partielle Übertragung und Verlaufsverwaltung.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Beginnt einen Frame für partielle Bereichsübertragung.
Syntax
void Wire3DCGB_BeginFrameSparse();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Wählt partielle Übertragung und löscht den gesamten 128×96-Staging-Bereich, damit beim Vergrößern des Änderungsbereichs keine alten Pixel erscheinen. Setzt Maskengrenzen zurück und deaktiviert Verdeckung; PAINTER_ONLY-Builds überspringen das Löschen der ungenutzten Bitmap-Maske. Der Vollbildmodus verwendet stattdessen den Reset seines eigenen Allokators.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Beim CGB-Sparse-Start aktualisiert die erste Nutzung jeder Zielbank (die ersten zwei Bilder) den gesamten Ausschnitt und entfernt Initialisierungskacheln. Diese Startkosten sind enthalten. DrawLine2D erfasst keine Sparse-Bereiche: DrawLineClipped2D oder ausdrücklich MarkDirtyRect2D verwenden.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Die zuvor gezeichneten roten und blauen Rahmen verschwinden; nur der letzte grüne Rahmen bei (80,8)..(112,32) bleibt. Dies zeigt partielle Übertragung und Verlaufsverwaltung.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Löscht die angezeigten 128×96-Frame-Tiles und den Staging-Bereich.
Syntax
void Wire3DCGB_ClearFrameTiles();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Wartet beim 128×96-Renderer auf VBlank, deaktiviert das LCD, löscht den Staging-Bereich und die Frame-Tile-Bereiche beider Bänke, setzt Kartenattribute zurück und aktiviert anschließend LCDC 0x81. Löscht Änderungsflags und -zähler, aber nicht den Min/Max-Verlauf partieller Übertragungen. Setzt full_mode nicht zurück und initialisiert den Vollbildmodus nicht neu.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Beim CGB-Sparse-Start aktualisiert die erste Nutzung jeder Zielbank (die ersten zwei Bilder) den gesamten Ausschnitt und entfernt Initialisierungskacheln. Diese Startkosten sind enthalten. DrawLine2D erfasst keine Sparse-Bereiche: DrawLineClipped2D oder ausdrücklich MarkDirtyRect2D verwenden.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Die zuvor gezeichneten roten und blauen Rahmen verschwinden; nur der letzte grüne Rahmen bei (80,8)..(112,32) bleibt. Dies zeigt partielle Übertragung und Verlaufsverwaltung.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Löscht die Verdeckungsbitmap oder den Vollbild-Span-Verlauf.
Syntax
void Wire3DCGB_ClearOcclusionMask();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Löscht bei gesetztem full_mode den Vollbild-Span-Verlauf, andernfalls die 128×96-Bitmap-Maske samt Grenzen. Löscht keine angezeigten oder vorbereiteten Pixel und ändert nicht, ob die Verdeckungsprüfung aktiviert ist.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Ein Dreieck verdeckt die Mitte roter Rasterzeilen; eine gepackte Silhouette verdeckt blaue Linien. Grüne Umrisse zeigen die Lage des verdeckenden Bereichs.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Löscht den gesamten Staging-Bereich und markiert den vollständigen 128×96-Viewport zur Übertragung.
Syntax
void Wire3DCGB_ClearSparseStageFast();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Löscht den gesamten Staging-Bereich in Bank 2 und markiert den vollständigen 128×96-Viewport als geändert. Trotz des Namens ist dies kein partielles Löschen und erhält keine vorbereiteten Pixel. Weder der Verdeckungszustand noch der Übertragungsmodus wird dabei zurückgesetzt beziehungsweise gewählt.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Die zuvor gezeichneten roten und blauen Rahmen verschwinden; nur der letzte grüne Rahmen bei (80,8)..(112,32) bleibt. Dies zeigt partielle Übertragung und Verlaufsverwaltung.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet bis zu 64 Kanten aus vorprojizierten vorzeichenbehafteten Byte-Eckpunktversätzen.
Syntax
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);Parameter
edgesEckpunktindizes je Kante im deklarierten Struct- oder Bytepaar-Format.
edge_countAnzahl der Kanten.
vertex_xArray vorprojizierter X-Eckpunktversätze.
vertex_yArray vorprojizierter Y-Eckpunktversätze.
xX-Koordinate des Mittelpunkts in Viewport-Pixeln.
yY-Koordinate des Mittelpunkts in Viewport-Pixeln.
colorZeichenfarbindex; die Beispielpaletten verwenden 1=Rot, 2=Blau und 3=Grün.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Zeichnet bis zu 64 indizierte Kanten aus vorzeichenbehafteten Byte-Versätzen um (cx,cy). Nullarrays werden ignoriert; Indizes müssen lesbare Eckpunkte adressieren. Halten Sie verschobene Endpunkte vor der umbrechenden Byte-Umwandlung im Viewport. Wählt den Pfad nach Modus und erhält die vorige Farbe; eine Prüfung der Eckpunktanzahl findet nicht statt.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Zwei rote waagerechte Kanten, ein blaues Quadrat, ein begrenzter grüner Rahmen, eine grüne Sechs-Pixel-Markierung und ein rotes Projektil vergleichen die Listenformate.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Prüft vorzeichenbehaftete projizierte Eckpunkte und Kanten, begrenzt danach die Kantenliste und zeichnet sie.
Syntax
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);Parameter
edgesEckpunktindizes je Kante im deklarierten Struct- oder Bytepaar-Format.
edge_countAnzahl der Kanten.
vxArray vorzeichenbehafteter 16-Bit-X-Versätze vor dem Clipping.
vyArray vorzeichenbehafteter 16-Bit-Y-Versätze vor dem Clipping.
vertex_countAnzahl der Einträge im Eckpunktarray.
cxX-Koordinate des Mittelpunkts in Viewport-Pixeln.
cyY-Koordinate des Mittelpunkts in Viewport-Pixeln.
colorZeichenfarbindex; die Beispielpaletten verwenden 1=Rot, 2=Blau und 3=Grün.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Prüft vor dem Zeichnen Zeiger, 1..24 Eckpunkte, höchstens 64 Kanten, jeden Index sowie Eingabekoordinaten und Mittelpunkte im Bereich ±2047. Vollständig sichtbare Geometrie verwendet einen temporären Puffer mit vorzeichenbehafteten Bytes und den schnellen indizierten Pfad; andere Kanten nutzen den Clipper für vorzeichenbehaftete Linien. Dieser kann verschobene Endpunkte außerhalb von ±2047 verwerfen, auch wenn jede einzelne Eingabe gültig war. Ersetzt den gemeinsamen Bildschirm-Arbeitspuffer und erhält die vorherige Farbe über die aufgerufenen Linien-APIs.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Zwei rote waagerechte Kanten, ein blaues Quadrat, ein begrenzter grüner Rahmen, eine grüne Sechs-Pixel-Markierung und ein rotes Projektil vergleichen die Listenformate.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Ersetzt den vorherigen Würfelstempel-Frame und überträgt bis zu drei Stempel samt Statusanzeigen.
Syntax
void Wire3DCGB_DrawFastCubeFrame(Wire3DCGB_FastCube* cubes, w3dcgb_u8 count, w3dcgb_u8 hidden_enabled, w3dcgb_u8 selected);Parameter
cubesArray mit Positionen, Winkeln und Farben für schnelles Würfelzeichnen.
countAnzahl der übergebenen Arrayeinträge; beachten Sie die Verarbeitungsgrenze der jeweiligen Operation.
hidden_enabledNull schließt verdeckte Kanten ein; ein Wert ungleich null wählt vereinfachtes Entfernen verdeckter Kanten.
selectedIndex des ausgewählten Objekts im ursprünglichen Array; die Stempel-API verwendet ihn für eine Statusanzeige.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Bereitet die Karte vor, löscht vorherige Bereiche und Statuszellen, sortiert bis zu drei Würfelstempel nach unverändertem Z von fern nach nah und zeichnet und überträgt Nummern und Attribute im VBlank. Das Aufruferarray wird nicht umgeordnet. Ein Zeiger ungleich null mit count=0 löscht alte Stempel; ein Nullzeiger bewirkt gar nichts. selected & 3 wählt nur die Statuszelle, keine Würfelhervorhebung. Benötigt geladene Würfelstempel, die vollständige Laufzeitumgebung und konsistente FastMap-WRAM-Einblendung; diese werden nicht initialisiert.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Beim CGB-Sparse-Start aktualisiert die erste Nutzung jeder Zielbank (die ersten zwei Bilder) den gesamten Ausschnitt und entfernt Initialisierungskacheln. Diese Startkosten sind enthalten. DrawLine2D erfasst keine Sparse-Bereiche: DrawLineClipped2D oder ausdrücklich MarkDirtyRect2D verwenden.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Der alte Würfelstempel verschwindet. Ein roter 32×32-Würfel beginnt bei (72,32), darüber stehen grüne Statusanzeigen.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet bis zu drei Würfel als 2D-Umrisse mit tiefenabhängiger Größe.
Syntax
void Wire3DCGB_DrawFastCubes(Wire3DCGB_FastCube* cubes, w3dcgb_u8 count, w3dcgb_u8 hidden_enabled, w3dcgb_u8 selected);Parameter
cubesArray mit Positionen, Winkeln und Farben für schnelles Würfelzeichnen.
countAnzahl der übergebenen Arrayeinträge; beachten Sie die Verarbeitungsgrenze der jeweiligen Operation.
hidden_enabledNull schließt verdeckte Kanten ein; ein Wert ungleich null wählt vereinfachtes Entfernen verdeckter Kanten.
selectedIndex des ausgewählten Objekts im ursprünglichen Array; die Stempel-API verwendet ihn für eine Statusanzeige.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Zeichnet bis zu drei 2D-Würfelnäherungen, nach unverändertem Z von fern nach nah sortiert, ohne das Aufruferarray umzuordnen. Null oder leere Eingaben werden ignoriert. selected ist ein Index des ursprünglichen Arrays. Kamera und Rotation werden nicht verwendet; die Farbe wird nicht wiederhergestellt.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Der nahe rote Würfel links ist größer als der entfernte blaue Würfel rechts. Ein grünes Kreuz markiert den ausgewählten roten Würfel.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet ein Projektil mit sechs Kanten um einen bereits projizierten Mittelpunkt; Tiefe und Phase bestimmen Größe und Ausrichtung.
Syntax
void Wire3DCGB_DrawFastProjectile(w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_i16 z, w3dcgb_u8 phase, w3dcgb_u8 color);Parameter
xX-Koordinate des Mittelpunkts in Viewport-Pixeln.
yY-Koordinate des Mittelpunkts in Viewport-Pixeln.
zTiefe zur Größenauswahl oder Projektionsberechnung.
phaseRotationsphase; alle acht Zählschritte folgt die nächste Ausrichtung.
colorZeichenfarbindex; die Beispielpaletten verwenden 1=Rot, 2=Blau und 3=Grün.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Zeichnet ein Projektil mit sechs Kanten um einen bereits projizierten Mittelpunkt, mit vier tiefenabhängigen Größenstufen und vier Phasenausrichtungen. Mittelpunkte außerhalb von X=10..117 oder Y=10..85 werden verworfen. Markiert Änderungsgrenzen und lässt die angeforderte Farbe ausgewählt. Verwendet den normalen Rasterisierer ohne Kameraanwendung.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Zwei rote waagerechte Kanten, ein blaues Quadrat, ein begrenzter grüner Rahmen, eine grüne Sechs-Pixel-Markierung und ein rotes Projektil vergleichen die Listenformate.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet kleine Linienanzeigen für Objektauswahl und Verdeckungsmodus.
Syntax
void Wire3DCGB_DrawFastStatus(w3dcgb_u8 hidden_enabled, w3dcgb_u8 selected);Parameter
hidden_enabledNull schließt verdeckte Kanten ein; ein Wert ungleich null wählt vereinfachtes Entfernen verdeckter Kanten.
selectedIndex des ausgewählten Objekts im ursprünglichen Array; die Stempel-API verwendet ihn für eine Statusanzeige.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Zeichnet kleine Auswahl- und Verdeckungsmodus-Anzeigen in Farbe 3 und markiert ihre Grenzen im normalen Modus als geändert. selected wird im Bereich 0..2 erwartet, aber nicht geprüft. Die Anzeigen verwenden Linien statt Schrift-Tiles; die vorherige Farbe wird nicht wiederhergestellt.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Der nahe rote Würfel links ist größer als der entfernte blaue Würfel rechts. Ein grünes Kreuz markiert den ausgewählten roten Würfel.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet mit dem aktiven Renderer eine Bildschirmgerade einschließlich beider Endpunkte.
Syntax
void Wire3DCGB_DrawLine2D(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by);Parameter
axX-Koordinate von Eckpunkt A in Viewport-Pixeln.
ayY-Koordinate von Eckpunkt A in Viewport-Pixeln.
bxX-Koordinate von Eckpunkt B in Viewport-Pixeln.
byY-Koordinate von Eckpunkt B in Viewport-Pixeln.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Speichert Byte-Endpunkte und ruft den normalen oder den Vollbild-Linienrasterisierer auf. Koordinaten müssen im gewählten Viewport liegen; verwenden Sie DrawLineClipped2D für vorzeichenbehaftete oder außerhalb liegende Geometrie. Normale Linien verknüpfen Farbebenen per OR und markieren keine partiellen Grenzen; verwenden Sie vor partieller Übertragung die Clipping-API oder InvalidateFrameHistory. Vollbildlinien ersetzen Farben und weisen Tiles zu. Beide aktiven Linienpfade behandeln Farbe null als 3, nicht als Löschen.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt einfache Linien, Punkte, Löschen und Projektion in einem Frame. Ein roter Rahmen enthält eine blaue Diagonale, einen grünen Punkt und eine grüne waagerechte Linie, ein blaues L sowie eine grüne Null oben rechts.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet eine Bildschirm-Linie in einer temporären Farbe und erhält die ausgewählte Farbe.
Syntax
void Wire3DCGB_DrawLine2DColor(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by, w3dcgb_u8 color);Parameter
axX-Koordinate von Eckpunkt A in Viewport-Pixeln.
ayY-Koordinate von Eckpunkt A in Viewport-Pixeln.
bxX-Koordinate von Eckpunkt B in Viewport-Pixeln.
byY-Koordinate von Eckpunkt B in Viewport-Pixeln.
colorZeichenfarbindex; die Beispielpaletten verwenden 1=Rot, 2=Blau und 3=Grün.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Setzt für DrawLine2D color & 3 und stellt die vorige Farbe wieder her. Beachten Sie dessen Bedingungen für Koordinaten, Farbkombination und partielle Bereiche; null löscht in keinem der beiden aktiven Renderer eine Linie.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt einfache Linien, Punkte, Löschen und Projektion in einem Frame. Ein roter Rahmen enthält eine blaue Diagonale, einen grünen Punkt und eine grüne waagerechte Linie, ein blaues L sowie eine grüne Null oben rechts.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Projiziert Weltendpunkte durch die Kamera und zeichnet eine Linie in der aktuellen Farbe.
Syntax
void Wire3DCGB_DrawLine3D(w3dcgb_i16 ax, w3dcgb_i16 ay, w3dcgb_i16 az, w3dcgb_i16 bx, w3dcgb_i16 by, w3dcgb_i16 bz);Parameter
axX-Komponente des Startpunkts in Weltkoordinaten.
ayY-Komponente des Startpunkts in Weltkoordinaten.
azZ-Komponente des Startpunkts in Weltkoordinaten.
bxX-Komponente des Endpunkts in Weltkoordinaten.
byY-Komponente des Endpunkts in Weltkoordinaten.
bzZ-Komponente des Endpunkts in Weltkoordinaten.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Projiziert beide Endpunkte durch die Kamera in den 128×96-Viewport. Verwirft die gesamte Linie, wenn ein Endpunkt die Tiefenprüfung nicht besteht; schneidet keine Übergänge durch die nahe Ebene zu. DrawLine2D wählt den Pfad nach Modus, die Projektion bleibt aber 128×96. Normale Linien kombinieren Farbebenen und markieren keine partiellen Grenzen; verwenden Sie eine vollständige Übertragung oder invalidieren Sie den Frame-Verlauf vor einer partiellen Übertragung ausdrücklich.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Vergleicht Modelle in Originalgröße und skalierte Modelle in Rot, Blau und Grün sowie sich kreuzende 3D-Linien. RAM-Werte prüfen zusätzlich die Kameraprojektion und deren Variante ohne Rotation.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet eine 3D-Linie in einer temporären Farbe.
Syntax
void Wire3DCGB_DrawLine3DColor(w3dcgb_i16 ax, w3dcgb_i16 ay, w3dcgb_i16 az, w3dcgb_i16 bx, w3dcgb_i16 by, w3dcgb_i16 bz, w3dcgb_u8 color);Parameter
axX-Komponente des Startpunkts in Weltkoordinaten.
ayY-Komponente des Startpunkts in Weltkoordinaten.
azZ-Komponente des Startpunkts in Weltkoordinaten.
bxX-Komponente des Endpunkts in Weltkoordinaten.
byY-Komponente des Endpunkts in Weltkoordinaten.
bzZ-Komponente des Endpunkts in Weltkoordinaten.
colorZeichenfarbindex; die Beispielpaletten verwenden 1=Rot, 2=Blau und 3=Grün.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Wählt vorübergehend color & 3 für DrawLine3D und stellt danach die vorige Farbe wieder her.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Vergleicht Modelle in Originalgröße und skalierte Modelle in Rot, Blau und Grün sowie sich kreuzende 3D-Linien. RAM-Werte prüfen zusätzlich die Kameraprojektion und deren Variante ohne Rotation.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Begrenzt vorzeichenbehaftete Bildschirmkoordinaten auf den Viewport und zeichnet eine Linie in der angeforderten Farbe.
Syntax
void Wire3DCGB_DrawLineClipped2D(w3dcgb_i16 x0, w3dcgb_i16 y0, w3dcgb_i16 x1, w3dcgb_i16 y1, w3dcgb_u8 color);Parameter
x0Unterer X-Endpunkt in Viewport-Pixeln; Reihenfolge und Begrenzung richten sich nach den Hinweisen zu dieser Operation.
y0Unterer Y-Endpunkt in Viewport-Pixeln; Reihenfolge und Begrenzung richten sich nach den Hinweisen zu dieser Operation.
x1Oberer X-Endpunkt in Viewport-Pixeln; Reihenfolge und Begrenzung richten sich nach den Hinweisen zu dieser Operation.
y1Oberer Y-Endpunkt in Viewport-Pixeln; Reihenfolge und Begrenzung richten sich nach den Hinweisen zu dieser Operation.
colorZeichenfarbindex; die Beispielpaletten verwenden 1=Rot, 2=Blau und 3=Grün.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Vorzeichenbehaftete Endpunkte werden vor der Umwandlung in die u8-ABI des Rasterisierers begrenzt. Schneidet eine vorzeichenbehaftete 2D-Linie auf den gewählten Viewport zu und zeichnet sie in einer temporären Farbe. Eingaben außerhalb von ±2047 werden verworfen. Vollständig innerhalb von 128×96 liegende Linien verwenden einen schnellen Pfad; andere nutzen Bereichscodes und begrenzte ganzzahlige Schnittpunktberechnungen mit höchstens acht Iterationen. Akzeptierte Linien im normalen Modus markieren Änderungsgrenzen. Dies ist ausschließlich Bildschirm-Clipping ohne 3D-Projektion oder Tiefen-Clipping.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt einfache Linien, Punkte, Löschen und Projektion in einem Frame. Ein roter Rahmen enthält eine blaue Diagonale, einen grünen Punkt und eine grüne waagerechte Linie, ein blaues L sowie eine grüne Null oben rechts.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet eine Liste von Vier-Byte-Bildschirmlinien-Datensätzen in einer gewählten Farbe.
Syntax
void Wire3DCGB_DrawLineList2DColor(const w3dcgb_u8* line_xy, w3dcgb_u8 line_count, w3dcgb_u8 color);Parameter
line_xyBytearray mit x0,y0,x1,y1-Datensätzen.
line_countAnzahl der Liniendatensätze; höchstens 64 werden verarbeitet.
colorZeichenfarbindex; die Beispielpaletten verwenden 1=Rot, 2=Blau und 3=Grün.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Zeichnet bis zu 64 Vier-Byte-Datensätze (x0,y0,x1,y1) und ignoriert eine Nullliste. Endpunkte müssen im gewählten Viewport liegen. Erhält die vorige Farbe und übergibt jede Linie an den normalen oder Vollbildrasterisierer.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt einfache Linien, Punkte, Löschen und Projektion in einem Frame. Ein roter Rahmen enthält eine blaue Diagonale, einen grünen Punkt und eine grüne waagerechte Linie, ein blaues L sowie eine grüne Null oben rechts.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet aktivierte Modellkanten aus vorprojizierten Eckpunkten und einer Kantenbitmaske.
Syntax
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);Parameter
modelModell mit Arrays und Anzahlen für Eckpunkte, Kanten und Flächen; seine Tabellen müssen während des Aufrufs lesbar bleiben.
vertex_xArray vorprojizierter X-Eckpunktversätze.
vertex_yArray vorprojizierter Y-Eckpunktversätze.
edge_maskBytearray mit einem Sichtbarkeitsbit je Kante, niederwertigstes Bit zuerst.
xX-Koordinate des Mittelpunkts in Viewport-Pixeln.
yY-Koordinate des Mittelpunkts in Viewport-Pixeln.
colorZeichenfarbindex; die Beispielpaletten verwenden 1=Rot, 2=Blau und 3=Grün.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Zeichnet aktivierte Modellkanten aus vorprojizierten vorzeichenbehafteten Byte-Versätzen um (x,y). Maskenbits beginnen mit dem niederwertigsten Bit, acht Kanten je Byte. Alle Zeiger und Eckpunktindizes müssen gültig sein; edge_mask[0] wird auch bei null Kanten gelesen. Keine Anzahl wird begrenzt. Verschobene Endpunkte müssen vor der Byte-Umwandlung im Viewport liegen; negative Werte würden umbrechen. Erhält die vorige Linienfarbe und wählt den Pfad nach aktivem Modus.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Zwei rote waagerechte Kanten, ein blaues Quadrat, ein begrenzter grüner Rahmen, eine grüne Sechs-Pixel-Markierung und ein rotes Projektil vergleichen die Listenformate.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet ein 3D-Modell an der angegebenen Position und mit der angegebenen Rotation in Originalgröße.
Syntax
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);Parameter
modelModell mit Arrays und Anzahlen für Eckpunkte, Kanten und Flächen; seine Tabellen müssen während des Aufrufs lesbar bleiben.
xX-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
yY-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
zZ-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
rxDrehung um X; sechzehn Schritte ergeben eine volle Umdrehung.
ryDrehung um Y; sechzehn Schritte ergeben eine volle Umdrehung.
rzDrehung um Z; sechzehn Schritte ergeben eine volle Umdrehung.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Zeichnet ein Modell mit Q8-Einheitsskalierung (256) gemäß den Bedingungen von DrawModelScaled.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Vergleicht Modelle in Originalgröße und skalierte Modelle in Rot, Blau und Grün sowie sich kreuzende 3D-Linien. RAM-Werte prüfen zusätzlich die Kameraprojektion und deren Variante ohne Rotation.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet ein Modell in Originalgröße mit einer temporären Farbe.
Syntax
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);Parameter
modelModell mit Arrays und Anzahlen für Eckpunkte, Kanten und Flächen; seine Tabellen müssen während des Aufrufs lesbar bleiben.
xX-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
yY-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
zZ-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
rxDrehung um X; sechzehn Schritte ergeben eine volle Umdrehung.
ryDrehung um Y; sechzehn Schritte ergeben eine volle Umdrehung.
rzDrehung um Z; sechzehn Schritte ergeben eine volle Umdrehung.
colorZeichenfarbindex; die Beispielpaletten verwenden 1=Rot, 2=Blau und 3=Grün.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Zeichnet ein Modell mit Q8-Einheitsskalierung in einer temporären Farbe und stellt danach die vorherige Farbe wieder her.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Vergleicht Modelle in Originalgröße und skalierte Modelle in Rot, Blau und Grün sowie sich kreuzende 3D-Linien. RAM-Werte prüfen zusätzlich die Kameraprojektion und deren Variante ohne Rotation.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Skaliert, dreht und projiziert ein Modell und zeichnet danach dessen ausgewählte Kanten in der aktuellen Farbe.
Syntax
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);Parameter
modelModell mit Arrays und Anzahlen für Eckpunkte, Kanten und Flächen; seine Tabellen müssen während des Aufrufs lesbar bleiben.
xX-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
yY-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
zZ-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
rxDrehung um X; sechzehn Schritte ergeben eine volle Umdrehung.
ryDrehung um Y; sechzehn Schritte ergeben eine volle Umdrehung.
rzDrehung um Z; sechzehn Schritte ergeben eine volle Umdrehung.
scale_q8Skalierung mit 256 als Einheit; nichtpositive Werte bedeuten ebenfalls Originalgröße.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Projiziert bis zu 24 Eckpunkte mit positiver Q8-Skalierung; nichtpositive Skalierung bedeutet Originalgröße. Multiplikation mit eins und Nullwinkelrotationen werden übersprungen. Zwischenwerte müssen in s16 passen. Wenn Nachbarschaftsfilterung verfügbar ist, werden bis zu 16 Vorderseitenflags erzeugt; anschließend werden Kanten mit gültiger Tiefe und gültigen Eckpunktindizes gezeichnet. Die Kantenzahl des Modells ist nicht auf 64 begrenzt. Es gibt kein Clipping an der nahen Ebene. Ersetzt den gemeinsamen Projektionscache und verknüpft Linienfarben per OR mit dem normalen 128×96-Staging-Bereich. Dieser Pfad markiert keine partiellen Grenzen; veranlassen Sie eine vollständige Übertragung oder machen Sie den Frame-Verlauf vor einer partiellen Übertragung ausdrücklich ungültig.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Vergleicht Modelle in Originalgröße und skalierte Modelle in Rot, Blau und Grün sowie sich kreuzende 3D-Linien. RAM-Werte prüfen zusätzlich die Kameraprojektion und deren Variante ohne Rotation.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet ein Modell mit gewählter Skalierung und temporärer Linienfarbe.
Syntax
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);Parameter
modelModell mit Arrays und Anzahlen für Eckpunkte, Kanten und Flächen; seine Tabellen müssen während des Aufrufs lesbar bleiben.
xX-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
yY-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
zZ-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
rxDrehung um X; sechzehn Schritte ergeben eine volle Umdrehung.
ryDrehung um Y; sechzehn Schritte ergeben eine volle Umdrehung.
rzDrehung um Z; sechzehn Schritte ergeben eine volle Umdrehung.
scale_q8Skalierung mit 256 als Einheit; nichtpositive Werte bedeuten ebenfalls Originalgröße.
colorZeichenfarbindex; die Beispielpaletten verwenden 1=Rot, 2=Blau und 3=Grün.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Wählt für DrawModelScaled color & 3 und stellt anschließend die Farbe beim Eintritt wieder her.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Vergleicht Modelle in Originalgröße und skalierte Modelle in Rot, Blau und Grün sowie sich kreuzende 3D-Linien. RAM-Werte prüfen zusätzlich die Kameraprojektion und deren Variante ohne Rotation.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Schreibt ein Pixel in der aktuellen Farbe.
Syntax
void Wire3DCGB_DrawPoint2D(w3dcgb_u8 x, w3dcgb_u8 y);Parameter
xX-Koordinate des Mittelpunkts in Viewport-Pixeln.
yY-Koordinate des Mittelpunkts in Viewport-Pixeln.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Verwirft im normalen Modus Koordinaten außerhalb von 128×96, markiert partielle Grenzen und ersetzt das vorbereitete Pixel durch die aktuelle Farbe einschließlich null. Im Vollbildmodus wird stattdessen eine schnelle Linie mit zusammenfallenden Endpunkten gezeichnet: Null bedeutet dort Farbe 3, und ungültige Koordinaten setzen das Overflow-Flag dieses Frames. Die Bildübertragung erfolgt später.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt einfache Linien, Punkte, Löschen und Projektion in einem Frame. Ein roter Rahmen enthält eine blaue Diagonale, einen grünen Punkt und eine grüne waagerechte Linie, ein blaues L sowie eine grüne Null oben rechts.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet bis zu acht Objekte von nah nach fern; vorherige Modellflächen verdecken spätere Linien.
Syntax
void Wire3DCGB_DrawScene(Wire3DCGB_Object* objects, w3dcgb_u8 count);Parameter
objectsObjektarray mit Positionen, Rotationen, Skalierungen und Sichtbarkeitsflags.
countAnzahl der übergebenen Arrayeinträge; beachten Sie die Verarbeitungsgrenze der jeweiligen Operation.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Sortiert höchstens acht Objekte nach der Tiefe ihres Ursprungs im Kameraraum von nah nach fern, ohne das Aufruferarray zu ändern. Löscht die Maske, zeichnet sichtbare Modelle unter Berücksichtigung zuvor abgedeckter Bereiche und fügt danach ihre Flächen als Verdeckung hinzu. Modellarrays und Flächenindizes müssen gültig sein. Farbe null übernimmt die aktuelle Farbe, möglicherweise die des vorherigen Objekts. Am Ende werden die ursprüngliche Farbe wiederhergestellt und Verdeckung deaktiviert. Dieser Modellpfad verwendet den normalen 128×96-Staging-Bereich.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Ein nahes rotes Quadrat bei (46,30)..(82,66) verdeckt die Mitte einer weiter entfernten blauen waagerechten Linie; sichtbar bleiben nur deren linker und rechter Abschnitt.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet eine Sechs-Pixel-Markierung, deren Kopf und Schwanz die Richtung anzeigen.
Syntax
void Wire3DCGB_DrawTinyModel2D(w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_u8 turn, w3dcgb_u8 color);Parameter
xX-Koordinate des Mittelpunkts in Viewport-Pixeln.
yY-Koordinate des Mittelpunkts in Viewport-Pixeln.
turnWert, dessen untere fünf Bits die Richtung der kleinen Markierung wählen.
colorZeichenfarbindex; die Beispielpaletten verwenden 1=Rot, 2=Blau und 3=Grün.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Zeichnet eine Sechs-Pixel-Markierung über den 128×96-Punktzeichner und erhält die Linienfarbe. Mittelpunkte außerhalb von X=3..124 oder Y=3..92 werden ignoriert. Die unteren fünf turn-Bits wählen Kopf- und Schwanzversätze für links/gerade/rechts. Dies ist keine allgemeine 3D-Transformation und verwendet nicht den Vollbildrenderer.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Zwei rote waagerechte Kanten, ein blaues Quadrat, ein begrenzter grüner Rahmen, eine grüne Sechs-Pixel-Markierung und ein rotes Projektil vergleichen die Listenformate.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet einen ein Pixel breiten Rand mit Farbindex 2 um den 128×96-Staging-Bereich.
Syntax
void Wire3DCGB_DrawWhiteBorderFast();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Schreibt einen ein Pixel breiten Rand in Farbe 2 um den normalen Staging-Bereich und erhält dabei innere Pixel sowie die WRAM-Bankauswahl. Die sichtbare Farbe hängt von der Palette ab. Kein Änderungsbereich wird markiert; bei partieller Übertragung muss der Aufrufer den Upload veranlassen.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Die linken 24 Spalten werden gelöscht, ein roter Streifen bleibt, und der äußere Rand mit Farbindex 2 ist blau.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
kitaqgb/lib/wire3d_cgb.h:147
kitaqgb/lib/wire3d_cgb.c:9369
void Wire3DCGB_DrawWhiteBorderFast()
{
w3dcgb_draw_white_border_asm();
}Wire3DCGB_EnableAtomicMaps
Konfiguriert die 128×96-Ausgabe für den Wechsel zwischen zwei Hintergrundkarten.
Syntax
void Wire3DCGB_EnableAtomicMaps();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Nur beim Start: Reserviert beide BG-Karten; eingereihte HUD-Tiles werden in beide übernommen. Aktiviert den Kartenwechsel einmal während des 128×96-Starts; im Vollbildmodus oder bei bereits aktivierter Einstellung geschieht nichts. Bei eingeschaltetem LCD wird auf VBlank gewartet, das LCD ausgeschaltet, beide Bänke von 9800 nach 9C00 kopiert und den Viewport-Attributen jeweils Tile-Bank 0 beziehungsweise 1 zugewiesen. Stellt LCDC mit ausgewählter Karte 9C00 und VBK null wieder her. Beide BG-Karten sind reserviert; eingereihte HUD-Tile-Nummern werden in beide kopiert.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Die zuvor gezeichneten roten und blauen Rahmen verschwinden; nur der letzte grüne Rahmen bei (80,8)..(112,32) bleibt. Dies zeigt partielle Übertragung und Verlaufsverwaltung.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Schaltet die CGB-CPU auf Doppeltakt um.
Syntax
void Wire3DCGB_EnableDoubleSpeed();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Kehrt auf CGB sofort zurück, wenn KEY1 bereits Doppeltakt meldet; andernfalls wird der Geschwindigkeitswechsel angefordert und der STOP-Helfer aufgerufen. Diese API setzt CGB-Hardware voraus und bietet keinen Ersatzpfad für monochrome Geräte.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt einfache Linien, Punkte, Löschen und Projektion in einem Frame. Ein roter Rahmen enthält eine blaue Diagonale, einen grünen Punkt und eine grüne waagerechte Linie, ein blaues L sowie eine grüne Null oben rechts.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Überträgt den fertigen Frame und zeigt ihn an.
Syntax
void Wire3DCGB_EndFrame();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Im normalen Modus werden eingereihte BG-Schreibzugriffe ausgeführt, der gesamte Staging-Bereich übertragen und die fertige Tile-Bank angezeigt. Der Vollbildmodus überträgt und zeigt seine zugewiesenen Tiles, ohne die HUD-Warteschlange zu leeren. Erfordert aktiviertes LCD und die Bank-/Interruptbedingungen der Übertragungshelfer; kann mehrere Frames dauern.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Beim CGB-Sparse-Start aktualisiert die erste Nutzung jeder Zielbank (die ersten zwei Bilder) den gesamten Ausschnitt und entfernt Initialisierungskacheln. Diese Startkosten sind enthalten. DrawLine2D erfasst keine Sparse-Bereiche: DrawLineClipped2D oder ausdrücklich MarkDirtyRect2D verwenden.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt einfache Linien, Punkte, Löschen und Projektion in einem Frame. Ein roter Rahmen enthält eine blaue Diagonale, einen grünen Punkt und eine grüne waagerechte Linie, ein blaues L sowie eine grüne Null oben rechts.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Überträgt und zeigt einen vollständigen Frame, ohne eingereihte Hintergrund-Schreibzugriffe auszuführen.
Syntax
void Wire3DCGB_EndFrameFast();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Überträgt und zeigt den vollständigen Frame des gewählten Modus, ohne die BG-Warteschlange zu leeren. Ausstehende HUD-Schreibzugriffe werden nicht verbraucht. Es gelten dieselben LCD-, Bank- und Interruptbedingungen wie bei EndFrame; benötigt einen Build mit vollständiger Laufzeitumgebung.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Beim CGB-Sparse-Start aktualisiert die erste Nutzung jeder Zielbank (die ersten zwei Bilder) den gesamten Ausschnitt und entfernt Initialisierungskacheln. Diese Startkosten sind enthalten. DrawLine2D erfasst keine Sparse-Bereiche: DrawLineClipped2D oder ausdrücklich MarkDirtyRect2D verwenden.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Die zuvor gezeichneten roten und blauen Rahmen verschwinden; nur der letzte grüne Rahmen bei (80,8)..(112,32) bleibt. Dies zeigt partielle Übertragung und Verlaufsverwaltung.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Wartet auf einen neuen VBlank und überträgt und zeigt danach die erforderlichen partiellen Bereiche.
Syntax
void Wire3DCGB_EndFrameSparse();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Wartet im normalen Modus auf einen neuen VBlank und ruft EndFrameSparseNow auf. Der Vollbildmodus verwendet stattdessen seine vollständige Übertragung und Anzeige. Benötigt die vollständige Laufzeitumgebung und aktiviertes LCD; Abschluss innerhalb eines Frames ist nicht garantiert.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Beim CGB-Sparse-Start aktualisiert die erste Nutzung jeder Zielbank (die ersten zwei Bilder) den gesamten Ausschnitt und entfernt Initialisierungskacheln. Diese Startkosten sind enthalten. DrawLine2D erfasst keine Sparse-Bereiche: DrawLineClipped2D oder ausdrücklich MarkDirtyRect2D verwenden.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Die zuvor gezeichneten roten und blauen Rahmen verschwinden; nur der letzte grüne Rahmen bei (80,8)..(112,32) bleibt. Dies zeigt partielle Übertragung und Verlaufsverwaltung.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Übergibt Hintergrund-Schreibzugriffe und partielle Bereiche aktuell/N−2 ohne anfängliches Warten auf einen neuen VBlank.
Syntax
void Wire3DCGB_EndFrameSparseNow();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Führt eingereihte BG-Schreibzugriffe aus, überträgt den partiellen Tile-Bereich aktuell/N−2 in die hintere Bank und zeigt ihn an. Überspringt das anfängliche Warten auf einen neuen VBlank; der normale Kartenmodus wartet aber weiterhin beim Wiederherstellen des leeren HUD-Tiles. Auch DMA und Anzeige können warten. Der Vollbildmodus der vollständigen Laufzeitumgebung verwendet seinen eigenen Pfad. LCD muss aktiv sein; SVBK/VBK müssen während DMA stabil bleiben.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Beim CGB-Sparse-Start aktualisiert die erste Nutzung jeder Zielbank (die ersten zwei Bilder) den gesamten Ausschnitt und entfernt Initialisierungskacheln. Diese Startkosten sind enthalten. DrawLine2D erfasst keine Sparse-Bereiche: DrawLineClipped2D oder ausdrücklich MarkDirtyRect2D verwenden.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Die zuvor gezeichneten roten und blauen Rahmen verschwinden; nur der letzte grüne Rahmen bei (80,8)..(112,32) bleibt. Dies zeigt partielle Übertragung und Verlaufsverwaltung.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Löscht die äußersten 24 linken Spalten des normalen Staging-Bereichs.
Syntax
void Wire3DCGB_EraseLeftGuard24Fast();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Löscht die äußersten 24 linken Spalten des Staging-Bereichs per ASM mit erhaltener Bankauswahl. Kein Änderungsbereich wird markiert; bei partieller Übertragung muss der Aufrufer die gelöschten Tiles einschließen.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Die linken 24 Spalten werden gelöscht, ein roter Streifen bleibt, und der äußere Rand mit Farbindex 2 ist blau.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
kitaqgb/lib/wire3d_cgb.h:146
kitaqgb/lib/wire3d_cgb.c:9200
void Wire3DCGB_EraseLeftGuard24Fast()
{
w3dcgb_erase_left_guard24_asm();
}Wire3DCGB_EraseModelFaces
Löscht vorbereitete Pixel innerhalb der projizierten Vorderseiten des Modells.
Syntax
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);Parameter
modelModell mit Arrays und Anzahlen für Eckpunkte, Kanten und Flächen; seine Tabellen müssen während des Aufrufs lesbar bleiben.
xX-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
yY-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
zZ-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
rxDrehung um X; sechzehn Schritte ergeben eine volle Umdrehung.
ryDrehung um Y; sechzehn Schritte ergeben eine volle Umdrehung.
rzDrehung um Z; sechzehn Schritte ergeben eine volle Umdrehung.
scale_q8Skalierung mit 256 als Einheit; nichtpositive Werte bedeuten ebenfalls Originalgröße.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Transformiert für ein Modell mit verdeckten Linien, Eckpunkten und Flächen höchstens 24 Eckpunkte und löscht die nach vorn gerichteten Dreiecke unter höchstens 16 Flächen. Nichtpositive Skalierung bedeutet Originalgröße; dieser Pfad multipliziert auch bei Einheitsskalierung und führt alle drei Rotationshelfer auch bei Nullwinkeln aus. Ungültige Flächen oder solche mit fehlgeschlagener Tiefenprüfung werden verworfen. Ersetzt den gemeinsamen Projektionscache und verwendet den normalen C-Staging-Löscher; der Aufrufer oder die Speicherzuweisung muss daher die richtige WRAM-Einblendung sicherstellen.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Projizierte Flächen löschen einen gefüllten Bereich, sodass erhaltene und gelöschte Bereiche sichtbar werden.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Löscht eine gepackte Silhouette aus beiden Farbebenen des normalen Staging-Bereichs.
Syntax
void Wire3DCGB_ErasePackedSilhouette2D(const w3dcgb_u8* profile, w3dcgb_u8 count, w3dcgb_i8 y0, w3dcgb_u8 x, w3dcgb_u8 y);Parameter
profileSilhouettenarray mit einem Byte je Zeile; 0xFF überspringt eine Zeile.
countAnzahl der übergebenen Arrayeinträge; beachten Sie die Verarbeitungsgrenze der jeweiligen Operation.
y0Vorzeichenbehafteter Versatz vom Y-Mittelpunkt zur ersten Silhouettenzeile.
xX-Koordinate des Mittelpunkts in Viewport-Pixeln.
yY-Koordinate des Mittelpunkts in Viewport-Pixeln.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Löscht bis zu 29 gepackte Silhouettenzeilen aus beiden vorbereiteten Bitebenen. Format, Platzierung, Zwei-Pixel-Schutzrand und Clipping entsprechen MarkPackedSilhouette2D; null wird ignoriert. Der ASM-Span-Schreiber wählt WRAM-Bank 2 und stellt die vorherige Auswahl wieder her, markiert aber keine geänderten Tiles. Im partiellen Modus muss der Aufrufer gelöschte Tiles in den Übertragungsbereich aufnehmen. Diese API betrifft den 128×96-Staging-Bereich.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dreiecke, waagerechte Spans, Rechtecke und gepackte Silhouetten schneiden schwarze Löcher in rot, blau und grün gefüllte Felder.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Löscht ein Rechteck aus dem normalen Staging-Bereich.
Syntax
void Wire3DCGB_EraseRect2D(w3dcgb_u8 x0, w3dcgb_u8 y0, w3dcgb_u8 x1, w3dcgb_u8 y1);Parameter
x0Unterer X-Endpunkt in Viewport-Pixeln; Reihenfolge und Begrenzung richten sich nach den Hinweisen zu dieser Operation.
y0Unterer Y-Endpunkt in Viewport-Pixeln; Reihenfolge und Begrenzung richten sich nach den Hinweisen zu dieser Operation.
x1Oberer X-Endpunkt in Viewport-Pixeln; Reihenfolge und Begrenzung richten sich nach den Hinweisen zu dieser Operation.
y1Oberer Y-Endpunkt in Viewport-Pixeln; Reihenfolge und Begrenzung richten sich nach den Hinweisen zu dieser Operation.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Ordnet und begrenzt das Rechteck auf 128×96. Linke Streifen über die gesamte Höhe mit 16 oder 24 Pixeln Breite verwenden ASM-Löschen mit erhaltener Bankauswahl und Änderungsmarkierung. Andere Rechtecke verwenden zeilenweises Löschen in C und benötigen die richtige WRAM-Einblendung des Staging-Bereichs durch den Aufrufer.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dreiecke, waagerechte Spans, Rechtecke und gepackte Silhouetten schneiden schwarze Löcher in rot, blau und grün gefüllte Felder.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Löscht einen waagerechten Span und sichert und restauriert dabei die WRAM-Bankauswahl.
Syntax
void Wire3DCGB_EraseSpan2D(w3dcgb_u8 y, w3dcgb_u8 x0, w3dcgb_u8 x1);Parameter
yPixel-Y-Koordinate der zu löschenden Zeile.
x0Unterer X-Endpunkt in Viewport-Pixeln; Reihenfolge und Begrenzung richten sich nach den Hinweisen zu dieser Operation.
x1Oberer X-Endpunkt in Viewport-Pixeln; Reihenfolge und Begrenzung richten sich nach den Hinweisen zu dieser Operation.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Ordnet die X-Endpunkte, verwirft eine außerhalb liegende Zeile oder linke Grenze und begrenzt rechts auf 127. Markiert den Bereich als geändert und verwendet den ASM-Span-Löscher, der WRAM-Bank 2 auswählt und die vorherige Bankauswahl wiederherstellt.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dreiecke, waagerechte Spans, Rechtecke und gepackte Silhouetten schneiden schwarze Löcher in rot, blau und grün gefüllte Felder.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Löscht ein Dreieck aus beiden Farbebenen des normalen Staging-Bereichs.
Syntax
void Wire3DCGB_EraseTriangle2D(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by, w3dcgb_u8 cx, w3dcgb_u8 cy);Parameter
axX-Koordinate von Eckpunkt A in Viewport-Pixeln.
ayY-Koordinate von Eckpunkt A in Viewport-Pixeln.
bxX-Koordinate von Eckpunkt B in Viewport-Pixeln.
byY-Koordinate von Eckpunkt B in Viewport-Pixeln.
cxX-Koordinate von Eckpunkt C in Viewport-Pixeln.
cyY-Koordinate von Eckpunkt C in Viewport-Pixeln.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Löscht ein Dreieck über den normalen C-Staging-Löscher. Die begrenzten Spans markieren berührte Tiles als geändert; Aufrufer oder Speicherzuweisung müssen die WRAM-Einblendung des Staging-Bereichs sicherstellen.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dreiecke, waagerechte Spans, Rechtecke und gepackte Silhouetten schneiden schwarze Löcher in rot, blau und grün gefüllte Felder.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Löscht Tile-Nummern und Attribute im 16×12-FastMap-Viewport.
Syntax
void Wire3DCGB_FastMapBegin();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Markiert FastMap als vorbereitet und löscht Tile-Nummern und Attribute im 16×12-Viewport. Die Schattenspalten 16..31 bleiben erhalten, obwohl Flush je Zeile 32 Spalten kopiert. Benötigt die vollständige Laufzeitumgebung und stabile FastMap-WRAM-Einblendung; initialisiert keine Hardware und überträgt die Karte nicht.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Eine rote Ecke, ein großes blaues Rechteck und ein grüner Rahmen von einem Tile zeigen die Umrisszellen. Die anfängliche rote Zelle oben links verschwindet; beim reinen Tile-Update bleiben die Attribute erhalten.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Löscht nur die Tile-Nummern im 16×12-FastMap-Viewport.
Syntax
void Wire3DCGB_FastMapBeginTilesOnly();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Markiert FastMap als vorbereitet und löscht nur die Tile-Nummern im 16×12-Viewport. Attribute und Spalten 16..31 bleiben erhalten. Benötigt die vollständige Laufzeitumgebung und die vorgesehene WRAM-Einblendung; Hardwareinitialisierung und Übertragung erfolgen separat.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Eine rote Ecke, ein großes blaues Rechteck und ein grüner Rahmen von einem Tile zeigen die Umrisszellen. Die anfängliche rote Zelle oben links verschwindet; beim reinen Tile-Update bleiben die Attribute erhalten.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Fügt einer Kartenzelle die ausgewählten oberen, unteren, linken und rechten Umrissseiten hinzu.
Syntax
void Wire3DCGB_FastMapCell(w3dcgb_u8 tx, w3dcgb_u8 ty, w3dcgb_u8 color, w3dcgb_u8 mask);Parameter
txX-Position in Tile-Koordinaten.
tyY-Position in Tile-Koordinaten.
colorZeichenfarbindex; die Beispielpaletten verwenden 1=Rot, 2=Blau und 3=Grün.
maskZellseitenmaske: 1=oben, 2=unten, 4=links, 8=rechts.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Fügt einer Zelle Umrissseiten hinzu: Bits 1/2/4/8 bedeuten oben/unten/links/rechts. Masken gleicher Farbe werden kombiniert; eine andere Farbe ersetzt die alte Maske. Maske null wird ignoriert, Farbe null bedeutet MAIN, und Farben über 3 werden auf 3 begrenzt. Betrifft den 16×12-Schattenpuffer bei stabiler WRAM-Einblendung; benötigt die vollständige Laufzeitumgebung.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Eine rote Ecke, ein großes blaues Rechteck und ein grüner Rahmen von einem Tile zeigen die Umrisszellen. Die anfängliche rote Zelle oben links verschwindet; beim reinen Tile-Update bleiben die Attribute erhalten.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Überträgt die ersten zwölf vollständigen Zeilen der Schatten-Tile-Nummern und -Attribute ins VRAM.
Syntax
void Wire3DCGB_FastMapFlush();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Wartet bei aktiviertem LCD auf einen neuen VBlank und überträgt dann die ersten zwölf vollständigen Kartenzeilen mit Tile-Nummern und Attributen nach Karte 9800. Bei ausgeschaltetem LCD geht es sofort weiter. Benötigt die vollständige Laufzeitumgebung, stabile WRAM-Einblendung und genügend sichere Zeit für beide sofortigen GDMA-Übertragungen.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Eine rote Ecke, ein großes blaues Rechteck und ein grüner Rahmen von einem Tile zeigen die Umrisszellen. Die anfängliche rote Zelle oben links verschwindet; beim reinen Tile-Update bleiben die Attribute erhalten.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Überträgt nur die Tile-Nummern der ersten zwölf vollständigen Schattenkartenzeilen.
Syntax
void Wire3DCGB_FastMapFlushTilesOnly();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Wartet bei aktiviertem LCD auf einen neuen VBlank und überträgt nur die Tile-Nummern der ersten zwölf vollständigen Zeilen nach Karte 9800. Attribute bleiben erhalten. Benötigt die vollständige Laufzeitumgebung, stabile WRAM-Einblendung und ein sicheres GDMA-Zeitfenster.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Eine rote Ecke, ein großes blaues Rechteck und ein grüner Rahmen von einem Tile zeigen die Umrisszellen. Die anfängliche rote Zelle oben links verschwindet; beim reinen Tile-Update bleiben die Attribute erhalten.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Setzt die ausgewählten Umrissseiten um ein Rechteck in Tile-Koordinaten.
Syntax
void Wire3DCGB_FastMapRect(w3dcgb_u8 tx0, w3dcgb_u8 ty0, w3dcgb_u8 tx1, w3dcgb_u8 ty1, w3dcgb_u8 color, w3dcgb_u8 sides);Parameter
tx0X-Position in Tile-Koordinaten.
ty0Y-Position in Tile-Koordinaten.
tx1X-Position in Tile-Koordinaten.
ty1Y-Position in Tile-Koordinaten.
colorZeichenfarbindex; die Beispielpaletten verwenden 1=Rot, 2=Blau und 3=Grün.
sidesRechteckseitenmaske: 1=oben, 2=unten, 4=links, 8=rechts.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Ordnet die Byte-Tile-Koordinaten, begrenzt sie auf 16×12 und ersetzt die ausgewählten Randzellen. Seitenbits 1/2/4/8 bedeuten oben/unten/links/rechts. Farbe null bedeutet MAIN; Werte über 3 werden auf 3 begrenzt. Attribute und innere Zellen bleiben erhalten. Verwenden Sie mindestens zwei Zeilen und Spalten für getrennte Ecken; zusammenfallende Ecken werden nacheinander überschrieben. Benötigt die vollständige Laufzeitumgebung und stabile WRAM-Einblendung.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Eine rote Ecke, ein großes blaues Rechteck und ein grüner Rahmen von einem Tile zeigen die Umrisszellen. Die anfängliche rote Zelle oben links verschwindet; beim reinen Tile-Update bleiben die Attribute erhalten.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Meldet eine ungültige Koordinate oder erschöpfte Tile-Zuweisung beim Vollbildzeichnen.
Syntax
w3dcgb_u8 Wire3DCGB_GetFullScreenOverflow();Rückgabewert
Null ohne Fehler, eins nach erschöpfter Zuweisung oder ungültiger Koordinate.
Bedingungen und Grenzen
Liefert das Fehlerflag des Vollbildframes: Der schnelle Linienpfad setzt es bei erschöpfter Tile-Zuweisung oder ungültiger Koordinate. Danach werden weitere Pixelzugriffe des schnellen Pfads unterdrückt, bis BeginFrame das Flag zurücksetzt. Dies ist kein allgemeines Hardwarestatusflag; der Getter benötigt die vollständige Laufzeitumgebung.
Die Vollbild-Zuweisung erfolgt, bevor Verdeckung und Overflow Pixelschreibzugriffe unterdrücken. Zugewiesene Tiles können schwarz bleiben; weiteres Zeichnen nach einem Fehler kann die Tile-Anzahl weiterhin erhöhen.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
127 rote Punkte belegen unterschiedliche Tiles. Der Versuch einer 128. Zuweisung lässt die Anzahl bei 127 und setzt overflow auf eins.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
kitaqgb/lib/wire3d_cgb.h:194
kitaqgb/lib/wire3d_cgb.c:9965
w3dcgb_u8 Wire3DCGB_GetFullScreenOverflow()
{
return w3dcgb_full_overflow;
}Wire3DCGB_GetFullScreenTileCount
Liefert die Anzahl der im aktuellen Frame zugewiesenen Vollbild-Tiles.
Syntax
w3dcgb_u8 Wire3DCGB_GetFullScreenTileCount();Rückgabewert
Anzahl zugewiesener Tiles, 0..127.
Bedingungen und Grenzen
Liefert die aktuelle Vollbild-Zuweisungsanzahl bis 127. Dies ist weder eine Byteanzahl noch die Anzahl sichtbarer oder von null verschiedener Pixel. Nur mit vollständiger Laufzeitumgebung.
Die Vollbild-Zuweisung erfolgt, bevor Verdeckung und Overflow Pixelschreibzugriffe unterdrücken. Zugewiesene Tiles können schwarz bleiben; weiteres Zeichnen nach einem Fehler kann die Tile-Anzahl weiterhin erhöhen.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
127 rote Punkte belegen unterschiedliche Tiles. Der Versuch einer 128. Zuweisung lässt die Anzahl bei 127 und setzt overflow auf eins.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
kitaqgb/lib/wire3d_cgb.h:193
kitaqgb/lib/wire3d_cgb.c:9956
w3dcgb_u8 Wire3DCGB_GetFullScreenTileCount()
{
return w3dcgb_full_tile_count;
}Wire3DCGB_GetLineColor
Liest den aktuell gespeicherten Linienfarbindex.
Syntax
w3dcgb_u8 Wire3DCGB_GetLineColor();Rückgabewert
Aktuell gespeicherter Linienfarbwert.
Bedingungen und Grenzen
Liefert die aktuell gespeicherte Zwei-Bit-Linienfarbe, ohne den Zeichenzustand zu ändern.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt einfache Linien, Punkte, Löschen und Projektion in einem Frame. Ein roter Rahmen enthält eine blaue Diagonale, einen grünen Punkt und eine grüne waagerechte Linie, ein blaues L sowie eine grüne Null oben rechts.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
kitaqgb/lib/wire3d_cgb.h:120
kitaqgb/lib/wire3d_cgb.c:1147
w3dcgb_u8 Wire3DCGB_GetLineColor()
{
return w3dcgb_line_color;
}Wire3DCGB_Init
Initialisiert den CGB-Pixelrenderer für 128×96.
Syntax
void Wire3DCGB_Init();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Initialisiert den CGB-exklusiven 128×96-Renderer: Aktiviert den Doppeltakt, schaltet das LCD im VBlank aus, löscht beide Tile-Bänke, lädt HUD- und erzeugte Tiles und richtet einen spaltenweise angeordneten 16×12-Viewport ein. Der Startzustand verwendet die leere Tile-Bank 1, Scrollwerte null, Standard-BG-Paletten, Farbe 2 und eine auf null gesetzte Kamera. Setzt Warteschlangen zurück und löscht den Staging-Bereich in Bank 2. Rufen Sie vor dem Zeichnen BeginFrame auf, um den Verdeckungszustand zu initialisieren. Die Initialisierung ersetzt den LCD-, Tile- und Kartenzustand global.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Beim CGB-Sparse-Start aktualisiert die erste Nutzung jeder Zielbank (die ersten zwei Bilder) den gesamten Ausschnitt und entfernt Initialisierungskacheln. Diese Startkosten sind enthalten. DrawLine2D erfasst keine Sparse-Bereiche: DrawLineClipped2D oder ausdrücklich MarkDirtyRect2D verwenden.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt einfache Linien, Punkte, Löschen und Projektion in einem Frame. Ein roter Rahmen enthält eine blaue Diagonale, einen grünen Punkt und eine grüne waagerechte Linie, ein blaues L sowie eine grüne Null oben rechts.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Initialisiert das FastMap-Rendering mit vorberechneten Umriss-Tiles.
Syntax
void Wire3DCGB_InitFastMapLite();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Initialisiert einen CGB-Tilemap-Renderer mit HUD und 48 vorberechneten Umriss-Tiles. Löscht Tile-VRAM und Karten, setzt Scrolling, Paletten und Kamera zurück und wählt den normalen Modus. Das übliche Kartenlayout des Pixel-Viewports und erzeugte Würfelstempel entfallen; verwenden Sie in diesem Modus die FastMap-APIs. Löscht den Staging-Bereich in Bank 2 und markiert die FastMap-Vorbereitung als ausstehend. Ein Build mit vollständiger Laufzeitumgebung ist erforderlich.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Eine rote Ecke, ein großes blaues Rechteck und ein grüner Rahmen von einem Tile zeigen die Umrisszellen. Die anfängliche rote Zelle oben links verschwindet; beim reinen Tile-Update bleiben die Attribute erhalten.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Initialisiert einen 160×144-Renderer, der beim Zeichnen von Pixeln Tiles zuweist.
Syntax
void Wire3DCGB_InitFullScreen();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Initialisiert den CGB-exklusiven Tile-Allokator für 160×144. Löscht beide Tile-Bänke und Karte 9800, setzt Scrolling, Paletten, Farbe und Kamera, setzt Tile-Zähler sowie Lookup- und Span-Zustand zurück und aktiviert die vorzeichenlose BG-Tile-Adressierung. HUD-Tiles werden nicht geladen. Reservieren Sie die festen WRAM-Bereiche für Lookup, Nutzdaten und Adresslisten. Lassen Sie beim gesamten Vollbild-Rendering dieselbe WRAM-Bank eingeblendet.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Ein großer Rahmen reicht von (8,8) bis (151,135): oben und links rot, unten blau, rechts grün. Er verwendet 64 Tiles bei overflow null.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Erweitert den aktuellen und die beiden vorherigen Übertragungsbereiche auf alle 192 Tiles des normalen Modus.
Syntax
void Wire3DCGB_InvalidateFrameHistory();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Markiert den aktuellen und beide vorherigen partiellen Bereiche als alle 192 Tiles des normalen Modus. Pixeldaten werden nicht gelöscht; spätere Übertragungen können sich nicht mehr auf alte Bereiche verlassen.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Beim CGB-Sparse-Start aktualisiert die erste Nutzung jeder Zielbank (die ersten zwei Bilder) den gesamten Ausschnitt und entfernt Initialisierungskacheln. Diese Startkosten sind enthalten. DrawLine2D erfasst keine Sparse-Bereiche: DrawLineClipped2D oder ausdrücklich MarkDirtyRect2D verwenden.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Die zuvor gezeichneten roten und blauen Rahmen verschwinden; nur der letzte grüne Rahmen bei (80,8)..(112,32) bleibt. Dies zeigt partielle Übertragung und Verlaufsverwaltung.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Fügt dem später zu übertragenden Bereich ein Pixelrechteck hinzu.
Syntax
void Wire3DCGB_MarkDirtyRect2D(w3dcgb_u8 min_x, w3dcgb_u8 min_y, w3dcgb_u8 max_x, w3dcgb_u8 max_y);Parameter
min_xUnterer X-Endpunkt in Viewport-Pixeln; Reihenfolge und Begrenzung richten sich nach den Hinweisen zu dieser Operation.
min_yUnterer Y-Endpunkt in Viewport-Pixeln; Reihenfolge und Begrenzung richten sich nach den Hinweisen zu dieser Operation.
max_xOberer X-Endpunkt in Viewport-Pixeln; Reihenfolge und Begrenzung richten sich nach den Hinweisen zu dieser Operation.
max_yOberer X-Endpunkt in Viewport-Pixeln; Reihenfolge und Begrenzung richten sich nach den Hinweisen zu dieser Operation.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Markiert ein Pixelrechteck einschließlich seiner Endpunkte zur späteren Übertragung, ohne es zu zeichnen. Geben Sie die Endpunkte geordnet an; Werte oberhalb von 127/95 werden auf den Rand begrenzt. Dies erfasst die 128×96-Tiles, nicht den Vollbild-Tile-Allokator.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Die zuvor gezeichneten roten und blauen Rahmen verschwinden; nur der letzte grüne Rahmen bei (80,8)..(112,32) bleibt. Dies zeigt partielle Übertragung und Verlaufsverwaltung.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Markiert eine zeilenweise gepackte Silhouette in der 128×96-Verdeckungsbitmap.
Syntax
void Wire3DCGB_MarkPackedSilhouette2D(const w3dcgb_u8* profile, w3dcgb_u8 count, w3dcgb_i8 y0, w3dcgb_u8 x, w3dcgb_u8 y);Parameter
profileSilhouettenarray mit einem Byte je Zeile; 0xFF überspringt eine Zeile.
countAnzahl der übergebenen Arrayeinträge; beachten Sie die Verarbeitungsgrenze der jeweiligen Operation.
y0Vorzeichenbehafteter Versatz vom Y-Mittelpunkt zur ersten Silhouettenzeile.
xX-Koordinate des Mittelpunkts in Viewport-Pixeln.
yY-Koordinate des Mittelpunkts in Viewport-Pixeln.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Markiert bis zu 29 Silhouettenzeilen in der 128×96-Bitmap-Maske. Das obere Nibble jedes gepackten Bytes beschreibt den Mittenversatz (nibble−7), das untere die halbe Breite; 0xFF überspringt eine Zeile. Die Zeilen liegen bei y+y0+i; ihre Spans werden um zwei Pixel erweitert und auf den Viewport begrenzt. profile muss count lesbare Bytes enthalten; null wird ignoriert. Aktualisiert weder Vollbild-Spans noch aktiviert es Verdeckung.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Ein Dreieck verdeckt die Mitte roter Rasterzeilen; eine gepackte Silhouette verdeckt blaue Linien. Grüne Umrisse zeigen die Lage des verdeckenden Bereichs.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Registriert ein Dreieck als Bereich, der anschließend gezeichnete Linien verdecken kann.
Syntax
void Wire3DCGB_MarkTriangle2D(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by, w3dcgb_u8 cx, w3dcgb_u8 cy);Parameter
axX-Koordinate von Eckpunkt A in Viewport-Pixeln.
ayY-Koordinate von Eckpunkt A in Viewport-Pixeln.
bxX-Koordinate von Eckpunkt B in Viewport-Pixeln.
byY-Koordinate von Eckpunkt B in Viewport-Pixeln.
cxX-Koordinate von Eckpunkt C in Viewport-Pixeln.
cyY-Koordinate von Eckpunkt C in Viewport-Pixeln.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Markiert ein Dreieck in Bildschirmkoordinaten, ohne Pixel zu zeichnen oder Verdeckung zu aktivieren. Die Eckpunkte müssen im gewählten Viewport liegen. Der verwendete ASM-Code ergänzt einen Schutzrand von einem Pixel in X, begrenzt auf 0..127 im Modus 128×96 beziehungsweise 0..159 im Modus 160×144. Beliebige außerhalb liegende Dreiecke werden nicht zugeschnitten.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Ein Dreieck verdeckt die Mitte roter Rasterzeilen; eine gepackte Silhouette verdeckt blaue Linien. Grüne Umrisse zeigen die Lage des verdeckenden Bereichs.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Nähert einen projizierten Versatz mit Brennweite 48 an.
Syntax
w3dcgb_i16 Wire3DCGB_ProjectAxis48(w3dcgb_i16 value, w3dcgb_i16 z);Parameter
valueZu projizierende vorzeichenbehaftete 16-Bit-Komponente.
zTiefe zur Größenauswahl oder Projektionsberechnung.
Rückgabewert
Angenäherter vorzeichenbehafteter 16-Bit-Projektionsversatz.
Bedingungen und Grenzen
Nähert value*48/z ohne Kamera- oder Bildschirmmittenversatz an. Negative oder sehr kleine Z-Werte werden zu 4. Bei Z über 255 werden Tiefe und Betrag gemeinsam nach rechts geschoben, bis die Tiefe in ein Byte passt; danach wird der Betrag auf 160 begrenzt. Liefert einen vorzeichenbehafteten Versatz; der Helfer verwirft keine nahen oder fernen Tiefenwerte.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Zwei rote waagerechte Kanten, ein blaues Quadrat, ein begrenzter grüner Rahmen, eine grüne Sechs-Pixel-Markierung und ein rotes Projektil vergleichen die Listenformate.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Projiziert einen Weltpunkt durch die Kamera in den 128×96-Viewport.
Syntax
w3dcgb_u8 Wire3DCGB_ProjectPoint(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_u8* sx, w3dcgb_u8* sy);Parameter
xX-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
yY-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
zZ-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
sxGültiger beschreibbarer u8-Zeiger für die projizierte X-Koordinate.
syGültiger beschreibbarer u8-Zeiger für die projizierte Y-Koordinate.
Rückgabewert
Liefert 1 bei erfolgreicher Projektion oder 0 bei verworfener Tiefe.
Bedingungen und Grenzen
Projiziert einen Weltpunkt durch die aktuelle Kamera in den 128×96-Viewport. Bei verworfener Tiefe wird null zurückgegeben und die Ausgabe bleibt unverändert; andernfalls werden begrenzte Byte-Koordinaten geschrieben. Gültige beschreibbare Zeiger sind erforderlich. Dies ist nicht der 160×144-Vollbildprojektor. In MINIMAL_RUNTIME-Builds nicht enthalten.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Vergleicht Modelle in Originalgröße und skalierte Modelle in Rot, Blau und Grün sowie sich kreuzende 3D-Linien. RAM-Werte prüfen zusätzlich die Kameraprojektion und deren Variante ohne Rotation.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Projiziert einen Punkt nach Abzug der Kameraposition ohne Kamerarotation.
Syntax
w3dcgb_u8 Wire3DCGB_ProjectPointNoRotation(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_u8* sx, w3dcgb_u8* sy);Parameter
xX-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
yY-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
zZ-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
sxGültiger beschreibbarer u8-Zeiger für die projizierte X-Koordinate.
syGültiger beschreibbarer u8-Zeiger für die projizierte Y-Koordinate.
Rückgabewert
Liefert 1 bei erfolgreicher Projektion oder 0 bei verworfener Tiefe.
Bedingungen und Grenzen
Schneller Pfad für Spiele, deren Kamerawinkel für Nicken, Gieren und Rollen null bleiben. Zieht die Kameraposition ab und projiziert nach 128×96, wobei alle Kamerawinkel ignoriert werden. Nur bei drei Nullwinkeln verwenden. Ungültige Tiefe wird ohne Änderung der Ausgabeziele verworfen; erfolgreiche Koordinaten werden auf den Viewport begrenzt. In MINIMAL_RUNTIME-Builds nicht enthalten.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Vergleicht Modelle in Originalgröße und skalierte Modelle in Rot, Blau und Grün sowie sich kreuzende 3D-Linien. RAM-Werte prüfen zusätzlich die Kameraprojektion und deren Variante ohne Rotation.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Reiht eine Änderung der Hintergrund-Tile-Nummer für EndFrame ein.
Syntax
void Wire3DCGB_PutBgTile(w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_u8 tile);Parameter
xX-Tile-Koordinate in der 32×32-Hintergrundkarte.
yY-Tile-Koordinate in der 32×32-Hintergrundkarte.
tileAcht-Bit-Tile-Nummer für die Hintergrundzelle.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Reiht einen Tile-Nummer-Schreibzugriff für eine 32×32-BG-Karte ein. Ungültige Koordinaten und weitere Einträge nach 48 ausstehenden Schreibzugriffen werden ignoriert. EndFrame leert diese private Warteschlange; im atomic-map-Modus werden Schreibzugriffe in beide BG-Karten übernommen. Attribute werden nicht eingereiht.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt einfache Linien, Punkte, Löschen und Projektion in einem Frame. Ein roter Rahmen enthält eine blaue Diagonale, einen grünen Punkt und eine grüne waagerechte Linie, ein blaues L sowie eine grüne Null oben rechts.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Packt rote, grüne und blaue Fünf-Bit-Kanäle in eine CGB-15-Bit-Farbe.
Syntax
#define WIRE3DCGB_RGB15(r5, g5, b5) ((w3dcgb_u16)((w3dcgb_u16)((r5) & 31) | ((w3dcgb_u16)((g5) & 31) << 5) | ((w3dcgb_u16)((b5) & 31) << 10)))Parameter
r5Rotkanal, 0..31.
g5Grünkanal, 0..31.
b5Blaukanal, 0..31.
Rückgabewert
Gepackter RGB15-Wert als u16.
Bedingungen und Grenzen
Packt die unteren fünf Bits jedes Kanals in RGB15; jedes Argument wird genau einmal ausgewertet.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt einfache Linien, Punkte, Löschen und Projektion in einem Frame. Ein roter Rahmen enthält eine blaue Diagonale, einen grünen Punkt und eine grüne waagerechte Linie, ein blaues L sowie eine grüne Null oben rechts.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
kitaqgb/lib/wire3d_cgb.h:50
Wire3DCGB_SetCamera
Speichert Kameraposition und -ausrichtung für die Projektion mit 16 Winkelschritten pro Umdrehung.
Syntax
void Wire3DCGB_SetCamera(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 pitch, w3dcgb_i8 yaw, w3dcgb_i8 roll);Parameter
xX-Komponente der Kamera in Weltkoordinaten.
yY-Komponente der Kamera in Weltkoordinaten.
zZ-Komponente der Kamera in Weltkoordinaten.
pitchDrehung um X; sechzehn Schritte ergeben eine volle Umdrehung.
yawDrehung um Y; sechzehn Schritte ergeben eine volle Umdrehung.
rollDrehung um Z; sechzehn Schritte ergeben eine volle Umdrehung.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Speichert Kameraposition und -winkel, ohne vorhandene Pixel zu ändern. Rotationshelfer verwenden die unteren vier Winkelbits, also 16 Schritte pro Umdrehung. Bildschirmversätze liegen in separaten LCD-Registern und werden durch diesen Aufruf nicht geändert.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Vergleicht Modelle in Originalgröße und skalierte Modelle in Rot, Blau und Grün sowie sich kreuzende 3D-Linien. RAM-Werte prüfen zusätzlich die Kameraprojektion und deren Variante ohne Rotation.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Wählt den Farbindex für anschließend gezeichnete Linien.
Syntax
void Wire3DCGB_SetLineColor(w3dcgb_u8 color);Parameter
colorZeichenfarbindex; die Beispielpaletten verwenden 1=Rot, 2=Blau und 3=Grün.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Speichert color & 3. Verwenden Sie die benannten Linienfarben 1..3: Normale Linien verknüpfen ihre Bitebenen mit OR, sodass sich Farben an Schnittpunkten kombinieren; schnelle Vollbildlinien ersetzen dagegen die Pixelfarbe. Linienfarbe null wird als 3 behandelt und löscht nicht. Beim Zeichnen von Punkten im normalen Modus wird Farbe null unabhängig davon zum Löschen unterstützt.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt einfache Linien, Punkte, Löschen und Projektion in einem Frame. Ein roter Rahmen enthält eine blaue Diagonale, einen grünen Punkt und eine grüne waagerechte Linie, ein blaues L sowie eine grüne Null oben rechts.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Aktiviert oder deaktiviert die Verdeckungsprüfung für nachfolgende Linien.
Syntax
void Wire3DCGB_SetOcclusionActive(w3dcgb_u8 active);Parameter
activeNull deaktiviert die Verdeckungsprüfung; jeder andere Wert aktiviert sie.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Normalisiert active auf null oder eins und speichert es als Verdeckungsschalter. Es werden weder Masken gelöscht noch Geometrie markiert.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Ein Dreieck verdeckt die Mitte roter Rasterzeilen; eine gepackte Silhouette verdeckt blaue Linien. Grüne Umrisse zeigen die Lage des verdeckenden Bereichs.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Setzt die vier Zeichenfarben und die Hintergrundpaletten zum Einfärben der Stempel.
Syntax
void Wire3DCGB_SetPaletteRGB15(w3dcgb_u16 color0, w3dcgb_u16 color1, w3dcgb_u16 color2, w3dcgb_u16 color3);Parameter
color0RGB15-Farbe in Paletteneintrag 0.
color1RGB15-Farbe in Paletteneintrag 1.
color2RGB15-Farbe in Paletteneintrag 2.
color3RGB15-Farbe in Paletteneintrag 3.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Setzt BG-Palette 0 auf die vier übergebenen RGB15-Farben. Die Paletten 1..3 teilen sich color0 und wiederholen ihre jeweilige Farbe mit Index ungleich null in den Einträgen 1..3. So lassen sich monochrome Stempel-Tiles über Attribute umfärben. Rufen Sie die Funktion in einem zulässigen Zeitfenster für Palettenzugriffe auf, üblicherweise beim Einrichten mit ausgeschaltetem LCD oder im VBlank.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt einfache Linien, Punkte, Löschen und Projektion in einem Frame. Ein roter Rahmen enthält eine blaue Diagonale, einen grünen Punkt und eine grüne waagerechte Linie, ein blaues L sowie eine grüne Null oben rechts.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Setzt die LCD-Scrollregister SCX und SCY direkt.
Syntax
void Wire3DCGB_SetScreenOffset(w3dcgb_u8 scx, w3dcgb_u8 scy);Parameter
scxIn SCX geschriebener Scrollversatz in Pixeln.
scyIn SCY geschriebener Scrollversatz in Pixeln.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
Schreibt SCX/SCY sofort, ohne auf VBlank zu warten oder projizierte Koordinaten zu ändern. Der Aufrufer bestimmt, wann eine sichtbare Scrolländerung akzeptabel ist.
Nur CGB. Das normale Staging reserviert D300..DEFF in WRAM-Bank 2. Wegen des gemeinsam genutzten Zustands sind diese Routinen nicht reentrant; rufen Sie sie nicht rekursiv aus Interrupts auf. Die Beispiele verwenden einen festen Stack und die vollständige Laufzeitumgebung.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt einfache Linien, Punkte, Löschen und Projektion in einem Frame. Ein roter Rahmen enthält eine blaue Diagonale, einen grünen Punkt und eine grüne waagerechte Linie, ein blaues L sowie eine grüne Null oben rechts.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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-Zeitmessung, Profile mit 88 Zeilen und unabhängige Takte
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Ein vollständiger Transfer mit 88 Zeilen liest bei DMG 1.408 Byte und bei CGB 2.816 Byte. Gegenüber DMG 120 sinkt die Datenmenge um 26,67 %, gegenüber 96 Zeilen um 8,33 %; daraus folgt keine entsprechende fps-Steigerung. DMG behält 256-Byte-Spaltenabstände, CGB packt Spalten mit 11 Kacheln. CGB reserviert weiterhin 3.072 Byte für die Kompatibilität zum Vollbildmodus.
ProjectCameraPoint projiziert Kamerakoordinaten ohne Kamerasubtraktion oder -rotation. Außerhalb Z=8..255 liefert es 0 und lässt die Ausgaben unverändert. X/Y werden auf ±120 begrenzt; Produkte der inversen Tiefentabelle werden vorzeichenbehaftet mit Abrundung durch 32 geteilt und danach auf den Bildschirm begrenzt. Dies ist kein geometrisches Abschneiden von Linien. Das allgemeine CGB ProjectPoint behält die Rotationsgrenzen ±220 auch bei Nullwinkeln.
DMG EndFrameNow überspringt nur das anfängliche Warten auf einen neuen VBlank und verarbeitet BG-Warteschlange, Transfermodi und dirty-Historie. CGB EndFrameSparseNow arbeitet ebenfalls synchron. Now wartet weiterhin auf STAT-Zugriff, DMA-Ende und sichere Anzeige. DMG-Aktualisierungen sind nicht atomar. Beim CGB-sparse-Löschen zählen der aktuelle Bereich und der zwei Bilder alte Bereich der Zielbank. Niedrige CGB-Linienfunktionen brauchen dirty-Markierungen.
Beim CGB-Sparse-Start aktualisiert die erste Nutzung jeder Zielbank (die ersten zwei Bilder) den gesamten Ausschnitt und entfernt Initialisierungskacheln. Diese Startkosten sind enthalten. DrawLine2D erfasst keine Sparse-Bereiche: DrawLineClipped2D oder ausdrücklich MarkDirtyRect2D verwenden.
Die Beispiele verwenden einen unabhängig erstellten bewegten Quader, eine Balkenanzeige und vier BGM-Töne. Die Bewegung nutzt verstrichene audio_vblank-Ticks; eine kurze sichere VBlank-Routine aktualisiert die Anzeige. Rufen Sie den Renderer mit gemeinsamem Zustand nie aus einer ISR auf. wire3d_audio_vblank.c legt die 80-Byte-Warteschlange in festen WRAM und Steuerfunktionen in ROM-Bank 5. Kompilieren Sie nicht zusätzlich audio_vblank.c. CGB-Beispiele nutzen WIRE3DCGB_STAGE_BANK2_ALLOCATION. Lesen Sie die Differenz eines 8-Bit-Ticks innerhalb von 255 Bildern.
Das Messwerkzeug zählt Marker nach abgeschlossenem Transfer und Anzeigenwechsel. PPU-Dots (4.194.304/s; 70.224/Bild) erfassen Löschen, Projektion, Rasterung, Transfer samt Anzeige und äußere Wartezeit. Berichtet werden Mittelwert, Median, größtes Intervall und überschrittene Fristen. Transfer samt Anzeige umfasst interne STAT/DMA/VBlank-Wartezeiten. Vergleichen Sie rohe CGB-CPU-Zyklen bei doppeltem Takt nicht direkt mit DMG. Gleiche mittlere fps belegen keine Einhaltung aller Fristen. Reale Hardware ist nicht geprüft.
Sieben eigene Beispielkonfigurationen führten je 48 Transfers aus: 336 Stage/VRAM-Vergleiche und 84 Leerbilder zur Löschprüfung. Fünf Profile bestanden 25.700 Projektionsgrenzfälle. Fünf Rust-Builds beendeten ebenfalls 48 Bilder mit BGM-Ausgabe. Einige Intervalle überschreiten vier PPU-Bilder: Durchschnitts-fps beweisen keinen Betrieb ohne Verzögerung. Emulatorprüfung, keine Hardwareverifikation.
KOKURA führte die eigenen DMG/CGB-Beispiele je 400 Bilder aus; SARAKURA-Analyse und strenge Schemavalidierung bestanden. Jeweils bleiben null Fehler, eine Warnung für wiederholten PC in der Warteschleife und drei Hinweise, darunter DAC/Mixer-Knackrisiken. Audiotreue und Hardwareverhalten sind damit nicht bestätigt.
Veröffentlichte Beispiele, Bilder und Prüfdaten verwenden ausschließlich unabhängig erstellte Geometrie, Anzeigen und Tonfolgen. Sie enthalten keine kommerziellen Spiel-ROMs, extrahierten Code, Spielgeometrie, Bildschirmbilder, Musik oder Zustandsdateien.
Prüfergebnisse und Beispiele · C / BGM / HUD
| Profil | fps | Median / Maximum (PPU-Bilder) | Fristüberschreitungen / 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 projiziert Kamerakoordinaten ohne Kamerasubtraktion oder -rotation. Außerhalb Z=8..255 liefert es 0 und lässt die Ausgaben unverändert. X/Y werden auf ±120 begrenzt; Produkte der inversen Tiefentabelle werden vorzeichenbehaftet mit Abrundung durch 32 geteilt und danach auf den Bildschirm begrenzt. Dies ist kein geometrisches Abschneiden von Linien. Das allgemeine CGB ProjectPoint behält die Rotationsgrenzen ±220 auch bei Nullwinkeln.
Syntax
w3ddmg_u8 Wire3DDMG_ProjectCameraPoint(w3ddmg_i16 x,w3ddmg_i16 y,w3ddmg_i16 z,w3ddmg_u8* sx,w3ddmg_u8* sy);Parameter
xVorzeichenbehaftete 16-Bit-Kamerakoordinaten X/Y/Z. sx und sy müssen gültige beschreibbare u8-Zeiger sein.
yVorzeichenbehaftete 16-Bit-Kamerakoordinaten X/Y/Z. sx und sy müssen gültige beschreibbare u8-Zeiger sein.
zVorzeichenbehaftete 16-Bit-Kamerakoordinaten X/Y/Z. sx und sy müssen gültige beschreibbare u8-Zeiger sein.
sxVorzeichenbehaftete 16-Bit-Kamerakoordinaten X/Y/Z. sx und sy müssen gültige beschreibbare u8-Zeiger sein.
syVorzeichenbehaftete 16-Bit-Kamerakoordinaten X/Y/Z. sx und sy müssen gültige beschreibbare u8-Zeiger sein.
Rückgabewert
Liefert bei erfolgreicher Projektion 1, bei verworfener Tiefe 0. Ein Verwerfen lässt sx und sy unverändert.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Die Beispiele verwenden einen unabhängig erstellten bewegten Quader, eine Balkenanzeige und vier BGM-Töne. Die Bewegung nutzt verstrichene audio_vblank-Ticks; eine kurze sichere VBlank-Routine aktualisiert die Anzeige. Rufen Sie den Renderer mit gemeinsamem Zustand nie aus einer ISR auf. wire3d_audio_vblank.c legt die 80-Byte-Warteschlange in festen WRAM und Steuerfunktionen in ROM-Bank 5. Kompilieren Sie nicht zusätzlich audio_vblank.c. CGB-Beispiele nutzen WIRE3DCGB_STAGE_BANK2_ALLOCATION. Lesen Sie die Differenz eines 8-Bit-Ticks innerhalb von 255 Bildern.
Das Messwerkzeug zählt Marker nach abgeschlossenem Transfer und Anzeigenwechsel. PPU-Dots (4.194.304/s; 70.224/Bild) erfassen Löschen, Projektion, Rasterung, Transfer samt Anzeige und äußere Wartezeit. Berichtet werden Mittelwert, Median, größtes Intervall und überschrittene Fristen. Transfer samt Anzeige umfasst interne STAT/DMA/VBlank-Wartezeiten. Vergleichen Sie rohe CGB-CPU-Zyklen bei doppeltem Takt nicht direkt mit DMG. Gleiche mittlere fps belegen keine Einhaltung aller Fristen. Reale Hardware ist nicht geprüft.
Anwendungsbeispiel
#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.
}
}Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Sieben eigene Beispielkonfigurationen führten je 48 Transfers aus: 336 Stage/VRAM-Vergleiche und 84 Leerbilder zur Löschprüfung. Fünf Profile bestanden 25.700 Projektionsgrenzfälle. Fünf Rust-Builds beendeten ebenfalls 48 Bilder mit BGM-Ausgabe. Einige Intervalle überschreiten vier PPU-Bilder: Durchschnitts-fps beweisen keinen Betrieb ohne Verzögerung. Emulatorprüfung, keine Hardwareverifikation.
Vollständiges Beispielprogramm
Implementierung und Quelltext
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 projiziert Kamerakoordinaten ohne Kamerasubtraktion oder -rotation. Außerhalb Z=8..255 liefert es 0 und lässt die Ausgaben unverändert. X/Y werden auf ±120 begrenzt; Produkte der inversen Tiefentabelle werden vorzeichenbehaftet mit Abrundung durch 32 geteilt und danach auf den Bildschirm begrenzt. Dies ist kein geometrisches Abschneiden von Linien. Das allgemeine CGB ProjectPoint behält die Rotationsgrenzen ±220 auch bei Nullwinkeln.
Syntax
w3dcgb_u8 Wire3DCGB_ProjectCameraPoint(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_u8* sx, w3dcgb_u8* sy);Parameter
xVorzeichenbehaftete 16-Bit-Kamerakoordinaten X/Y/Z. sx und sy müssen gültige beschreibbare u8-Zeiger sein.
yVorzeichenbehaftete 16-Bit-Kamerakoordinaten X/Y/Z. sx und sy müssen gültige beschreibbare u8-Zeiger sein.
zVorzeichenbehaftete 16-Bit-Kamerakoordinaten X/Y/Z. sx und sy müssen gültige beschreibbare u8-Zeiger sein.
sxVorzeichenbehaftete 16-Bit-Kamerakoordinaten X/Y/Z. sx und sy müssen gültige beschreibbare u8-Zeiger sein.
syVorzeichenbehaftete 16-Bit-Kamerakoordinaten X/Y/Z. sx und sy müssen gültige beschreibbare u8-Zeiger sein.
Rückgabewert
Liefert bei erfolgreicher Projektion 1, bei verworfener Tiefe 0. Ein Verwerfen lässt sx und sy unverändert.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Die Beispiele verwenden einen unabhängig erstellten bewegten Quader, eine Balkenanzeige und vier BGM-Töne. Die Bewegung nutzt verstrichene audio_vblank-Ticks; eine kurze sichere VBlank-Routine aktualisiert die Anzeige. Rufen Sie den Renderer mit gemeinsamem Zustand nie aus einer ISR auf. wire3d_audio_vblank.c legt die 80-Byte-Warteschlange in festen WRAM und Steuerfunktionen in ROM-Bank 5. Kompilieren Sie nicht zusätzlich audio_vblank.c. CGB-Beispiele nutzen WIRE3DCGB_STAGE_BANK2_ALLOCATION. Lesen Sie die Differenz eines 8-Bit-Ticks innerhalb von 255 Bildern.
Das Messwerkzeug zählt Marker nach abgeschlossenem Transfer und Anzeigenwechsel. PPU-Dots (4.194.304/s; 70.224/Bild) erfassen Löschen, Projektion, Rasterung, Transfer samt Anzeige und äußere Wartezeit. Berichtet werden Mittelwert, Median, größtes Intervall und überschrittene Fristen. Transfer samt Anzeige umfasst interne STAT/DMA/VBlank-Wartezeiten. Vergleichen Sie rohe CGB-CPU-Zyklen bei doppeltem Takt nicht direkt mit DMG. Gleiche mittlere fps belegen keine Einhaltung aller Fristen. Reale Hardware ist nicht geprüft.
Anwendungsbeispiel
#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.
}
}Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Sieben eigene Beispielkonfigurationen führten je 48 Transfers aus: 336 Stage/VRAM-Vergleiche und 84 Leerbilder zur Löschprüfung. Fünf Profile bestanden 25.700 Projektionsgrenzfälle. Fünf Rust-Builds beendeten ebenfalls 48 Bilder mit BGM-Ausgabe. Einige Intervalle überschreiten vier PPU-Bilder: Durchschnitts-fps beweisen keinen Betrieb ohne Verzögerung. Emulatorprüfung, keine Hardwareverifikation.
Vollständiges Beispielprogramm
Implementierung und Quelltext
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 überspringt nur das anfängliche Warten auf einen neuen VBlank und verarbeitet BG-Warteschlange, Transfermodi und dirty-Historie. CGB EndFrameSparseNow arbeitet ebenfalls synchron. Now wartet weiterhin auf STAT-Zugriff, DMA-Ende und sichere Anzeige. DMG-Aktualisierungen sind nicht atomar. Beim CGB-sparse-Löschen zählen der aktuelle Bereich und der zwei Bilder alte Bereich der Zielbank. Niedrige CGB-Linienfunktionen brauchen dirty-Markierungen.
Syntax
void Wire3DDMG_EndFrameNow();Rückgabewert
Kein Rückgabewert; kehrt nach Transfer und erforderlicher Synchronisierung zurück.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Die Beispiele verwenden einen unabhängig erstellten bewegten Quader, eine Balkenanzeige und vier BGM-Töne. Die Bewegung nutzt verstrichene audio_vblank-Ticks; eine kurze sichere VBlank-Routine aktualisiert die Anzeige. Rufen Sie den Renderer mit gemeinsamem Zustand nie aus einer ISR auf. wire3d_audio_vblank.c legt die 80-Byte-Warteschlange in festen WRAM und Steuerfunktionen in ROM-Bank 5. Kompilieren Sie nicht zusätzlich audio_vblank.c. CGB-Beispiele nutzen WIRE3DCGB_STAGE_BANK2_ALLOCATION. Lesen Sie die Differenz eines 8-Bit-Ticks innerhalb von 255 Bildern.
Das Messwerkzeug zählt Marker nach abgeschlossenem Transfer und Anzeigenwechsel. PPU-Dots (4.194.304/s; 70.224/Bild) erfassen Löschen, Projektion, Rasterung, Transfer samt Anzeige und äußere Wartezeit. Berichtet werden Mittelwert, Median, größtes Intervall und überschrittene Fristen. Transfer samt Anzeige umfasst interne STAT/DMA/VBlank-Wartezeiten. Vergleichen Sie rohe CGB-CPU-Zyklen bei doppeltem Takt nicht direkt mit DMG. Gleiche mittlere fps belegen keine Einhaltung aller Fristen. Reale Hardware ist nicht geprüft.
Anwendungsbeispiel
#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();
}Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.
Erwartetes Ergebnis
Sieben eigene Beispielkonfigurationen führten je 48 Transfers aus: 336 Stage/VRAM-Vergleiche und 84 Leerbilder zur Löschprüfung. Fünf Profile bestanden 25.700 Projektionsgrenzfälle. Fünf Rust-Builds beendeten ebenfalls 48 Bilder mit BGM-Ausgabe. Einige Intervalle überschreiten vier PPU-Bilder: Durchschnitts-fps beweisen keinen Betrieb ohne Verzögerung. Emulatorprüfung, keine Hardwareverifikation.
Vollständiges Beispielprogramm
Implementierung und Quelltext
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 — Drahtgitterdarstellung für DMG
Verwendung der schnellen Renderingpfade
Bei Linien innerhalb des Darstellungsbereichs werden Zeichenadresse und Pixelbit schrittweise fortgeschrieben; verbleibende Pixelzahl und Fehlerwert bleiben in CPU-Registern. Dadurch entfallen Tile-Koordinatenberechnungen pro Pixel; zusätzliche Verbindungspixel schließen diagonale Übergänge. Bei aktivierter Verdeckung entscheiden fünf Abtastpunkte entlang der Linie, ob sie gezeichnet werden muss. Akzeptierte Linien verwenden denselben schnellen Pfad. Maskenzeilen werden byteweise gefüllt, wobei partielle Randbits erhalten bleiben. Flächenbegrenzungsrechtecke und Fünfpunktverwerfung sind Näherungen, keine pixelgenaue Dreiecks- oder Linienverdeckung. Drehungen um 0, 90, 180 und 270 Grad begrenzen zuerst die Eingaben und verwenden anschließend Koordinatentausch und Vorzeichenwechsel. Die Gesamtleistung hängt auch von Eckpunktzahl, Kantenlänge, Verdeckung und VRAM-Übertragungen ab. Messen Sie einzelne Operationen getrennt von der Zeit bis zum fertigen angezeigten Bild.
Monochromes 3D-Linienzeichnen. Übergeben Sie Modelleckpunkte, Kanten und Flächen sowie Objektposition, Rotation und Skalierung. Verwenden Sie Initialisierung, Frame-Beginn, Zeichnen und Übertragung in dieser Reihenfolge. Physik ist getrennt. Winkel haben sechzehn Schritte pro Umdrehung; Modellskalierung 256 bedeutet Originalgröße.
Vec3 enthält x/y/z, Edge die Eckpunktindizes a/b und Face die Dreiecksindizes a/b/c. vertices, edges und faces in Model zeigen auf diese Arrays; die jeweilige Anzahl gibt ihre Länge an. edge_faces enthält die Nachbarflächenindizes f0/f1, bei fehlender Fläche FACE_NONE. MODEL_HIDDEN_LINES in flags fordert flächenbasierte Kantenauswahl an. Die vorzeichenbehaftete projizierte Fläche bestimmt die Ausrichtung; die Eckpunktreihenfolge ist daher wichtig.
Object speichert Modellreferenz, Position x/y/z, Winkel rx/ry/rz, scale_q8 und visible. Objekte können ein Modell teilen; Zeichnen kopiert aber keine Tabellen und schaltet deren ROM-Bänke nicht automatisch um. Referenzierte Daten müssen während des gesamten Zeichnens lesbar bleiben. CGB-Object besitzt zusätzlich einen Farbindex.
Model für Höhe 96 enthält außerdem edge_masks und edge_mask_count. Übergeben Sie eine RAM-Tabelle mit 16-Bit-Kantenmasken, die nach Objekt-Gierwinkel gewählt werden, oder setzen Sie beide Felder bei Nichtgebrauch auf null.
Wire3DDMG_BeginFrame
Beginnt das Zeichnen eines Frames und deaktiviert die Verdeckungsprüfung.
Syntax
void Wire3DDMG_BeginFrame();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_BeginFrame(); Löscht vorbereitete Pixel und Verdeckungsmaske und deaktiviert die Verdeckungsfilterung. Angezeigter VRAM-Frame und ausstehende BG-Tile-Warteschlange bleiben unverändert. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_BeginFrame(); Deaktiviert nur die Verdeckungsfilterung. Staging wird normalerweise während der Übertragung gelöscht; Init liefert den ersten leeren Bereich. Verwirft keinen ungesendeten Frame, löscht keine Maske und setzt weder ausstehende BG-Schreibzugriffe noch Änderungsflags zurück.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
WIRE3D_DMG_HEIGHT ist standardmäßig 120. Verwenden Sie für Höhe 96 wire3d_dmg_96.c. SelectEdgeMask ist bei Höhe 96 verfügbar; RotatePoint, DrawIndexedEdges, Übertragungsfreigaben und direkte Übertragungen benötigen Höhe 120.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet ein ganzzahlig skaliertes Linienmodell aus Eckpunkten und Zwei-Byte-Kantenindexpaaren.
Syntax
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);Parameter
verticesArray von 3D-Eckpunkten.
vertex_countAnzahl der Einträge im Eckpunktarray.
edgesEckpunktindizes je Kante im deklarierten Struct- oder Bytepaar-Format.
edge_countAnzahl der Kanten.
xX-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
yY-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
zZ-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
scaleGanzzahlige Skalierung; null wird als eins behandelt.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
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); Zeichnet per Bytepaar indizierte Kanten nach ganzzahliger Skalierung und Verschiebung; Skalierung null bedeutet eins, ohne Objektrotation oder Flächenfilterung. Projiziert höchstens 24 Eckpunkte. Übergeben Sie höchstens 128 Kantenpaare, da Byte-Offsets nach 255 umbrechen. Ungültige Eckpunkt-IDs und tiefenbedingt verworfene Endpunkte werden übersprungen; Nullarrays werden ignoriert. Koordinatenprodukte und -summen müssen als s16 darstellbar sein.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
WIRE3D_DMG_HEIGHT ist standardmäßig 120. Verwenden Sie für Höhe 96 wire3d_dmg_96.c. SelectEdgeMask ist bei Höhe 96 verfügbar; RotatePoint, DrawIndexedEdges, Übertragungsfreigaben und direkte Übertragungen benötigen Höhe 120.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Eine projizierte waagerechte Linie und ein zusätzlicher 8×8-Block zeigen direkte Übertragungen; ein Quellbyte wechselt beim Verbrauch von 255 auf 0.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet eine vierfach zusammenhängende Bildschirmlinie einschließlich Endpunkten in den Staging-Bereich.
Syntax
void Wire3DDMG_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by);Parameter
axX-Koordinate von Eckpunkt A in Viewport-Pixeln.
ayY-Koordinate von Eckpunkt A in Viewport-Pixeln.
bxX-Koordinate von Eckpunkt B in Viewport-Pixeln.
byY-Koordinate von Eckpunkt B in Viewport-Pixeln.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by); Zeichnet eine zusammenhängende Linie einschließlich Endpunkten in den 128×96-Staging-Bereich. Während DrawScene wird die grobe Verdeckungsverwerfung mit fünf Abtastpunkten verwendet, sonst direkt gezeichnet. Verwenden Sie Viewport-Koordinaten. Nur EndFrame aktualisiert VRAM. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by); Bei aktivierter Änderungsübertragung wird das umschließende Tile-Rechteck markiert und danach eine zusammenhängende Staging-Linie gezeichnet. Szenenzeichnen kann sie anhand von fünf Maskenabtastungen verwerfen. Geben Sie Endpunkte im 128×120-Viewport an; niedrige Pixelgrenzprüfungen schneiden das Segment nicht geometrisch zu.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
WIRE3D_DMG_HEIGHT ist standardmäßig 120. Verwenden Sie für Höhe 96 wire3d_dmg_96.c. SelectEdgeMask ist bei Höhe 96 verfügbar; RotatePoint, DrawIndexedEdges, Übertragungsfreigaben und direkte Übertragungen benötigen Höhe 120.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Projiziert zwei Weltendpunkte und zeichnet eine Linie dazwischen.
Syntax
void Wire3DDMG_DrawLine3D(w3ddmg_i16 ax, w3ddmg_i16 ay, w3ddmg_i16 az, w3ddmg_i16 bx, w3ddmg_i16 by, w3ddmg_i16 bz);Parameter
axX-Komponente des Startpunkts in Weltkoordinaten.
ayY-Komponente des Startpunkts in Weltkoordinaten.
azZ-Komponente des Startpunkts in Weltkoordinaten.
bxX-Komponente des Endpunkts in Weltkoordinaten.
byY-Komponente des Endpunkts in Weltkoordinaten.
bzZ-Komponente des Endpunkts in Weltkoordinaten.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
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); Projiziert beide Weltendpunkte und zeichnet nur, wenn beide den Tiefenbereich bestehen. Bildet keine Schnittpunkte eines kreuzenden Segments mit Nah- oder Fernebene; projizierte Endpunkte werden einzeln auf die Bildschirmränder begrenzt. 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); Projiziert beide Weltendpunkte und zeichnet nur, wenn beide den Tiefenbereich bestehen. Bildet keine Schnittpunkte eines kreuzenden Segments mit Nah- oder Fernebene; projizierte Endpunkte werden einzeln auf die Bildschirmränder begrenzt.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
WIRE3D_DMG_HEIGHT ist standardmäßig 120. Verwenden Sie für Höhe 96 wire3d_dmg_96.c. SelectEdgeMask ist bei Höhe 96 verfügbar; RotatePoint, DrawIndexedEdges, Übertragungsfreigaben und direkte Übertragungen benötigen Höhe 120.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet ein Eckpunkt-Kanten-Modell an der gewünschten Position und mit der gewünschten Rotation in Originalgröße.
Syntax
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);Parameter
modelModell mit Arrays und Anzahlen für Eckpunkte, Kanten und Flächen; seine Tabellen müssen während des Aufrufs lesbar bleiben.
xX-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
yY-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
zZ-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
rxDrehung um X; sechzehn Schritte ergeben eine volle Umdrehung.
ryDrehung um Y; sechzehn Schritte ergeben eine volle Umdrehung.
rzDrehung um Z; sechzehn Schritte ergeben eine volle Umdrehung.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
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); Zeichnet ein unskaliertes Modell, indem DrawModelScaled mit Skalierung 256 aufgerufen wird. 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); Zeichnet ein unskaliertes Modell, indem DrawModelScaled mit Skalierung 256 aufgerufen wird.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
WIRE3D_DMG_HEIGHT ist standardmäßig 120. Verwenden Sie für Höhe 96 wire3d_dmg_96.c. SelectEdgeMask ist bei Höhe 96 verfügbar; RotatePoint, DrawIndexedEdges, Übertragungsfreigaben und direkte Übertragungen benötigen Höhe 120.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Modelle in Originalgröße und halber Größe erscheinen über einer Szene aus einem Objektarray mit denselben Skalierungen und zeigen Projektion und Skalierung.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Skaliert ein Modell, dreht es in Y/X/Z-Reihenfolge, verschiebt und projiziert seine Eckpunkte und zeichnet die Kanten.
Syntax
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);Parameter
modelModell mit Arrays und Anzahlen für Eckpunkte, Kanten und Flächen; seine Tabellen müssen während des Aufrufs lesbar bleiben.
xX-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
yY-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
zZ-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
rxDrehung um X; sechzehn Schritte ergeben eine volle Umdrehung.
ryDrehung um Y; sechzehn Schritte ergeben eine volle Umdrehung.
rzDrehung um Z; sechzehn Schritte ergeben eine volle Umdrehung.
scale_q8Skalierung mit 256 als Einheit; nichtpositive Werte bedeuten ebenfalls Originalgröße.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
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); Skaliert bis zu 24 Eckpunkte, dreht sie in Y/X/Z-Reihenfolge, verschiebt und projiziert sie; zeichnet danach bis zu 16 Kanten, gefiltert durch Giermasken und optional nach vorn gerichtete Flächen. Nichtpositive Skalierung wird zur Einheit (256). Nullzeiger für Modell, Eckpunkte oder Kanten werden ignoriert; referenzierte Tabellen müssen lesbar bleiben. Skalierungsprodukte und Verschiebungen müssen in den vorzeichenbehafteten 16-Bit-Bereich passen. Kanten über Tiefengrenzen werden verworfen, nicht zugeschnitten. 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); Skaliert bis zu 24 Eckpunkte, dreht Y/X/Z, verschiebt und projiziert sie und durchläuft dann alle edge_count-Einträge mit optionaler Nachbarflächenfilterung. edge_count ist ein Byte-Zähler. Der Flächen-Arbeitspuffer ist auf 16 begrenzt; Kantentabellen müssen alle deklarierten Einträge enthalten. Nichtpositive Skalierung bedeutet 256. Nullzeiger für Modell, Eckpunkte oder Kanten werden ignoriert. Produkte und Verschiebungen müssen in vorzeichenbehaftete 16 Bit passen; Kanten über Tiefengrenzen werden verworfen.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
WIRE3D_DMG_HEIGHT ist standardmäßig 120. Verwenden Sie für Höhe 96 wire3d_dmg_96.c. SelectEdgeMask ist bei Höhe 96 verfügbar; RotatePoint, DrawIndexedEdges, Übertragungsfreigaben und direkte Übertragungen benötigen Höhe 120.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Modelle in Originalgröße und halber Größe erscheinen über einer Szene aus einem Objektarray mit denselben Skalierungen und zeigen Projektion und Skalierung.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Zeichnet bis zu acht Objekte von nah nach fern; nähere Flächen verdecken spätere Kanten.
Syntax
void Wire3DDMG_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count);Parameter
objectsObjektarray mit Positionen, Rotationen, Skalierungen und Sichtbarkeitsflags.
countAnzahl der übergebenen Arrayeinträge; beachten Sie die Verarbeitungsgrenze der jeweiligen Operation.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count); Verarbeitet höchstens die ersten acht Objekte, nach transformierter Ursprungstiefe von nah nach fern sortiert. Zeichnet sichtbare gültige Modelle und markiert anschließend die Begrenzungsrechtecke ihrer Vorderseiten, um spätere Linien zu verwerfen, deren sämtliche Abtastpunkte verdeckt sind. Dies nähert Verdeckung zwischen Objekten an und ist kein Tiefenpuffer. Löscht die eigene Maske, erhält aber vorhandene Staging-Pixel. Nullarrays werden ignoriert; Objekte und Daten müssen lesbar bleiben. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count); Sortiert bis zu acht Objektursprünge nach Kameratiefe von nah nach fern. Zeichnet sichtbare gültige Modelle und markiert Vorderseiten-Begrenzungsrechtecke für spätere Objekte. Der erste sortierte Platz überspringt Maskentests; der letzte benötigt keinen neuen Verdeckungsbereich. Dies ist grobes Linienverwerfen, kein Tiefenpuffer. Null oder leere Eingaben werden ignoriert; Aufruferdaten und aktueller Projektionscache müssen während des Durchlaufs gültig bleiben.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
WIRE3D_DMG_HEIGHT ist standardmäßig 120. Verwenden Sie für Höhe 96 wire3d_dmg_96.c. SelectEdgeMask ist bei Höhe 96 verfügbar; RotatePoint, DrawIndexedEdges, Übertragungsfreigaben und direkte Übertragungen benötigen Höhe 120.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Modelle in Originalgröße und halber Größe erscheinen über einer Szene aus einem Objektarray mit denselben Skalierungen und zeigen Projektion und Skalierung.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Übergibt ausstehende Hintergrund-Schreibzugriffe und vorbereitete Zeichnungen an VRAM.
Syntax
void Wire3DDMG_EndFrame();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_EndFrame(); Wartet auf den nächsten VBlank, führt ausstehende BG-Kartenschreibzugriffe aus und kopiert Staging unter Abfrage der Zugriffsfenster ins VRAM. Das Kopieren verbraucht die vorbereiteten Pixel. Die Übertragung kann über VBlank hinausgehen; dies ist kein atomarer Frame-Wechsel. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_EndFrame(); Wartet auf den nächsten VBlank und führt BG-Schreibzugriffe aus. Verbraucht dann optional zuerst die Hilfsstreifen, bevor geänderte Tiles oder das gesamte Haupt-Staging übertragen werden. Wegen überlappender Hilfs- und Hauptquellen ist diese Reihenfolge wichtig. STAT wird über Zugriffsfenster hinweg weiter abgefragt; die Aktualisierung muss nicht in einen VBlank passen.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
WIRE3D_DMG_HEIGHT ist standardmäßig 120. Verwenden Sie für Höhe 96 wire3d_dmg_96.c. SelectEdgeMask ist bei Höhe 96 verfügbar; RotatePoint, DrawIndexedEdges, Übertragungsfreigaben und direkte Übertragungen benötigen Höhe 120.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Projiziert nach vorn gerichtete Modelldreiecke und löscht vorbereitete Pixel in ihrem Inneren.
Syntax
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);Parameter
modelModell mit Arrays und Anzahlen für Eckpunkte, Kanten und Flächen; seine Tabellen müssen während des Aufrufs lesbar bleiben.
xX-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
yY-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
zZ-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
rxDrehung um X; sechzehn Schritte ergeben eine volle Umdrehung.
ryDrehung um Y; sechzehn Schritte ergeben eine volle Umdrehung.
rzDrehung um Z; sechzehn Schritte ergeben eine volle Umdrehung.
scale_q8Skalierung mit 256 als Einheit; nichtpositive Werte bedeuten ebenfalls Originalgröße.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
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); Projiziert bis zu 24 Eckpunkte und löscht das Innere nach vorn gerichteter Dreiecke aus dem Staging-Bereich für ein Modell mit Verdeckungsflags und Flächendaten. Nichtpositive Skalierung bedeutet 256, also Originalgröße. Bis zu 16 Flächen werden betrachtet; Flächen über Tiefengrenzen werden übersprungen. Ersetzt auch gemeinsame Projektionscaches, aktualisiert aber kein 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); Projiziert bis zu 24 Eckpunkte und löscht das Innere nach vorn gerichteter Dreiecke aus dem Staging-Bereich für ein Modell mit Verdeckungsflags und Flächendaten. Nichtpositive Skalierung bedeutet 256, also Originalgröße. Bis zu 16 Flächen werden betrachtet; Flächen über Tiefengrenzen werden übersprungen. Ersetzt auch gemeinsame Projektionscaches, aktualisiert aber kein VRAM.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
WIRE3D_DMG_HEIGHT ist standardmäßig 120. Verwenden Sie für Höhe 96 wire3d_dmg_96.c. SelectEdgeMask ist bei Höhe 96 verfügbar; RotatePoint, DrawIndexedEdges, Übertragungsfreigaben und direkte Übertragungen benötigen Höhe 120.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Projizierte Flächen löschen einen gefüllten Bereich, sodass erhaltene und gelöschte Bereiche sichtbar werden.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Löscht einen waagerechten Span einschließlich Endpunkten in einer vorbereiteten Zeile.
Syntax
void Wire3DDMG_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1);Parameter
yPixel-Y-Koordinate der zu löschenden Zeile.
x0Unterer X-Endpunkt in Viewport-Pixeln; Reihenfolge und Begrenzung richten sich nach den Hinweisen zu dieser Operation.
x1Oberer X-Endpunkt in Viewport-Pixeln; Reihenfolge und Begrenzung richten sich nach den Hinweisen zu dieser Operation.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1); Ordnet die X-Endpunkte und löscht den vorbereiteten Span einschließlich Endpunkten. Beide müssen in 0..127 liegen; ungültiges Y wird ignoriert. Die Routine begrenzt X nicht automatisch. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1); Ordnet die X-Endpunkte und löscht den vorbereiteten Span einschließlich Endpunkten. Beide müssen in 0..127 liegen; ungültiges Y wird ignoriert. Die Routine begrenzt X nicht automatisch.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
WIRE3D_DMG_HEIGHT ist standardmäßig 120. Verwenden Sie für Höhe 96 wire3d_dmg_96.c. SelectEdgeMask ist bei Höhe 96 verfügbar; RotatePoint, DrawIndexedEdges, Übertragungsfreigaben und direkte Übertragungen benötigen Höhe 120.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Löscht ein Bildschirmdreieck über waagerechte Rasterzeilen-Spans aus dem Staging-Bereich.
Syntax
void Wire3DDMG_EraseTriangle2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by, w3ddmg_u8 cx, w3ddmg_u8 cy);Parameter
axX-Koordinate von Eckpunkt A in Viewport-Pixeln.
ayY-Koordinate von Eckpunkt A in Viewport-Pixeln.
bxX-Koordinate von Eckpunkt B in Viewport-Pixeln.
byY-Koordinate von Eckpunkt B in Viewport-Pixeln.
cxX-Koordinate von Eckpunkt C in Viewport-Pixeln.
cyY-Koordinate von Eckpunkt C in Viewport-Pixeln.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
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); Löscht ein Dreieck aus vorbereiteten Pixeln über ganzzahlige Rasterzeilenschnittpunkte. Geben Sie Viewport-Koordinaten an. Entartete Dreiecke werden ignoriert; Verdeckungsmaske und VRAM bleiben unverändert. 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); Löscht ein Dreieck aus vorbereiteten Pixeln über ganzzahlige Rasterzeilenschnittpunkte. Geben Sie Viewport-Koordinaten an. Entartete Dreiecke werden ignoriert; Verdeckungsmaske und VRAM bleiben unverändert.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
WIRE3D_DMG_HEIGHT ist standardmäßig 120. Verwenden Sie für Höhe 96 wire3d_dmg_96.c. SelectEdgeMask ist bei Höhe 96 verfügbar; RotatePoint, DrawIndexedEdges, Übertragungsfreigaben und direkte Übertragungen benötigen Höhe 120.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Projizierte Flächen löschen einen gefüllten Bereich, sodass erhaltene und gelöschte Bereiche sichtbar werden.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Initialisiert LCD, Tiles und Hintergrundkarte für einen monochromen Drahtgitter-Viewport.
Syntax
void Wire3DDMG_Init();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_Init(); Übernimmt das LCD: Wartet auf VBlank, schaltet es aus, löscht 6144 Tile-Bytes und die BG-Karte, richtet HUD-Tiles und den 128×96-Viewport mit vorzeichenbehafteten Tile-Nummern ein und aktiviert BG mit Scrollwerten null und BGP=0xB4. Setzt Kamera, BG-Warteschlange und Staging-Bereich zurück. Reservieren Sie 0xD000..0xDFFF für Staging und erhalten Sie dessen WRAM-Bankeinblendung. Rufen Sie vor dem Zeichnen BeginFrame auf, um auch den Verdeckungszustand zu initialisieren. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_Init(); Übernimmt den LCD-Zustand, löscht Tile-VRAM und BG-Karte und richtet einen 16×15-Viewport ab Kartentile (3,1) ein. Setzt Scrolling (8,0), BGP=0xB4 und BG-Anzeige. Setzt Kamera, Warteschlangen, Übertragungsmodi, beide Änderungstabellen und Staging zurück. Reservieren Sie 0xD000..0xDFFF und erhalten Sie die WRAM-Einblendung; Hilfsspeicher verwendet dieselben Adressen. Rufen Sie vor dem Zeichnen BeginFrame auf, um den Verdeckungszustand herzustellen.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
WIRE3D_DMG_HEIGHT ist standardmäßig 120. Verwenden Sie für Höhe 96 wire3d_dmg_96.c. SelectEdgeMask ist bei Höhe 96 verfügbar; RotatePoint, DrawIndexedEdges, Übertragungsfreigaben und direkte Übertragungen benötigen Höhe 120.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Projiziert einen Weltpunkt durch die Kamera in Viewport-Koordinaten.
Syntax
w3ddmg_u8 Wire3DDMG_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy);Parameter
xX-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
yY-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
zZ-Komponente des Punkts oder Objektursprungs in Weltkoordinaten.
sxGültiger beschreibbarer u8-Zeiger für die projizierte X-Koordinate.
syGültiger beschreibbarer u8-Zeiger für die projizierte Y-Koordinate.
Rückgabewert
Liefert 1 bei erfolgreicher Projektion oder 0 bei verworfener Tiefe.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96 w3ddmg_u8 Wire3DDMG_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy); Projiziert einen Weltpunkt mit der aktuellen Kamera. Verworfene Tiefe liefert null und lässt die Ausgabe unverändert; bei Erfolg werden auf 128×96 begrenzte Koordinaten geschrieben. Ausgabezeiger müssen gültig sein. Bildschirmbegrenzung ist kein geometrisches Clipping. WIRE3D_DMG_HEIGHT = 120 w3ddmg_u8 Wire3DDMG_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy); Projiziert einen Weltpunkt mit der aktuellen Kamera. Ungültige Tiefe liefert null ohne Ausgabeänderung; bei Erfolg werden auf 128×120 begrenzte Koordinaten geschrieben. Beide Ausgabezeiger müssen gültig sein. Koordinatendifferenzen müssen in s16 passen.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
WIRE3D_DMG_HEIGHT ist standardmäßig 120. Verwenden Sie für Höhe 96 wire3d_dmg_96.c. SelectEdgeMask ist bei Höhe 96 verfügbar; RotatePoint, DrawIndexedEdges, Übertragungsfreigaben und direkte Übertragungen benötigen Höhe 120.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Reiht einen Tile-Nummer-Schreibzugriff für eine Hintergrundkartenzelle ein.
Syntax
void Wire3DDMG_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile);Parameter
xX-Tile-Koordinate in der 32×32-Hintergrundkarte.
yY-Tile-Koordinate in der 32×32-Hintergrundkarte.
tileAcht-Bit-Tile-Nummer für die Hintergrundzelle.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile); Reiht einen Tile-Schreibzugriff auf die 32×32-Karte bei 0x9800 für EndFrame ein. Ungültige Kartenkoordinaten und Anfragen über 48 ausstehende Schreibzugriffe hinaus werden ohne Meldung ignoriert. Diese Warteschlange ist von der allgemeinen vram-Bibliothekswarteschlange getrennt. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile); Reiht einen Tile-Schreibzugriff auf die 32×32-Karte bei 0x9800 für EndFrame ein. Ungültige Kartenkoordinaten und Anfragen über 48 ausstehende Schreibzugriffe hinaus werden ohne Meldung ignoriert. Diese Warteschlange ist von der allgemeinen vram-Bibliothekswarteschlange getrennt.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
WIRE3D_DMG_HEIGHT ist standardmäßig 120. Verwenden Sie für Höhe 96 wire3d_dmg_96.c. SelectEdgeMask ist bei Höhe 96 verfügbar; RotatePoint, DrawIndexedEdges, Übertragungsfreigaben und direkte Übertragungen benötigen Höhe 120.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Dreht einen Punkt mit den angegebenen Winkeln direkt in seinen Variablen.
Syntax
void Wire3DDMG_RotatePoint(w3ddmg_i16* x, w3ddmg_i16* y, w3ddmg_i16* z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz);Parameter
xSeparater beschreibbarer s16-Zeiger für die X-Komponente.
ySeparater beschreibbarer s16-Zeiger für die Y-Komponente.
zSeparater beschreibbarer s16-Zeiger für die Z-Komponente.
rxDrehung um X; sechzehn Schritte ergeben eine volle Umdrehung.
ryDrehung um Y; sechzehn Schritte ergeben eine volle Umdrehung.
rzDrehung um Z; sechzehn Schritte ergeben eine volle Umdrehung.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
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); Dreht direkt in den Variablen in Y/X/Z-Reihenfolge mit 16 Schritten pro Umdrehung. Ein Nullzeiger für eine Komponente macht den gesamten Aufruf wirkungslos; verwenden Sie getrennte Zeiger. Jede Achsrotation begrenzt ihre Eingaben auf ±220.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
WIRE3D_DMG_HEIGHT ist standardmäßig 120. Verwenden Sie für Höhe 96 wire3d_dmg_96.c. SelectEdgeMask ist bei Höhe 96 verfügbar; RotatePoint, DrawIndexedEdges, Übertragungsfreigaben und direkte Übertragungen benötigen Höhe 120.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Modelle in Originalgröße und halber Größe erscheinen über einer Szene aus einem Objektarray mit denselben Skalierungen und zeigen Projektion und Skalierung.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Wählt eine vorberechnete Kantensichtbarkeitsmaske für den Gierwinkel des Objekts.
Syntax
w3ddmg_u16 Wire3DDMG_SelectEdgeMask(const Wire3DDMG_Model* model, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz);Parameter
modelModell mit Arrays und Anzahlen für Eckpunkte, Kanten und Flächen; seine Tabellen müssen während des Aufrufs lesbar bleiben.
rxDrehung um X; sechzehn Schritte ergeben eine volle Umdrehung.
ryDrehung um Y; sechzehn Schritte ergeben eine volle Umdrehung.
rzDrehung um Z; sechzehn Schritte ergeben eine volle Umdrehung.
Rückgabewert
16-Bit-Kantensichtbarkeitsmaske oder 0xFFFF, wenn keine Tabelle übergeben wurde.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96 w3ddmg_u16 Wire3DDMG_SelectEdgeMask(const Wire3DDMG_Model* model, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz); Wählt eine vorberechnete Maske aus den unteren vier Bits des Objekt-Gierwinkels; Nicken, Rollen und Kameraausrichtung werden ignoriert. Verwenden Sie 16, 8, 4 oder 2 Bereiche; andere positive Anzahlen wählen Eintrag null, wobei Anzahlen >=16 die ersten 16 verwenden. Fehlende Daten liefern 0xFFFF. Die Maskentabelle muss über die aktuelle Datenzeigereinblendung lesbar bleiben.
Dieses Beispiel verwendet das 128×96-Profil; sein Viewport beginnt auf dem Bildschirm bei (0,0). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
WIRE3D_DMG_HEIGHT ist standardmäßig 120. Verwenden Sie für Höhe 96 wire3d_dmg_96.c. SelectEdgeMask ist bei Höhe 96 verfügbar; RotatePoint, DrawIndexedEdges, Übertragungsfreigaben und direkte Übertragungen benötigen Höhe 120.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Modelle in Originalgröße und halber Größe erscheinen über einer Szene aus einem Objektarray mit denselben Skalierungen und zeigen Projektion und Skalierung.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Wählt, ob EndFrame auch die Hilfsstreifen überträgt.
Syntax
void Wire3DDMG_SetAuxTransfer(w3ddmg_u8 flag);Parameter
flagNull deaktiviert die Übertragungsfunktion; jeder andere Wert aktiviert sie.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_SetAuxTransfer(w3ddmg_u8 flag); Speichert die Hilfsübertragungsfreigabe für EndFrame; jeder Wert ungleich null aktiviert sie. Hier werden keine Daten kopiert oder gelöscht. Hilfsquellbytes teilen sich die Adressen mit dem Haupt-Staging-Bereich.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
WIRE3D_DMG_HEIGHT ist standardmäßig 120. Verwenden Sie für Höhe 96 wire3d_dmg_96.c. SelectEdgeMask ist bei Höhe 96 verfügbar; RotatePoint, DrawIndexedEdges, Übertragungsfreigaben und direkte Übertragungen benötigen Höhe 120.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Die Hilfsübertragung verbraucht einen Teil des Haupt-Staging-Bereichs; dadurch entsteht bei Bildschirmkoordinate (80,24) ein schwarzer 8×8-Block.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Speichert Kameraposition und -ausrichtung für spätere Projektionen.
Syntax
void Wire3DDMG_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 pitch, w3ddmg_u8 yaw, w3ddmg_u8 roll);Parameter
xX-Komponente der Kamera in Weltkoordinaten.
yY-Komponente der Kamera in Weltkoordinaten.
zZ-Komponente der Kamera in Weltkoordinaten.
pitchDrehung um X; sechzehn Schritte ergeben eine volle Umdrehung.
yawDrehung um Y; sechzehn Schritte ergeben eine volle Umdrehung.
rollDrehung um Z; sechzehn Schritte ergeben eine volle Umdrehung.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
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); Speichert Kameraposition und -winkel für späteres Zeichnen; 16 Winkelschritte ergeben eine Umdrehung. Vorhandene Zeichnungen werden nicht neu projiziert und Eingabebereiche nicht geprüft. 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); Speichert Kameraposition und -winkel für späteres Zeichnen; 16 Winkelschritte ergeben eine Umdrehung. Vorhandene Zeichnungen werden nicht neu projiziert und Eingabebereiche nicht geprüft.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
WIRE3D_DMG_HEIGHT ist standardmäßig 120. Verwenden Sie für Höhe 96 wire3d_dmg_96.c. SelectEdgeMask ist bei Höhe 96 verfügbar; RotatePoint, DrawIndexedEdges, Übertragungsfreigaben und direkte Übertragungen benötigen Höhe 120.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Wählt die Übertragung geänderter Tiles für den Haupt-Viewport mit 120 Zeilen.
Syntax
void Wire3DDMG_SetDirtyTransfer(w3ddmg_u8 flag);Parameter
flagNull deaktiviert die Übertragungsfunktion; jeder andere Wert aktiviert sie.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_SetDirtyTransfer(w3ddmg_u8 flag); Speichert die Freigabe für Änderungsübertragung und löscht beide Änderungsverläufe sowie den Haupt-Staging-Bereich, selbst bei unverändertem Wert. VRAM bleibt erhalten; beim Aktivieren über einem alten Bild können unmarkierte alte Tiles zurückbleiben. Sorgen Sie daher für einen sauberen angezeigten Ausgangszustand.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
WIRE3D_DMG_HEIGHT ist standardmäßig 120. Verwenden Sie für Höhe 96 wire3d_dmg_96.c. SelectEdgeMask ist bei Höhe 96 verfügbar; RotatePoint, DrawIndexedEdges, Übertragungsfreigaben und direkte Übertragungen benötigen Höhe 120.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Der vorherige Rahmen links oben verschwindet; nur ein neuer Rahmen bei Bildschirmkoordinaten (96,88)..(120,112) bleibt.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Schreibt die Zuordnung der vier Helligkeitsstufen ins monochrome Hintergrund-Palettenregister BGP.
Syntax
void Wire3DDMG_SetPalette(w3ddmg_u8 bgp);Parameter
bgpBGP-Registerwert mit vier Zwei-Bit-Helligkeitszuordnungen.
Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_SetPalette(w3ddmg_u8 bgp); Schreibt die rohe DMG-BGP-Palettencodierung sofort, ohne Frame-Synchronisierung. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_SetPalette(w3ddmg_u8 bgp); Schreibt die rohe DMG-BGP-Palettencodierung sofort, ohne Frame-Synchronisierung.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
WIRE3D_DMG_HEIGHT ist standardmäßig 120. Verwenden Sie für Höhe 96 wire3d_dmg_96.c. SelectEdgeMask ist bei Höhe 96 verfügbar; RotatePoint, DrawIndexedEdges, Übertragungsfreigaben und direkte Übertragungen benötigen Höhe 120.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Dieses Beispiel zeigt Linien, Punkte, Löschen und Projektion in einem Frame. Die Mitte der oberen Kante des Rahmens links oben wird gelöscht; nahe der Bildmitte wird eine Diagonale projiziert. Eine verworfene Projektion erhält die Ausgabewerte 91 und 92.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Überträgt sechs Hilfsstreifen sofort und löscht ihre Quellbytes.
Syntax
void Wire3DDMG_TransferAuxNow();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_TransferAuxNow(); Überträgt und verbraucht die Hilfsquellstreifen sofort, unabhängig von der Hilfsfreigabe. Wartet nicht auf den VBlank-Start und aktualisiert weder Änderungsverlauf noch BG-Warteschlange. Die Quelle überlappt den Haupt-Staging-Bereich; stimmen Sie die Übertragungen aufeinander ab.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
WIRE3D_DMG_HEIGHT ist standardmäßig 120. Verwenden Sie für Höhe 96 wire3d_dmg_96.c. SelectEdgeMask ist bei Höhe 96 verfügbar; RotatePoint, DrawIndexedEdges, Übertragungsfreigaben und direkte Übertragungen benötigen Höhe 120.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Eine projizierte waagerechte Linie und ein zusätzlicher 8×8-Block zeigen direkte Übertragungen; ein Quellbyte wechselt beim Verbrauch von 255 auf 0.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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
Überträgt den gesamten Haupt-Staging-Bereich sofort und löscht die verbrauchten Quellpixel.
Syntax
void Wire3DDMG_TransferMainNow();Rückgabewert
Kein Rückgabewert; geänderter Zustand und Anzeige-Timing sind oben beschrieben.
Bedingungen und Grenzen
WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_TransferMainNow(); Überträgt und verbraucht den gesamten Haupt-Staging-Bereich sofort, fragt dabei STAT ab, wartet aber nicht auf den nächsten VBlank. Ignoriert Übertragungsfreigaben und erhält Änderungsverläufe sowie BG-Tile-Warteschlange; der Aufrufer koordiniert den Frame-Ablauf.
Dieses Beispiel verwendet das 128×120-Profil; sein Viewport beginnt auf dem Bildschirm bei (16,8). Reservieren Sie WRAM D000..DFFF und halten Sie dessen Bankeinblendung auch auf CGB stabil. Der gemeinsame Zustand ist nicht reentrant.
WIRE3D_DMG_HEIGHT ist standardmäßig 120. Verwenden Sie für Höhe 96 wire3d_dmg_96.c. SelectEdgeMask ist bei Höhe 96 verfügbar; RotatePoint, DrawIndexedEdges, Übertragungsfreigaben und direkte Übertragungen benötigen Höhe 120.
WIRE3D_DMG_HEIGHT erlaubt 88, 96 oder 120; WIRE3DCGB_HEIGHT erlaubt 88 oder 96. Die Vorgaben bleiben DMG 120 und CGB 96. Das 88-Zeilen-Profil hat 128×88 Pixel mit Mittelpunkt Y=44. Bibliothek und Aufrufer benötigen denselben Wert; kompilieren Sie wire3d_dmg_88.c / wire3d_cgb_88.c statt des normalen Einstiegspunkts. DMG 88 verwendet die Modellstruktur des 96-Zeilen-Profils und dessen Grenze von 16 Kanten. CGB 160×144 bleibt unverändert.
Anwendungsbeispiel
#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) {}
}Erwartetes Ergebnis
Eine projizierte waagerechte Linie und ein zusätzlicher 8×8-Block zeigen direkte Übertragungen; ein Quellbyte wechselt beim Verbrauch von 255 auf 0.
Vollständiges Beispielprogramm
Build-Befehl
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-disasmImplementierung und Quelltext
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();
}Strukturen, Konstanten und vollständige Header
Diese Header enthalten auch Makros ohne Funktionsform, Strukturen, Arraygrenzen, Aufzählungen und Aliase. Sie geben die erfassten Quellen einschließlich der ursprünglichen Kommentare unverändert wieder.
asset.h — Ressourcen-IDs und Datenbeschreibungen
#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 — Musik, Soundeffekte und Audiosteuerung
#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 — Musikwiedergabe im VBlank-Interrupt
#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 — Bankabhängiger Zugriff auf Code und Daten
#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 — Weltkoordinaten und sichtbare Bereiche
#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-Paletten für BG und 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-Kachelnummern und -attribute
#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 — Ringpuffer für Positionsverläufe
#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 — Geschosspools, Fächermuster, Treffer und Streiferkennung
#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-Protokolle und Zusicherungen
#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 — Monochrome Drahtgitterdarstellung mit 128×120 Pixeln für 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 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 — Objektpools mit festen Arrays
#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-Festkommaarithmetik und Rechtecke
#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 — Tastenzustand, Drücken, Loslassen und Wiederholung
#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 — Serielle Kommunikation und logische Pakete
#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-Kommunikation mit externem Takt
#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-Bewegung und Kollisionen
#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 — Kreisphysik
#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 — Physik für achsenparallele 3D-Quader
#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 — Scrolltabellen für Bildstreifen und Bildschirmzeilen
#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 — Zufallszahlen, Text, Karten, Spielstände und RPG-/ADV-/SLG-Funktionen
#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 — Szenenregistrierung, -wechsel und -aktualisierung
#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 — Hintergrund, Fenster und geteiltes Scrollen
#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 — Spielbretter, Zuglisten und Rücknahme
#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-Reservierung, Positionierung, Metasprites und Animation
#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 — Spriteauswahl nach Priorität und Rotation
#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 — Start, Bildzähler, Wartefunktionen und Interrupts
#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-Aktualisierungen und Übertragung per Warteschlange
#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 — Drahtgitterdarstellung für 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 — Farbige Drahtgitterdarstellung für 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 — Drahtgitterdarstellung für 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







