KITAQ SERIES • ÉDITION DE RÉFÉRENCE
BIBLIOTHÈQUE KITAQGB
Outils pour créer un jeu
Copie des sources : 14 septembre 2026 · Édition anglaise de référence : 14 septembre 2026
Utiliser la bibliothèque avec le compilateur natif
lib/ contient les en-têtes et sources C compilés dans la ROM de la console. Le compilateur pour PC et les outils auxiliaires sont en Rust ; les sources de jeux, bibliothèques cibles et API restent en C. SOURCE_MANIFEST.json et LIBRARY_MERGE.json consignent les sources retenues lorsqu'ils sont fournis.
kitaqgb · Compilateur natif Rust et outils auxiliaires · GitHub Actions
Les constructions natives et vérifications d'exécution ont réussi sous Windows, Linux, macOS ARM et macOS Intel. KITAQGB a passé 48 tests et 395 vérifications d'outils par environnement ; KITAQFC en a passé 55 et 401. Rust 1.85 a également été testé. PUBLIC_DISTRIBUTION.json consigne les empreintes des binaires installés et la provenance des validations. Les workflows GitHub Actions publics reconstruisent et testent ces sources indépendamment.
Les sorties de référence conservées vérifient les octets ROM, les diagnostics et les formats des outils. Les anciennes preuves d'émulation C# restent des résultats historiques liés à leurs empreintes sources. Elles ne prouvent pas automatiquement toutes les API Rust, le matériel réel ou le démarrage complet d'un jeu par le BIOS FDS. Le script PNG d'origine, indisponible, a été réimplémenté d'après sa spécification ; l'identité des octets avec ce script ne peut être affirmée.
Exemples de programmes complets
Chaque programme, les en-têtes communs, le fichier ascii.c fourni et ses ressources converties sont inclus. Les noms commençant par m_ sont des fonctions écrites pour ces manuels. Lisez chaque commande de compilation avec son résultat attendu et son compte rendu de vérification. Lancez les commandes depuis le dossier parent des dépôts voisins.
Script de compilation par lot / Résultats et captures d'écran
Afficher le jeu de caractères fourni gb_font.c
Objectif : Présente les lettres, chiffres et signes de ponctuation de la police originale fournie, ainsi que leur affichage.
Fonctionnement : m_init prépare l’affichage et la police. m_text dessine chaque ligne ; m_put dessine le guillemet double avec le code de caractère 34.
Commandes et résultat attendu : Repérez les 26 lettres majuscules, les 26 minuscules, les 10 chiffres et les 30 signes de ponctuation. Vérifiez que chaque glyphe est lisible. Aucune saisie n’est nécessaire.

Télécharger le source / État de la vérification
.\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(); }
}Votre premier affichage de texte gb_hello.c
Objectif : Présente les étapes de base pour démarrer une ROM et dessiner du texte et un nombre sur le fond.
Fonctionnement : Après m_init, m_text dessine le message d’accueil et m_number formate 42. La boucle finale attend les images en conservant l’affichage.
Commandes et résultat attendu : L’écran affiche HELLO WORLD et 042. Le zéro initial provient du format décimal sur trois chiffres.

Télécharger le source / État de la vérification
.\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(); }
}Calculer avec un intermédiaire plus large gb_arithmetic.c
Objectif : Montre comment conserver un résultat intermédiaire qui dépasse huit bits.
Fonctionnement : (u16)200 + 100 donne 300. Le programme divise ce résultat par 10, puis le convertit en u8 pour l’afficher. Notez que la conversion vers le type plus large précède l’addition.
Commandes et résultat attendu : 030 représente le résultat calculé, 30.

Télécharger le source / État de la vérification
.\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(); }
}Branchements et boucles gb_control.c
Objectif : Essaie for, continue, while, do/while et switch dans un petit calcul.
Fonctionnement : Additionner 0 à 7 en sautant 3 donne 25. La boucle while avance jusqu’à 30, do/while jusqu’à 32, puis switch choisit case 32 pour affecter 42.
Commandes et résultat attendu : 042 est le résultat final de ces boucles et branchements.

Télécharger le source / État de la vérification
.\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(); }
}Fonctions, tableaux, structures et pointeurs gb_aggregate.c
Objectif : Montre comment regrouper des valeurs et y accéder par des fonctions et des pointeurs.
Fonctionnement : Le programme copie un Point contenant (10,20), puis écrit de 1 à 4 dans un tableau via un pointeur. Il additionne le résultat de fonction 30, les valeurs du tableau 1, 2 et 4 et la constante 5.
Commandes et résultat attendu : La somme est affichée sous la forme 042. Suivez la copie de structure, les écritures dans ptr[i] et la valeur renvoyée par la fonction.
![Fonctions, tableaux, structures et pointeurs : La somme est affichée sous la forme 042. Suivez la copie de structure, les écritures dans ptr[i] et la valeur renvoyée par la fonction.](../verification/gb_aggregate.png)
Télécharger le source / État de la vérification
.\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(); }
}Drapeaux binaires et copie de tampon gb_bits_memory.c
Objectif : Regroupe des drapeaux dans un octet et copie un tampon dans une zone distincte.
Fonctionnement : __memset efface quatre octets. Le programme active le bit 3, inverse le bit 1, puis copie les quatre octets avec __memcpy.
Commandes et résultat attendu : le premier octet de destination est affiché sous la forme 010 ; le bit 3 apporte 8 et le bit 1 apporte 2.

Télécharger le source / État de la vérification
.\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(); }
}Compter les nouveaux appuis sur un bouton gb_input.c
Objectif : Distingue un nouvel appui sur un bouton d’un bouton maintenu enfoncé.
Fonctionnement : Chaque image appelle input_update. Le compteur n’avance que si input_pressed(BTN_A) est vrai.
Commandes et résultat attendu : le compteur commence à 000. Appuyez sur A pour obtenir 001 ; maintenir le bouton n’ajoute rien. Relâchez-le puis appuyez de nouveau pour obtenir 002. Le compteur sur un octet revient de 255 à 000.

Télécharger le source / État de la vérification
.\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); } }
}Multiplier des valeurs à virgule fixe Q8.8 gb_fixed.c
Objectif : Présente la conversion d’entier en Q8.8, la multiplication et le retour à un entier.
Fonctionnement : fix_from_int convertit 3 et 4 en Q8.8. fix_mul les multiplie, puis fix_to_int reconvertit le produit en entier.
Commandes et résultat attendu : 012 signifie 3 × 4 = 12. C’est l’entier converti, pas la valeur interne multipliée par 256.

Télécharger le source / État de la vérification
.\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(); }
}Allouer dans un pool fixe d’objets gb_entity.c
Objectif : Crée un objet dans un ensemble fixe d’emplacements, sans allocation dynamique.
Fonctionnement : entity_init réinitialise le pool. entity_create crée un objet de type 1 en (20,30) ; le programme vérifie l’ID d’échec 0xFF avant de fixer vx à 2.
Commandes et résultat attendu : 001 est le nombre d’objets actifs, pas un ID ni une coordonnée. Cet exemple ne met pas à jour et ne dessine pas l’objet ; aucun personnage ne se déplace donc à l’écran.

Télécharger le source / État de la vérification
.\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(); }
}Enregistrer une valeur de diagnostic en RAM gb_debug.c
Objectif : Conserve une valeur de jeu nommée dans un tampon de diagnostic, indépendamment de l’affichage.
Fonctionnement : Le programme initialise le débogage, fixe l’étiquette d’image à 1 et enregistre la valeur 42 sous le nom HP.
Commandes et résultat attendu : 001 est le nombre d’entrées de trace. HP=42 est stocké dans le tampon de diagnostic ; l’écran seul ne montre ni ne vérifie ce contenu.

Télécharger le source / État de la vérification
.\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(); }
}Stocker un historique de positions gb_chain.c
Objectif : Montre comment stocker un historique de positions dans un tampon circulaire.
Fonctionnement : chain_init associe un tableau pouvant contenir quatre points. chain_push_head enregistre ensuite (20,30).
Commandes et résultat attendu : 042 est un repère fixe de fin, pas une coordonnée ni un compteur. Examinez trail et points pour vérifier l’historique stocké. Ce programme ne dessine pas de corps suiveur.

Télécharger le source / État de la vérification
.\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(); }
}Lire le compteur d’images de la bibliothèque gb_system.c
Objectif : Montre l’effet des attentes comptées en images sur le compteur d’images de la bibliothèque.
Fonctionnement : Après system_init, le programme appelle deux fois system_wait_vblank et affiche system_get_frame8.
Commandes et résultat attendu : Le résultat est 002. La boucle d’attente utilise la fonction utilitaire m_wait du manuel ; la valeur affichée ne continue donc pas à augmenter.

Télécharger le source / État de la vérification
.\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(); }
}Sélectionner l’ID de la scène courante gb_scene.c
Objectif : Montre comment sélectionner un ID pour distinguer des scènes, comme le titre et la partie en cours.
Fonctionnement : Le programme enregistre deux entrées SceneDef initialisées à zéro et sélectionne l’ID 1 avec scene_change.
Commandes et résultat attendu : 001 est l’ID courant renvoyé par scene_get_current. Cet exemple n’enregistre ni callbacks de scène ni dessin de transition.

Télécharger le source / État de la vérification
.\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(); }
}Convertir les coordonnées du monde en coordonnées d’écran gb_camera.c
Objectif : Soustrait la position de la caméra pour obtenir la position à l’écran d’un point du monde.
Fonctionnement : Camera_Set reçoit la valeur Q8.8 2560, soit X=10 pixels. Camera_WorldToScreenX convertit ensuite la coordonnée du monde X=52.
Commandes et résultat attendu : 052 moins 010 donne le 042 affiché. C’est un calcul de coordonnées ; le fond ne défile pas.

Télécharger le source / État de la vérification
.\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(); }
}Décompresser des données RLE en RAM gb_rle.c
Objectif : Essaie une représentation compacte des octets répétés sous forme de paires nombre/valeur.
Fonctionnement : Les octets compressés {3,42,0} représentent trois copies de 42, suivies d’un terminateur de compte nul. rle_decode écrit dans une destination de trois octets.
Commandes et résultat attendu : le dernier octet, out[2], est affiché sous la forme 042. Les trois octets décompressés doivent tous contenir 42.
![Décompresser des données RLE en RAM : le dernier octet, out[2], est affiché sous la forme 042. Les trois octets décompressés doivent tous contenir 42.](../verification/gb_rle.png)
Télécharger le source / État de la vérification
.\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(); }
}Lire et écrire une case du plateau gb_board.c
Objectif : Montre comment les coordonnées d’une grille correspondent au stockage d’un jeu de plateau.
Fonctionnement : Un tableau de 16 octets stocke un plateau de 4×4. Le programme l’efface, écrit 42 dans la case (2,1), puis relit cette case.
Commandes et résultat attendu : 042 est la valeur relue. Le programme ne dessine pas le plateau de 4×4 lui-même.

Télécharger le source / État de la vérification
.\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(); }
}Faire avancer une boîte d’un pas de physique gb_physics.c
Objectif : Initialise un monde et un corps rectangulaire, puis met à jour la position à partir de la vitesse.
Fonctionnement : Le corps démarre en (40,40), avec une vitesse (2,0) et une gravité nulle. Le programme appelle kq2d_step une fois.
Commandes et résultat attendu : 042 est la coordonnée X obtenue, mesurée ici en pixels entiers. Aucune boîte ni animation continue n’est dessinée.

Télécharger le source / État de la vérification
.\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(); }
}Gérer la fin d’un transfert série et le dépassement du délai gb_link.c
Objectif : Distingue un transfert terminé d’un transfert qui n’aboutit pas dans le délai d’attente.
Fonctionnement : Le maître envoie 42 et attend avec Link_WaitByte. À la fin du transfert, l’octet reçu est affiché ; en cas de délai dépassé, le transfert est annulé et zéro est affiché.
Commandes et résultat attendu : Un transfert terminé sans connexion peut renvoyer 255. Un délai dépassé affiche 000 ; avec un pair connecté, l’écran montre l’octet reçu. Le résultat n’est pas toujours 042.

Télécharger le source / État de la vérification
.\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(); }
}Lire des données ROM avec un argument de banque gb_bank.c
Objectif : Présente les arguments nécessaires pour copier des données de la ROM vers la RAM.
Fonctionnement : far_data_read copie les deux octets 7 et 42 dans copied, avec l’argument de banque 0 et une longueur de 2.
Commandes et résultat attendu : Le deuxième octet de destination est affiché sous la forme 042. L’exemple lit la ROM fixe ; il n’illustre pas un transfert entre différentes banques commutables.

Télécharger le source / État de la vérification
.\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(); }
}Charger des données par ID de ressource gb_asset.c
Objectif : Enregistre l’emplacement et la longueur d’une ressource, puis récupère ses octets par ID.
Fonctionnement : La ressource 0 est de type RAW, dans la banque 0, avec un pointeur vers {7,42} et une longueur de 2. asset_load_raw la copie dans un tampon RAM de deux octets.
Commandes et résultat attendu : Le deuxième octet est affiché sous la forme 042. Cet exemple illustre la recherche et la copie d’une ressource, pas le rendu d’une image.

Télécharger le source / État de la vérification
.\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(); }
}Allouer un projectile gb_danmaku.c
Objectif : Initialise le pool de projectiles et examine son occupation après une création.
Fonctionnement : Après danmaku_reset, le programme appelle danmaku_spawn(40,40,16,0) et affiche dm_count.
Commandes et résultat attendu : 001 est le nombre de projectiles alloués. Il n’y a ici ni boucle de mise à jour des projectiles ni composition du fond ; aucun projectile mobile n’est dessiné.

Télécharger le source / État de la vérification
.\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(); }
}Définir une palette de fond CGB gb_cgb_palette.c
Objectif : Choisit les couleurs du fond et du texte à partir des composantes RGB de la Game Boy Color.
Fonctionnement : Le programme désactive le LCD pendant le VBlank, règle la couleur 0 de la palette 0 sur le blanc (31,31,31) et la couleur 3 sur le violet (12,0,22), puis réactive l’affichage.
Commandes et résultat attendu : Exécutez en mode CGB pour voir le texte violet et 042 sur fond blanc. L’affichage monochrome DMG ne peut pas montrer ces couleurs.

Télécharger le source / État de la vérification
.\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(); }
}Faire défiler le fond horizontalement gb_scroll.c
Objectif : Déplace le point de vue sans redessiner le contenu du fond.
Fonctionnement : Chaque image incrémente phase et le transmet à Scroll_SetBg. La position sur huit bits revient à zéro après 255.
Commandes et résultat attendu : Le mot SCROLL se déplace vers la gauche. Observez sa position au fil du temps ; une seule capture ne peut pas montrer le mouvement.

Télécharger le source / État de la vérification
.\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); }
}Mettre une mise à jour de tuile en file gb_vram_queue.c
Objectif : Sépare une demande de dessin du transfert VRAM qui l’applique.
Fonctionnement : vram_queue_bg_tile met en file la tuile 52 à la coordonnée (3,8), puis vram_flush la transfère. Dans la police fournie, la tuile 52 correspond au chiffre 4.
Commandes et résultat attendu : Repérez un seul 4 à la coordonnée de tuile du fond (3,8). Il s’agit d’une mise à jour de tuile, pas d’un compteur numérique.

Télécharger le source / État de la vérification
.\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(); }
}Afficher un sprite par DMA OAM gb_sprite.c
Objectif : Alloue et affiche un sprite indépendamment du fond.
Fonctionnement : Le pool initialisé fournit l’emplacement 0. Le programme choisit la tuile 65, fixe la position (70,80), active l’affichage OBJ et transfère l’OAM miroir à chaque image.
Commandes et résultat attendu : Une lettre A immobile apparaît à la position de sprite indiquée. Dans un jeu, vérifiez l’échec éventuel de l’allocation avant d’utiliser l’ID renvoyé.

Télécharger le source / État de la vérification
.\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(); }
}Générer une valeur aléatoire reproductible gb_rng.c
Objectif : Utilise une graine pour reproduire une séquence pseudo-aléatoire.
Fonctionnement : rng_seed(1234) initialise le générateur, puis rng_range(10) est appelé une fois. La borne supérieure 10 est exclue.
Commandes et résultat attendu : L’écran affiche une valeur entre 000 et 009. Relancer le même programme avec la même graine reproduit cette valeur ; elle ne change pas à chaque image.

Télécharger le source / État de la vérification
.\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(); }
}Stocker un drapeau d’état du jeu gb_flags.c
Objectif : Représente un état booléen, comme l’achèvement d’un événement, par un numéro de drapeau.
Fonctionnement : Le programme efface le drapeau 12, le définit, puis le relit avec flag_get.
Commandes et résultat attendu : 001 signifie que le drapeau 12 est vrai. Cet exemple utilise des drapeaux en RAM et ne les conserve pas après extinction.

Télécharger le source / État de la vérification
.\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(); }
}Faire avancer un cercle d’un pas de physique gb_circle.c
Objectif : Configure un corps circulaire et met à jour sa position à partir de sa vitesse.
Fonctionnement : Le cercle actif a un rayon de 4, une position (40,40) et une vitesse (2,0). La gravité est nulle et linear_damping_q8 vaut 255 ; kq2dc_step s’exécute une fois.
Commandes et résultat attendu : 042 est la coordonnée X entière obtenue. Cet exemple ne dessine ni contour de cercle ni animation de collision.

Télécharger le source / État de la vérification
.\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(); }
}Traiter un effet sonore à chaque image gb_sound.c
Objectif : Démarre un flux d’effet sonore et le fait progresser par des mises à jour régulières à chaque image.
Fonctionnement : Après Audio_Init, Audio_PlaySFX lance tone sur le canal d’ID 1. La boucle principale appelle Audio_Update une fois par image.
Commandes et résultat attendu : Un bref effet sonore pulsé joue pendant que 042 reste affiché. Ce nombre est un repère fixe, pas le volume ni la position de lecture. Évaluez le son à l’écoute ou à partir d’un enregistrement.

Télécharger le source / État de la vérification
.\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(); }
}Dictionnaire de l'API de bibliothèque
554 entrées. Ouvrez une entrée pour consulter sa syntaxe, ses arguments, les notes source et son exemple. Les fragments d'appel nécessitent une initialisation autour du code ; ce ne sont pas des ROM autonomes. Les exemples montrent comment transmettre des valeurs préparées à l'API, sans constituer une validation sur le périphérique.
zx0
Décode les ressources compatibles ZX0 en RAM ou VRAM. Préparez-les sur PC avec kitaqgb-zx0.exe, puis décodez seulement les données nécessaires à l’exécution. --format=auto compare les charges utiles brutes, RLE et ZX0 et choisit la plus petite ; à égalité, l’ordre de préférence est brut, RLE, puis ZX0. Limitez le conteneur complet à 65535 octets, en-tête de neuf octets compris, et divisez les ressources selon les banques CPU et la RAM disponibles.
Einar Saukas a conçu le format ZX0 et l’algorithme de compression original. Le compresseur et le décompresseur fournis ici sont des implémentations KITAQ indépendantes, sous copyright DAISUKE OBA et publiées sous licence MIT.
Exécutez ces commandes sur l’ordinateur hôte depuis la racine du dépôt. Compilez l’outil avec 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
Décode un flux ZX0 v2 dans une zone RAM bornée. Les correspondances référencent des octets déjà décodés ; la destination doit donc être lisible et inscriptible. Utilisez-le pour des cartes de tuiles ou tables de niveaux que le CPU traitera avant utilisation.
Syntaxe
u16 zx0_decompress(void* dst, u16 capacity, const void* src, u16 packed_size);Paramètres
dstDébut de la RAM de destination accessible en écriture ; ne doit pas être null. Exprimez la capacité en octets, pas en éléments de tableau.
capacityNombre d’octets inscriptibles en destination. Un flux ZX0 ordinaire nécessite au moins un octet. Une ressource KQA1 brute vide peut réussir avec une capacité nulle.
srcDébut des données compressées lisibles avec le mappage de banque courant. Ne doit pas être null.
packed_sizeNombre d’octets de l’entrée complète. Un flux ZX0 inclut son marqueur de fin et n’a pas d’octets supplémentaires après lui. Un conteneur KQA1 inclut son en-tête de neuf octets. Maximum : 65535 octets.
Valeur renvoyée
Renvoie le nombre d’octets décodés en cas de succès, zéro en cas d’erreur. Vérifiez toujours aussi zx0_error.
Conditions et limites
Incluez zx0.h et compilez lib/zx0.c. Ces routines partagent un espace temporaire et ne sont pas réentrantes depuis les interruptions. Entrée et sortie ne doivent ni se chevaucher, ni boucler dans l’espace d’adressage CPU, ni franchir les fenêtres de banques actuellement mappées. La bibliothèque ne change pas les banques de ressources.
Chaque appel met à jour zx0_error : 0 succès, 1 argument invalide, 2 entrée tronquée, 3 flux malformé, 4 espace de sortie insuffisant, 5 affichage actif. Un échec peut laisser une sortie partielle : ne l’utilisez pas. Si plusieurs conditions sont invalides, la première détectée détermine le code.
Accepte les flux ZX0 v2 en sens avant. ZX0 v1, les flux inverses et les dictionnaires externes sont hors de cette interface. Connaissez la taille décodée de la ressource produite sur l’hôte et fournissez assez de stockage.
Exemple d’utilisation
count=zx0_decompress(decoded_map,16,packed_map,packed_map_SIZE);
if(count!=16||zx0_error!=ZX0_OK)failures++;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
La ligne RAM MAP répète les tuiles carré, losange et damier. AUTO RLE MAP forme une barre horizontale avec seize carrés. VRAM TILES répète les trois mêmes tuiles après décodage de leurs pixels en VRAM. Sur CGB et FC, le carré est blanc, le losange rouge et le damier bleu ; DMG utilise des nuances de gris. CHECKS OK confirme que les trois appels ont renvoyé les tailles décodées attendues sans erreur.


Commande de compilation
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-disasmImplémentation et source
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
Lit le codec et les tailles dans l’en-tête KQA1 produit par --format=auto, puis copie les octets bruts ou décode RLE/ZX0 en RAM. L’appelant n’a pas besoin d’une branche distincte par codec.
Syntaxe
u16 asset_decompress(void* dst, u16 capacity, const void* src, u16 packed_size);Paramètres
dstDébut de la RAM de destination accessible en écriture ; ne doit pas être null. Exprimez la capacité en octets, pas en éléments de tableau.
capacityNombre d’octets inscriptibles en destination. Un flux ZX0 ordinaire nécessite au moins un octet. Une ressource KQA1 brute vide peut réussir avec une capacité nulle.
srcDébut des données compressées lisibles avec le mappage de banque courant. Ne doit pas être null.
packed_sizeNombre d’octets de l’entrée complète. Un flux ZX0 inclut son marqueur de fin et n’a pas d’octets supplémentaires après lui. Un conteneur KQA1 inclut son en-tête de neuf octets. Maximum : 65535 octets.
Valeur renvoyée
Renvoie le nombre d’octets décodés en cas de succès, zéro en cas d’erreur. Vérifiez toujours aussi zx0_error.
Conditions et limites
Incluez zx0.h et compilez lib/zx0.c. Ces routines partagent un espace temporaire et ne sont pas réentrantes depuis les interruptions. Entrée et sortie ne doivent ni se chevaucher, ni boucler dans l’espace d’adressage CPU, ni franchir les fenêtres de banques actuellement mappées. La bibliothèque ne change pas les banques de ressources.
Chaque appel met à jour zx0_error : 0 succès, 1 argument invalide, 2 entrée tronquée, 3 flux malformé, 4 espace de sortie insuffisant, 5 affichage actif. Un échec peut laisser une sortie partielle : ne l’utilisez pas. Si plusieurs conditions sont invalides, la première détectée détermine le code.
KQA1 est le conteneur de ressources KITAQ : signature de quatre octets, codec d’un octet (0 brut, 1 RLE, 2 ZX0), taille décodée u16, taille de charge utile u16, puis charge utile. Les champs u16 sont en petit-boutiste. RLE répète des paires compte/valeur avec comptes de 1 à 255 et un terminateur de compte zéro. Une ressource brute vide réussit avec valeur de retour zéro et erreur zéro.
Exemple d’utilisation
count=asset_decompress(decoded_auto,16,packed_auto,packed_auto_SIZE);
if(count!=16||zx0_error!=ZX0_OK)failures++;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
La ligne RAM MAP répète les tuiles carré, losange et damier. AUTO RLE MAP forme une barre horizontale avec seize carrés. VRAM TILES répète les trois mêmes tuiles après décodage de leurs pixels en VRAM. Sur CGB et FC, le carré est blanc, le losange rouge et le damier bleu ; DMG utilise des nuances de gris. CHECKS OK confirme que les trois appels ont renvoyé les tailles décodées attendues sans erreur.


Commande de compilation
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-disasmImplémentation et source
kitaqgb/lib/zx0.h:18
Decode a KQA1 raw/RLE/ZX0 asset produced with --format=auto. Empty raw assets return zero with zx0_error==ZX0_OK.
kitaqgb/lib/zx0.c:95
u16 asset_decompress(void* dst,u16 capacity,const void* src,u16 packed_size) {
const u8* in; u8* out; u16 raw; u16 packed; u16 used;
u8 codec; u8 count; u8 value;
zx0_error=ZX0_OK;
if(packed_size<9||!kq_zx_arguments(dst,capacity,src,packed_size)) { zx0_error=ZX0_BAD_ARGUMENT; return 0; }
in=(const u8*)src; out=(u8*)dst;
if(in[0]!=75||in[1]!=81||in[2]!=65||in[3]!=49) { zx0_error=ZX0_BAD_STREAM; return 0; }
codec=in[4]; raw=(u16)((u16)in[5]|((u16)in[6]<<8));
packed=(u16)((u16)in[7]|((u16)in[8]<<8));
if(packed!=packed_size-9||codec>2) { zx0_error=ZX0_BAD_STREAM; return 0; }
if(raw>capacity) { zx0_error=ZX0_OUTPUT_FULL; return 0; }
in+=9;
if(codec==2) {
used=zx0_decompress(dst,raw,in,packed);
if(zx0_error==0&&used!=raw) zx0_error=ZX0_BAD_STREAM;
return zx0_error?0:used;
}
if(codec==0) {
if(raw!=packed) { zx0_error=ZX0_BAD_STREAM; return 0; }
used=raw; while(raw!=0) { *out++=*in++; raw--; } return used;
}
used=0;
while(packed!=0) {
count=*in++; packed--;
if(count==0) {
if(packed!=0||used!=raw) { zx0_error=ZX0_BAD_STREAM; return 0; }
return used;
}
if(packed==0) { zx0_error=ZX0_TRUNCATED; return 0; }
value=*in++; packed--;
if((u16)count>raw-used) { zx0_error=ZX0_OUTPUT_FULL; return 0; }
used+=count; while(count!=0) { *out++=value; count--; }
}
zx0_error=ZX0_TRUNCATED; return 0;
}zx0_decompress_vram
LCD arrêté, décode directement les pixels de tuiles ou données de carte ZX0 dans la banque VRAM sélectionnée. La VRAM fournit elle-même l’historique des correspondances ; aucun tampon RAM intermédiaire n’est nécessaire.
Syntaxe
u16 zx0_decompress_vram(u16 vram_addr, const void* src, u16 packed_size);Paramètres
vram_addrAdresse de début VRAM, 0x8000..0x9FFF. La sortie est bornée par la fin de VRAM à 0xA000. Sur CGB, sélectionnez VBK avant l’appel.
srcDébut des données compressées lisibles avec le mappage de banque courant. Ne doit pas être null.
packed_sizeNombre d’octets de l’entrée complète. Un flux ZX0 inclut son marqueur de fin et n’a pas d’octets supplémentaires après lui. Un conteneur KQA1 inclut son en-tête de neuf octets. Maximum : 65535 octets.
Valeur renvoyée
Renvoie le nombre d’octets décodés en cas de succès, zéro en cas d’erreur. Vérifiez toujours aussi zx0_error.
Conditions et limites
Incluez zx0.h et compilez lib/zx0.c. Ces routines partagent un espace temporaire et ne sont pas réentrantes depuis les interruptions. Entrée et sortie ne doivent ni se chevaucher, ni boucler dans l’espace d’adressage CPU, ni franchir les fenêtres de banques actuellement mappées. La bibliothèque ne change pas les banques de ressources.
Chaque appel met à jour zx0_error : 0 succès, 1 argument invalide, 2 entrée tronquée, 3 flux malformé, 4 espace de sortie insuffisant, 5 affichage actif. Un échec peut laisser une sortie partielle : ne l’utilisez pas. Si plusieurs conditions sont invalides, la première détectée détermine le code.
Accepte les flux ZX0 v2 en sens avant. ZX0 v1, les flux inverses et les dictionnaires externes sont hors de cette interface. Connaissez la taille décodée de la ressource produite sur l’hôte et fournissez assez de stockage.
Renvoie l’erreur 5 si le LCD est activé ; être simplement en VBlank ne suffit pas. Affichage, VBK et interruptions restent inchangés. L’appelant arrête puis redémarre le LCD.
Exemple d’utilisation
count=zx0_decompress_vram(0x8800,packed_tiles,packed_tiles_SIZE);
if(count!=48||zx0_error!=ZX0_OK)failures++;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
La ligne RAM MAP répète les tuiles carré, losange et damier. AUTO RLE MAP forme une barre horizontale avec seize carrés. VRAM TILES répète les trois mêmes tuiles après décodage de leurs pixels en VRAM. Sur CGB et FC, le carré est blanc, le losange rouge et le damier bleu ; DMG utilise des nuances de gris. CHECKS OK confirme que les trois appels ont renvoyé les tailles décodées attendues sans erreur.


Commande de compilation
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-disasmImplémentation et source
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 — Identifiants de ressources et descripteurs de données
La bibliothèque de ressources retrouve les données en ROM à partir d’un identifiant de 8 bits. Incluez asset.c et, sur FC, également bank.c. Chaque AssetDesc compact occupe 6 octets : type, banque des données, adresse sur 16 bits et longueur en octets. La table et les données peuvent se trouver dans des banques différentes.
Enregistrez la table avant toute recherche. Cet enregistrement est un état global partagé : ne le modifiez pas pendant une recherche. La bibliothèque vérifie les identifiants et le pointeur de sortie de asset_get, mais pas la table enregistrée, les adresses des données ni le contenu de la cartouche.
Recherche une ressource RAW ou TILES et transfère ses desc.len octets avec __vram_copy. Sélectionnez d’abord la banque ROM des données : cette fonction GB utilise directement desc.ptr et ne sélectionne pas desc.bank pour le transfert.
asset_get
Copie un AssetDesc depuis la banque ROM de la table enregistrée vers l’espace fourni par l’appelant. Elle récupère les métadonnées de la ressource, pas son contenu.
Syntaxe
u8 asset_get(u8 asset_id, AssetDesc* out_desc);Paramètres
asset_idIndice de ressource à partir de zéro. Il doit vérifier
asset_id < countdans la table enregistrée.out_descEspace accessible en écriture pour un descripteur de 6 octets. Un pointeur nul est rejeté avant tout accès à la table.
Valeur renvoyée
1 après copie du descripteur ; 0 si la sortie est nulle ou l’identifiant hors limites. Dans ces deux cas, la sortie reste inchangée.
Conditions et limites
Enregistrez la table avant toute recherche. Cet enregistrement est un état global partagé : ne le modifiez pas pendant une recherche. La bibliothèque vérifie les identifiants et le pointeur de sortie de asset_get, mais pas la table enregistrée, les adresses des données ni le contenu de la cartouche.
Les exemples placent le code appelant dans la banque fixe 0 afin qu’un changement de banque source ne le rende pas inaccessible. Les transferts sont synchrones. N’interrompez pas un transfert par une autre copie changeant de banque ; cette fonction ne garantit pas à elle seule la sûreté des interruptions de toute l’application.
Exemple d’utilisation
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);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple lit le descripteur 0 et vérifie le type TILES, la banque 2, le pointeur et la longueur de 144 octets. Les identifiants invalides et sorties nulles doivent être refusés, sans modifier la valeur de sortie précédente.
Image attendue : une rangée rouge part de (16,32) et occupe 72×8 pixels. Elle répète trois fois un triangle de 8×8, un carré de 8×8 au contour d’un pixel et une tuile dont les quatre colonnes de gauche sont pleines. Le triangle s’élargit d’un pixel en haut à gauche à huit sur sa ligne inférieure.
Sur GB, le triangle et le contour bleus en (16,64) montrent le résultat de __farmemcpy ; la paire verte en (16,96), celui de __far_memcpy. Chaque paire occupe 16×8 pixels. Le CGB utilise ces couleurs ; le DMG affiche les mêmes formes en noir sur blanc.
L’état attendu est FAILED CHECKS 000 et FIRST FAILURE 00. La vérification exécute 300 images puis compare texte, formes et couleurs aux résultats attendus. Il s’agit d’une preuve sur émulateur, pas d’un essai sur matériel physique.


Commande de compilation
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-disasmImplémentation et source
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
Lit dans le descripteur le numéro de banque des données. Ce n’est pas la banque de la table, et la fonction ne laisse pas cette banque de données sélectionnée.
Syntaxe
u8 asset_get_bank(u8 asset_id);Paramètres
asset_idIndice de ressource à partir de zéro. Il doit vérifier
asset_id < countdans la table enregistrée.
Valeur renvoyée
Le champ bank sur 8 bits, ou 0 si la recherche échoue. La banque zéro pouvant être valide, utilisez asset_get() pour distinguer succès et valeur nulle.
Conditions et limites
Enregistrez la table avant toute recherche. Cet enregistrement est un état global partagé : ne le modifiez pas pendant une recherche. La bibliothèque vérifie les identifiants et le pointeur de sortie de asset_get, mais pas la table enregistrée, les adresses des données ni le contenu de la cartouche.
Chaque accesseur rappelle asset_get et copie un descripteur. Pour obtenir banque, pointeur et longueur ensemble, appelez asset_get une seule fois et lisez ses champs.
Les exemples placent le code appelant dans la banque fixe 0 afin qu’un changement de banque source ne le rende pas inaccessible. Les transferts sont synchrones. N’interrompez pas un transfert par une autre copie changeant de banque ; cette fonction ne garantit pas à elle seule la sûreté des interruptions de toute l’application.
Exemple d’utilisation
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.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple attend la banque de données 2 alors que la table est dans la banque 3. Il vérifie aussi qu’un identifiant invalide renvoie zéro.
Image attendue : une rangée rouge part de (16,32) et occupe 72×8 pixels. Elle répète trois fois un triangle de 8×8, un carré de 8×8 au contour d’un pixel et une tuile dont les quatre colonnes de gauche sont pleines. Le triangle s’élargit d’un pixel en haut à gauche à huit sur sa ligne inférieure.
Sur GB, le triangle et le contour bleus en (16,64) montrent le résultat de __farmemcpy ; la paire verte en (16,96), celui de __far_memcpy. Chaque paire occupe 16×8 pixels. Le CGB utilise ces couleurs ; le DMG affiche les mêmes formes en noir sur blanc.
L’état attendu est FAILED CHECKS 000 et FIRST FAILURE 00. La vérification exécute 300 images puis compare texte, formes et couleurs aux résultats attendus. Il s’agit d’une preuve sur émulateur, pas d’un essai sur matériel physique.


Commande de compilation
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-disasmImplémentation et source
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
Lit dans le descripteur la longueur de la ressource en octets. Il s’agit d’une métadonnée : la fonction n’examine pas le contenu et ne calcule aucun nombre de tuiles, d’éléments ou d’images.
Syntaxe
u16 asset_get_len(u8 asset_id);Paramètres
asset_idIndice de ressource à partir de zéro. Il doit vérifier
asset_id < countdans la table enregistrée.
Valeur renvoyée
Le champ len sur 16 bits, en octets, ou 0 si la recherche échoue. Une ressource vide a aussi une longueur nulle ; asset_get() permet de faire la distinction.
Conditions et limites
Enregistrez la table avant toute recherche. Cet enregistrement est un état global partagé : ne le modifiez pas pendant une recherche. La bibliothèque vérifie les identifiants et le pointeur de sortie de asset_get, mais pas la table enregistrée, les adresses des données ni le contenu de la cartouche.
Chaque accesseur rappelle asset_get et copie un descripteur. Pour obtenir banque, pointeur et longueur ensemble, appelez asset_get une seule fois et lisez ses champs.
Les exemples placent le code appelant dans la banque fixe 0 afin qu’un changement de banque source ne le rende pas inaccessible. Les transferts sont synchrones. N’interrompez pas un transfert par une autre copie changeant de banque ; cette fonction ne garantit pas à elle seule la sûreté des interruptions de toute l’application.
Exemple d’utilisation
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.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
La ressource de neuf tuiles doit indiquer 144 octets, et non neuf tuiles. Une ressource vide comme un identifiant invalide doivent renvoyer zéro.
Image attendue : une rangée rouge part de (16,32) et occupe 72×8 pixels. Elle répète trois fois un triangle de 8×8, un carré de 8×8 au contour d’un pixel et une tuile dont les quatre colonnes de gauche sont pleines. Le triangle s’élargit d’un pixel en haut à gauche à huit sur sa ligne inférieure.
Sur GB, le triangle et le contour bleus en (16,64) montrent le résultat de __farmemcpy ; la paire verte en (16,96), celui de __far_memcpy. Chaque paire occupe 16×8 pixels. Le CGB utilise ces couleurs ; le DMG affiche les mêmes formes en noir sur blanc.
L’état attendu est FAILED CHECKS 000 et FIRST FAILURE 00. La vérification exécute 300 images puis compare texte, formes et couleurs aux résultats attendus. Il s’agit d’une preuve sur émulateur, pas d’un essai sur matériel physique.


Commande de compilation
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-disasmImplémentation et source
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
Lit l’adresse sur 16 bits conservée dans le descripteur. Le pointeur proche renvoyé ne contient aucun numéro de banque. Pour lire une autre banque ROM, associez-le à asset_get_bank() et à une fonction de copie interbanques.
Syntaxe
const u8* asset_get_ptr(u8 asset_id);Paramètres
asset_idIndice de ressource à partir de zéro. Il doit vérifier
asset_id < countdans la table enregistrée.
Valeur renvoyée
Le const u8* enregistré, ou un pointeur nul si la recherche échoue. Le pointeur du descripteur n’étant pas validé, utilisez asset_get() pour reconnaître un échec de recherche.
Conditions et limites
Enregistrez la table avant toute recherche. Cet enregistrement est un état global partagé : ne le modifiez pas pendant une recherche. La bibliothèque vérifie les identifiants et le pointeur de sortie de asset_get, mais pas la table enregistrée, les adresses des données ni le contenu de la cartouche.
Chaque accesseur rappelle asset_get et copie un descripteur. Pour obtenir banque, pointeur et longueur ensemble, appelez asset_get une seule fois et lisez ses champs.
Les exemples placent le code appelant dans la banque fixe 0 afin qu’un changement de banque source ne le rende pas inaccessible. Les transferts sont synchrones. N’interrompez pas un transfert par une autre copie changeant de banque ; cette fonction ne garantit pas à elle seule la sûreté des interruptions de toute l’application.
Exemple d’utilisation
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.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le pointeur doit correspondre à l’adresse ROM de la ressource après placement, tandis qu’un marqueur de la banque 1 reste lisible. L’exemple passe ensuite ce pointeur et la banque 2 à une copie interbanques.
Image attendue : une rangée rouge part de (16,32) et occupe 72×8 pixels. Elle répète trois fois un triangle de 8×8, un carré de 8×8 au contour d’un pixel et une tuile dont les quatre colonnes de gauche sont pleines. Le triangle s’élargit d’un pixel en haut à gauche à huit sur sa ligne inférieure.
Sur GB, le triangle et le contour bleus en (16,64) montrent le résultat de __farmemcpy ; la paire verte en (16,96), celui de __far_memcpy. Chaque paire occupe 16×8 pixels. Le CGB utilise ces couleurs ; le DMG affiche les mêmes formes en noir sur blanc.
L’état attendu est FAILED CHECKS 000 et FIRST FAILURE 00. La vérification exécute 300 images puis compare texte, formes et couleurs aux résultats attendus. Il s’agit d’une preuve sur émulateur, pas d’un essai sur matériel physique.


Commande de compilation
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-disasmImplémentation et source
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
Recherche la ressource et copie min(desc.len, max_len) octets de sa banque ROM vers une mémoire accessible en écriture. Le type est ignoré : graphismes, cartes et morceaux sont copiés tels quels, sans décodage ni décompression.
Syntaxe
u8 asset_load_raw(u8 asset_id, void* dst, u16 max_len);Paramètres
asset_idIndice de ressource à partir de zéro. Il doit vérifier
asset_id < countdans la table enregistrée.dstDestination en mémoire accessible en écriture, assez grande pour tous les octets copiés. Hors transfert de zéro octet, les adresses nulles ou invalides ne sont pas vérifiées.
max_lenNombre maximal d’octets à copier, de 0 à 65535. Une limite plus petite tronque la copie ; zéro ne copie aucun octet du contenu.
Valeur renvoyée
0 si la recherche échoue ; sinon 1, même pour une copie tronquée, une limite nulle ou une ressource vide. Ce n’est ni un nombre d’octets ni la garantie que toute la ressource tenait dans le tampon.
Conditions et limites
Enregistrez la table avant toute recherche. Cet enregistrement est un état global partagé : ne le modifiez pas pendant une recherche. La bibliothèque vérifie les identifiants et le pointeur de sortie de asset_get, mais pas la table enregistrée, les adresses des données ni le contenu de la cartouche.
Toute la source doit être lisible dans le mappage ROM prévu, et toute la destination accessible en écriture. La copie ne passe pas automatiquement à la banque suivante, ne gère pas les chevauchements comme memmove et ne synchronise pas les écritures VRAM. Utilisez les API graphiques pour la VRAM.
Les exemples placent le code appelant dans la banque fixe 0 afin qu’un changement de banque source ne le rende pas inaccessible. Les transferts sont synchrones. N’interrompez pas un transfert par une autre copie changeant de banque ; cette fonction ne garantit pas à elle seule la sûreté des interruptions de toute l’application.
Exemple d’utilisation
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);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Une limite de sept copie seulement sept octets d’une ressource de 144, laisse le suivant à 0x55 et renvoie pourtant un succès. Le programme teste aussi la copie complète, une limite nulle, une ressource vide et la copie brute de données MAP.
Image attendue : une rangée rouge part de (16,32) et occupe 72×8 pixels. Elle répète trois fois un triangle de 8×8, un carré de 8×8 au contour d’un pixel et une tuile dont les quatre colonnes de gauche sont pleines. Le triangle s’élargit d’un pixel en haut à gauche à huit sur sa ligne inférieure.
Sur GB, le triangle et le contour bleus en (16,64) montrent le résultat de __farmemcpy ; la paire verte en (16,96), celui de __far_memcpy. Chaque paire occupe 16×8 pixels. Le CGB utilise ces couleurs ; le DMG affiche les mêmes formes en noir sur blanc.
L’état attendu est FAILED CHECKS 000 et FIRST FAILURE 00. La vérification exécute 300 images puis compare texte, formes et couleurs aux résultats attendus. Il s’agit d’une preuve sur émulateur, pas d’un essai sur matériel physique.


Commande de compilation
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-disasmImplémentation et source
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
Recherche une ressource RAW ou TILES et transfère ses desc.len octets avec __vram_copy. Sélectionnez d’abord la banque ROM des données : cette fonction GB utilise directement desc.ptr et ne sélectionne pas desc.bank pour le transfert.
Syntaxe
u8 asset_load_tiles(u8 asset_id, u16 vram_dst);Paramètres
asset_idIndice de ressource à partir de zéro. Il doit vérifier
asset_id < countdans la table enregistrée.vram_dstAdresse en octets dans la VRAM, entre
$8000et$9FFF, et non numéro de tuile. Pour les motifs, utilisez une adresse alignée sur 16 octets et une longueur multiple de 16 ; la bibliothèque ne vérifie pas ces règles de format.
Valeur renvoyée
0 pour un identifiant invalide ou un type autre que RAW/TILES ; 1 après un transfert accepté, même de longueur nulle. Ce succès ne valide ni l’encodage des tuiles ni leur affichage.
Conditions et limites
Enregistrez la table avant toute recherche. Cet enregistrement est un état global partagé : ne le modifiez pas pendant une recherche. La bibliothèque vérifie les identifiants et le pointeur de sortie de asset_get, mais pas la table enregistrée, les adresses des données ni le contenu de la cartouche.
Les exemples placent le code appelant dans la banque fixe 0 afin qu’un changement de banque source ne le rende pas inaccessible. Les transferts sont synchrones. N’interrompez pas un transfert par une autre copie changeant de banque ; cette fonction ne garantit pas à elle seule la sûreté des interruptions de toute l’application.
Le transfert écrit uniquement des octets : il ne place pas les tuiles sur la carte, n’attribue pas de couleurs et n’alloue pas de VRAM. Configurez séparément la carte et les palettes. Les exemples effectuent le transfert avec le rendu désactivé, puis activent l’affichage.
La routine GB rétablit la banque mémorisée par le compilateur. Maintenez cet état avec __bankswitch : une écriture directe dans le mapper ne le met pas à jour. L’emplacement HRAM de sauvegarde est partagé ; des transferts imbriqués qui l’écrasent ne sont pas sûrs.
Exemple d’utilisation
__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);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple charge neuf motifs originaux de 8×8 pixels, soit 144 octets, et vérifie le rejet du type MAP et des identifiants invalides. Sur FC, cette longueur teste le bloc de 128 octets ainsi que les 16 octets restants.
Image attendue : une rangée rouge part de (16,32) et occupe 72×8 pixels. Elle répète trois fois un triangle de 8×8, un carré de 8×8 au contour d’un pixel et une tuile dont les quatre colonnes de gauche sont pleines. Le triangle s’élargit d’un pixel en haut à gauche à huit sur sa ligne inférieure.
Sur GB, le triangle et le contour bleus en (16,64) montrent le résultat de __farmemcpy ; la paire verte en (16,96), celui de __far_memcpy. Chaque paire occupe 16×8 pixels. Le CGB utilise ces couleurs ; le DMG affiche les mêmes formes en noir sur blanc.
L’état attendu est FAILED CHECKS 000 et FIRST FAILURE 00. La vérification exécute 300 images puis compare texte, formes et couleurs aux résultats attendus. Il s’agit d’une preuve sur émulateur, pas d’un essai sur matériel physique.


Commande de compilation
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-disasmImplémentation et source
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
Enregistre la banque, l’adresse et le nombre d’entrées de l’unique table active. La fonction conserve ces trois valeurs sans copier la table, charger de ressource ni allouer de mémoire.
Syntaxe
void asset_set_table(u8 bank, const AssetDesc* table, u8 count);Paramètres
bankNuméro sur 8 bits de la banque ROM de la table, et non de celle des données.
tablePointeur proche vers
countentréesAssetDescconsécutives. Lescount * 6octets doivent rester lisibles dans la banque de la table tant qu’elle est enregistrée.countNombre d’entrées, de 0 à 255. Avec zéro, aucun identifiant n’est valide ;
asset_set_table(0, 0, 0)permet d’enregistrer une table vide.
Valeur renvoyée
Aucune (void).
Conditions et limites
Enregistrez la table avant toute recherche. Cet enregistrement est un état global partagé : ne le modifiez pas pendant une recherche. La bibliothèque vérifie les identifiants et le pointeur de sortie de asset_get, mais pas la table enregistrée, les adresses des données ni le contenu de la cartouche.
Exemple d’utilisation
asset_set_table(3,asset_descriptors,4); // Four descriptors in bank 3, payloads in bank 2.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple enregistre quatre descripteurs dans la banque 3, avec les contenus non vides dans la banque 2. Il vérifie aussi qu’une table vide fait échouer la recherche sans lire l’adresse zéro.
Image attendue : une rangée rouge part de (16,32) et occupe 72×8 pixels. Elle répète trois fois un triangle de 8×8, un carré de 8×8 au contour d’un pixel et une tuile dont les quatre colonnes de gauche sont pleines. Le triangle s’élargit d’un pixel en haut à gauche à huit sur sa ligne inférieure.
Sur GB, le triangle et le contour bleus en (16,64) montrent le résultat de __farmemcpy ; la paire verte en (16,96), celui de __far_memcpy. Chaque paire occupe 16×8 pixels. Le CGB utilise ces couleurs ; le DMG affiche les mêmes formes en noir sur blanc.
L’état attendu est FAILED CHECKS 000 et FIRST FAILURE 00. La vérification exécute 300 images puis compare texte, formes et couleurs aux résultats attendus. Il s’agit d’une preuve sur émulateur, pas d’un essai sur matériel physique.


Commande de compilation
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-disasmImplémentation et source
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 — Musique, effets sonores et commandes audio
Fournit l’accès direct aux quatre voix, musique/effets en banques, routage stéréo, fondus et ondes personnalisées. Les identifiants des flux musicaux et API directes sont CH1=0, CH2=1, CH3=2, CH4=3. CH3 joue des formes d’onde ; CH4 génère du bruit.
Incluez audio_hwregs_gb.c avant audio.c et appelez Audio_Init au démarrage. Appelez Audio_Update exactement une fois par image, à environ 59,7 Hz. La lecture du flux modifie temporairement le mappage ROM ; ne réentrez pas dans ce pilote depuis une interruption.
Un effet consomme une paire (note,value) par mise à jour et se termine à note=0. value correspond à NR12 pour les effets d’impulsion, à NR32 pour CH3. Préfixez les données CH3 par 0xFF. Conservez le stockage jusqu’à la fin. Les priorités s’appliquent au sein d’un emplacement ; une priorité égale peut remplacer l’effet courant.
Audio_CancelMasterVolumeFade
Arrête les étapes de fondu suivantes en conservant les niveaux et registres actuels.
Syntaxe
void Audio_CancelMasterVolumeFade();Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Exemple d’utilisation
// 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();
}Résultat attendu
A4 passe à gauche, à droite puis au centre. Au centre, le niveau descend de 7 à 1, puis remonte à 4 et s’y maintient. Le niveau 0 reste faiblement audible ; arrêter le canal produit le silence. Un changement de routage peut laisser un transitoire de filtre qui décroît.


Commande de compilation
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-disasmImplémentation et source
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
Programme le balayage, le rapport cyclique, l’enveloppe et la hauteur CH1, puis déclenche l’impulsion.
Syntaxe
void __stackcall Audio_Ch1NoteOn(u8 note, u8 vol_env, u8 duty2);Paramètres
noteIndice de hauteur de 0 à 67. Voir les notes sur le repli de plage et l’écart d’octave de CH3.
vol_envCodage NR12/NR22/NR42 : demi-octet haut pour le volume initial, bit 3 pour une enveloppe croissante, trois bits bas pour sa période. 0xC0 maintient le volume à 12.
duty2Rapport cyclique : 0=12,5 %, 1=25 %, 3=75 % ; toutes les autres valeurs choisissent 50 %.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
note indexe une table de hauteurs de 0 à 67 : 0 correspond à C2 et 33 à A4. Les valeurs supérieures à 67 sont bornées à 67 ; 60..67 utilisent les fréquences de 48..55. Au même indice, CH3 sonne une octave sous un canal d’impulsion. Les fonctions de déclenchement agissent directement sur le matériel, sans vérifier l’activation ni la pause.
Exemple d’utilisation
// 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();
}Résultat attendu
Après environ une demi-seconde de silence, écoutez CH1 A4, CH2 A4, CH3 A3 puis le bruit. Chaque voix dure 30 images, avec des pauses de 15 images. SEQUENCE COMPLETE marque la fin du programme ; utilisez l’enregistrement pour apprécier le son.


Commande de compilation
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-disasmImplémentation et source
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
Programme le rapport cyclique, l’enveloppe et la hauteur CH2, puis déclenche l’impulsion.
Syntaxe
void __stackcall Audio_Ch2NoteOn(u8 note, u8 vol_env, u8 duty2);Paramètres
noteIndice de hauteur de 0 à 67. Voir les notes sur le repli de plage et l’écart d’octave de CH3.
vol_envCodage NR12/NR22/NR42 : demi-octet haut pour le volume initial, bit 3 pour une enveloppe croissante, trois bits bas pour sa période. 0xC0 maintient le volume à 12.
duty2Rapport cyclique : 0=12,5 %, 1=25 %, 3=75 % ; toutes les autres valeurs choisissent 50 %.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
note indexe une table de hauteurs de 0 à 67 : 0 correspond à C2 et 33 à A4. Les valeurs supérieures à 67 sont bornées à 67 ; 60..67 utilisent les fréquences de 48..55. Au même indice, CH3 sonne une octave sous un canal d’impulsion. Les fonctions de déclenchement agissent directement sur le matériel, sans vérifier l’activation ni la pause.
Exemple d’utilisation
// 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();
}Résultat attendu
Après environ une demi-seconde de silence, écoutez CH1 A4, CH2 A4, CH3 A3 puis le bruit. Chaque voix dure 30 images, avec des pauses de 15 images. SEQUENCE COMPLETE marque la fin du programme ; utilisez l’enregistrement pour apprécier le son.


Commande de compilation
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-disasmImplémentation et source
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
Déclenche l’onde CH3 chargée à la hauteur et au niveau NR32 demandés.
Syntaxe
void __stackcall Audio_Ch3NoteOn(u8 note, u8 level);Paramètres
noteIndice de hauteur de 0 à 67. Voir les notes sur le repli de plage et l’écart d’octave de CH3.
levelCodage NR32 : 0x00=muet, 0x20=100 %, 0x40=50 %, 0x60=25 %.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
note indexe une table de hauteurs de 0 à 67 : 0 correspond à C2 et 33 à A4. Les valeurs supérieures à 67 sont bornées à 67 ; 60..67 utilisent les fréquences de 48..55. Au même indice, CH3 sonne une octave sous un canal d’impulsion. Les fonctions de déclenchement agissent directement sur le matériel, sans vérifier l’activation ni la pause.
Exemple d’utilisation
// 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();
}Résultat attendu
Après environ une demi-seconde de silence, écoutez CH1 A4, CH2 A4, CH3 A3 puis le bruit. Chaque voix dure 30 images, avec des pauses de 15 images. SEQUENCE COMPLETE marque la fin du programme ; utilisez l’enregistrement pour apprécier le son.


Commande de compilation
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-disasmImplémentation et source
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
Mémorise les paramètres de bruit, programme les registres d’enveloppe et de compteur polynomial, puis déclenche CH4.
Syntaxe
void __stackcall Audio_Ch4NoteOn(u8 param, u8 vol_env);Paramètres
paramNR43 brut : bits 7..4 pour le décalage d’horloge, bit 3 pour le LFSR court, bits 2..0 pour le code de diviseur.
vol_envCodage NR12/NR22/NR42 : demi-octet haut pour le volume initial, bit 3 pour une enveloppe croissante, trois bits bas pour sa période. 0xC0 maintient le volume à 12.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
L’arrêt automatique par longueur n’est pas activé. Terminez le son avec l’enveloppe ou un arrêt explicite.
Exemple d’utilisation
// 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();
}Résultat attendu
Après environ une demi-seconde de silence, écoutez CH1 A4, CH2 A4, CH3 A3 puis le bruit. Chaque voix dure 30 images, avec des pauses de 15 images. SEQUENCE COMPLETE marque la fin du programme ; utilisez l’enregistrement pour apprécier le son.


Commande de compilation
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-disasmImplémentation et source
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
Rapproche chaque niveau de sortie d’un pas de sa cible à l’intervalle demandé.
Syntaxe
void __stackcall Audio_FadeToMasterVolume(u8 left, u8 right, u8 step_frames);Paramètres
leftNiveau maître gauche, de 0 à 7 ; les valeurs supérieures sont bornées à 7. Zéro n’est pas un silence complet.
rightNiveau maître droit, de 0 à 7 ; les valeurs supérieures sont bornées à 7.
step_framesNombre d’appels Audio_Update par changement d’un niveau. Zéro applique immédiatement la cible.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Incluez audio_hwregs_gb.c avant audio.c et appelez Audio_Init au démarrage. Appelez Audio_Update exactement une fois par image, à environ 59,7 Hz. La lecture du flux modifie temporairement le mappage ROM ; ne réentrez pas dans ce pilote depuis une interruption.
Exemple d’utilisation
// 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();
}Résultat attendu
A4 passe à gauche, à droite puis au centre. Au centre, le niveau descend de 7 à 1, puis remonte à 4 et s’y maintient. Le niveau 0 reste faiblement audible ; arrêter le canal produit le silence. Un changement de routage peut laisser un transitoire de filtre qui décroît.


Commande de compilation
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-disasmImplémentation et source
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
Active l’APU, initialise les états musique, effets, pause, mixage et onde, et laisse tous les canaux silencieux.
Syntaxe
void Audio_Init();Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Incluez audio_hwregs_gb.c avant audio.c et appelez Audio_Init au démarrage. Appelez Audio_Update exactement une fois par image, à environ 59,7 Hz. La lecture du flux modifie temporairement le mappage ROM ; ne réentrez pas dans ce pilote depuis une interruption.
Exemple d’utilisation
// 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();
}Résultat attendu
Après environ une demi-seconde de silence, écoutez CH1 A4, CH2 A4, CH3 A3 puis le bruit. Chaque voix dure 30 images, avec des pauses de 15 images. SEQUENCE COMPLETE marque la fin du programme ; utilisez l’enregistrement pour apprécier le son.


Commande de compilation
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-disasmImplémentation et source
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
Copie seize octets dans le cache d’onde personnalisée et la RAM d’onde CH3.
Syntaxe
void __stackcall Audio_LoadCustomWave(const u8 *wave16);Paramètres
wave16Seize octets lisibles ; les demi-octets haut et bas codent des échantillons successifs. NULL est ignoré.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
L’appelant peut réutiliser la source après copie. La fonction désactive le DAC pour écrire ; l’appelant doit redéclencher une note.
Exemple d’utilisation
// 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();
}Résultat attendu
Écoutez le préréglage triangle, une onde d’impulsion originale, puis la même onde rechargée depuis le cache. Chaque son dure 45 images, avec des pauses de 15 images. Tous sont à environ 220 Hz ; seul le premier a un timbre différent.


Commande de compilation
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-disasmImplémentation et source
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
Installe une onde prédéfinie ou personnalisée en cache dans la RAM d’onde CH3.
Syntaxe
void __stackcall Audio_LoadWave(u8 wave_id);Paramètres
wave_idIdentifiant AUDIO_WAVE_* de 0 à 7 ; 7 choisit l’onde personnalisée en cache. Les valeurs supérieures à 7 n’ont aucun effet.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Le chargement ne déclenche pas de note et ne modifie pas Audio_Ch3Wave. Le préréglage triangle remet aussi le cache personnalisé à une onde triangulaire. Appelez Audio_Ch3NoteOn pour déclencher la voix.
Exemple d’utilisation
// 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();
}Résultat attendu
Écoutez le préréglage triangle, une onde d’impulsion originale, puis la même onde rechargée depuis le cache. Chaque son dure 45 images, avec des pauses de 15 images. Tous sont à environ 220 Hz ; seul le premier a un timbre différent.


Commande de compilation
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-disasmImplémentation et source
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
Prépare le morceau de la banque indiquée depuis son début et réinitialise instruments, panoramique et delay.
Syntaxe
void __stackcall Audio_PlayMusic(u8 bank, u8 *song);Paramètres
bankBanque ROM contenant le flux ; elle doit correspondre à son emplacement.
songAdresse de début du morceau. Le pilote emprunte le tableau, qui doit rester lisible pendant toute la lecture.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Incluez audio_hwregs_gb.c avant audio.c et appelez Audio_Init au démarrage. Appelez Audio_Update exactement une fois par image, à environ 59,7 Hz. La lecture du flux modifie temporairement le mappage ROM ; ne réentrez pas dans ce pilote depuis une interruption.
Le prochain Audio_Update lit les données. NULL n’est pas vérifié. Les effets existants restent actifs.
Exemple d’utilisation
// 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();
}Résultat attendu
Écoutez une note, le silence de pause, la reprise, une note maintenue lorsque la musique est désactivée, le silence explicite du canal, la note suivante après réactivation, puis l’arrêt. La RAM confirme aussi que 30 mises à jour en pause préservent delay, tandis que la simple désactivation le fait avancer jusqu’à 30.


Commande de compilation
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-disasmImplémentation et source
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
Mémorise la banque ROM courante et demande un effet héritant du panoramique de base.
Syntaxe
void __stackcall Audio_PlaySFX(u8 *sfx, u8 priority);Paramètres
sfxDébut du flux d’octets de l’effet. Voir les notes pour les formats d’impulsion et CH3.
priorityPriorité de 0 à 255. La plus grande gagne ; une valeur égale peut aussi remplacer l’effet courant.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Un effet consomme une paire (note,value) par mise à jour et se termine à note=0. value correspond à NR12 pour les effets d’impulsion, à NR32 pour CH3. Préfixez les données CH3 par 0xFF. Conservez le stockage jusqu’à la fin. Les priorités s’appliquent au sein d’un emplacement ; une priorité égale peut remplacer l’effet courant.
Dans la configuration ordinaire, la libération d’un effet coupe CH3. Elle coupe CH1 si la musique est arrêtée, mais ne rejoue pas automatiquement une ancienne note lorsque la musique tourne. Avec AUDIO_VBLANK_SFX_RESTORE, elle demande la restauration par l’ISR.
Exemple d’utilisation
// 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();
}Résultat attendu
Les données de la banque 2 jouent une courte montée d’impulsion à gauche, un effet d’onde à droite puis une impulsion centrée. Les exemples suivants arrêtent tôt une impulsion droite, désactivent un effet puis réactivent la lecture. Une requête de priorité 4 ne peut pas remplacer la priorité 5.


Commande de compilation
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-disasmImplémentation et source
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
Identifie le type d’effet dans sa banque source explicite et demande sa lecture avec le panoramique de base.
Syntaxe
void __stackcall Audio_PlaySFXBanked(u8 bank, u8 *sfx, u8 priority);Paramètres
bankBanque ROM contenant le flux ; elle doit correspondre à son emplacement.
sfxDébut du flux d’octets de l’effet. Voir les notes pour les formats d’impulsion et CH3.
priorityPriorité de 0 à 255. La plus grande gagne ; une valeur égale peut aussi remplacer l’effet courant.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Un effet consomme une paire (note,value) par mise à jour et se termine à note=0. value correspond à NR12 pour les effets d’impulsion, à NR32 pour CH3. Préfixez les données CH3 par 0xFF. Conservez le stockage jusqu’à la fin. Les priorités s’appliquent au sein d’un emplacement ; une priorité égale peut remplacer l’effet courant.
Dans la configuration ordinaire, la libération d’un effet coupe CH3. Elle coupe CH1 si la musique est arrêtée, mais ne rejoue pas automatiquement une ancienne note lorsque la musique tourne. Avec AUDIO_VBLANK_SFX_RESTORE, elle demande la restauration par l’ISR.
Exemple d’utilisation
// 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();
}Résultat attendu
Les données de la banque 2 jouent une courte montée d’impulsion à gauche, un effet d’onde à droite puis une impulsion centrée. Les exemples suivants arrêtent tôt une impulsion droite, désactivent un effet puis réactivent la lecture. Une requête de priorité 4 ne peut pas remplacer la priorité 5.


Commande de compilation
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-disasmImplémentation et source
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
Mémorise la banque ROM courante et demande un effet avec un panoramique imposé.
Syntaxe
void __stackcall Audio_PlaySFXPanned(u8 *sfx, u8 priority, u8 pan);Paramètres
sfxDébut du flux d’octets de l’effet. Voir les notes pour les formats d’impulsion et CH3.
priorityPriorité de 0 à 255. La plus grande gagne ; une valeur égale peut aussi remplacer l’effet courant.
pan0=centre, 1=gauche, 2=droite, 3=muet. Les API d’effet interprètent les valeurs supérieures à 3, dont 0xFF, comme l’héritage du panoramique de base.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Un effet consomme une paire (note,value) par mise à jour et se termine à note=0. value correspond à NR12 pour les effets d’impulsion, à NR32 pour CH3. Préfixez les données CH3 par 0xFF. Conservez le stockage jusqu’à la fin. Les priorités s’appliquent au sein d’un emplacement ; une priorité égale peut remplacer l’effet courant.
Dans la configuration ordinaire, la libération d’un effet coupe CH3. Elle coupe CH1 si la musique est arrêtée, mais ne rejoue pas automatiquement une ancienne note lorsque la musique tourne. Avec AUDIO_VBLANK_SFX_RESTORE, elle demande la restauration par l’ISR.
Exemple d’utilisation
// 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();
}Résultat attendu
Les données de la banque 2 jouent une courte montée d’impulsion à gauche, un effet d’onde à droite puis une impulsion centrée. Les exemples suivants arrêtent tôt une impulsion droite, désactivent un effet puis réactivent la lecture. Une requête de priorité 4 ne peut pas remplacer la priorité 5.


Commande de compilation
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-disasmImplémentation et source
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
Réserve un emplacement d’effet d’impulsion ou CH3 avec banque, priorité et panoramique explicites.
Syntaxe
void __stackcall Audio_PlaySFXPannedBanked(u8 bank, u8 *sfx, u8 priority, u8 pan);Paramètres
bankBanque ROM contenant le flux ; elle doit correspondre à son emplacement.
sfxDébut du flux d’octets de l’effet. Voir les notes pour les formats d’impulsion et CH3.
priorityPriorité de 0 à 255. La plus grande gagne ; une valeur égale peut aussi remplacer l’effet courant.
pan0=centre, 1=gauche, 2=droite, 3=muet. Les API d’effet interprètent les valeurs supérieures à 3, dont 0xFF, comme l’héritage du panoramique de base.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Un effet consomme une paire (note,value) par mise à jour et se termine à note=0. value correspond à NR12 pour les effets d’impulsion, à NR32 pour CH3. Préfixez les données CH3 par 0xFF. Conservez le stockage jusqu’à la fin. Les priorités s’appliquent au sein d’un emplacement ; une priorité égale peut remplacer l’effet courant.
Dans la configuration ordinaire, la libération d’un effet coupe CH3. Elle coupe CH1 si la musique est arrêtée, mais ne rejoue pas automatiquement une ancienne note lorsque la musique tourne. Avec AUDIO_VBLANK_SFX_RESTORE, elle demande la restauration par l’ISR.
Exemple d’utilisation
// 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();
}Résultat attendu
Les données de la banque 2 jouent une courte montée d’impulsion à gauche, un effet d’onde à droite puis une impulsion centrée. Les exemples suivants arrêtent tôt une impulsion droite, désactivent un effet puis réactivent la lecture. Une requête de priorité 4 ne peut pas remplacer la priorité 5.


Commande de compilation
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-disasmImplémentation et source
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
Mémorise le rapport cyclique de la prochaine note CH1.
Syntaxe
void __stackcall Audio_SetCh1Duty(u8 duty);Paramètres
dutyIndice de rapport cyclique ; les deux bits bas sont stockés. 0=12,5 %, 1=25 %, 2=50 %, 3=75 %.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Cet appel seul ne change pas les registres audio actifs. Passez la valeur mémorisée au déclenchement de note ou utilisez le flux correspondant pour l’appliquer.
Exemple d’utilisation
// 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();
}Résultat attendu
Après environ une demi-seconde de silence, écoutez CH1 A4, CH2 A4, CH3 A3 puis le bruit. Chaque voix dure 30 images, avec des pauses de 15 images. SEQUENCE COMPLETE marque la fin du programme ; utilisez l’enregistrement pour apprécier le son.


Commande de compilation
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-disasmImplémentation et source
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
Mémorise le rapport cyclique de la prochaine note CH2.
Syntaxe
void __stackcall Audio_SetCh2Duty(u8 duty);Paramètres
dutyIndice de rapport cyclique ; les deux bits bas sont stockés. 0=12,5 %, 1=25 %, 2=50 %, 3=75 %.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Cet appel seul ne change pas les registres audio actifs. Passez la valeur mémorisée au déclenchement de note ou utilisez le flux correspondant pour l’appliquer.
Exemple d’utilisation
// 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();
}Résultat attendu
Après environ une demi-seconde de silence, écoutez CH1 A4, CH2 A4, CH3 A3 puis le bruit. Chaque voix dure 30 images, avec des pauses de 15 images. SEQUENCE COMPLETE marque la fin du programme ; utilisez l’enregistrement pour apprécier le son.


Commande de compilation
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-disasmImplémentation et source
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
Mémorise le niveau de sortie NR32 de la prochaine note CH3.
Syntaxe
void __stackcall Audio_SetCh3Level(u8 level);Paramètres
levelCodage NR32 : 0x00=muet, 0x20=100 %, 0x40=50 %, 0x60=25 %.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Cet appel seul ne change pas les registres audio actifs. Passez la valeur mémorisée au déclenchement de note ou utilisez le flux correspondant pour l’appliquer.
Exemple d’utilisation
// 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();
}Résultat attendu
Après environ une demi-seconde de silence, écoutez CH1 A4, CH2 A4, CH3 A3 puis le bruit. Chaque voix dure 30 images, avec des pauses de 15 images. SEQUENCE COMPLETE marque la fin du programme ; utilisez l’enregistrement pour apprécier le son.


Commande de compilation
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-disasmImplémentation et source
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
Mémorise les paramètres de bruit NR43 de la prochaine note CH4.
Syntaxe
void __stackcall Audio_SetCh4Param(u8 param);Paramètres
paramNR43 brut : bits 7..4 pour le décalage d’horloge, bit 3 pour le LFSR court, bits 2..0 pour le code de diviseur.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Cet appel seul ne change pas les registres audio actifs. Passez la valeur mémorisée au déclenchement de note ou utilisez le flux correspondant pour l’appliquer.
Exemple d’utilisation
// 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();
}Résultat attendu
Après environ une demi-seconde de silence, écoutez CH1 A4, CH2 A4, CH3 A3 puis le bruit. Chaque voix dure 30 images, avec des pauses de 15 images. SEQUENCE COMPLETE marque la fin du programme ; utilisez l’enregistrement pour apprécier le son.


Commande de compilation
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-disasmImplémentation et source
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
Borne les niveaux maîtres gauche/droit à 0..7, les écrit immédiatement et annule le fondu actif.
Syntaxe
void __stackcall Audio_SetMasterVolume(u8 left, u8 right);Paramètres
leftNiveau maître gauche, de 0 à 7 ; les valeurs supérieures sont bornées à 7. Zéro n’est pas un silence complet.
rightNiveau maître droit, de 0 à 7 ; les valeurs supérieures sont bornées à 7.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Exemple d’utilisation
// 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();
}Résultat attendu
A4 passe à gauche, à droite puis au centre. Au centre, le niveau descend de 7 à 1, puis remonte à 4 et s’y maintient. Le niveau 0 reste faiblement audible ; arrêter le canal produit le silence. Un changement de routage peut laisser un transitoire de filtre qui décroît.


Commande de compilation
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-disasmImplémentation et source
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
Détermine si le décodeur musical ordinaire écrit de nouvelles notes.
Syntaxe
void __stackcall Audio_SetMusicEnabled(u8 on);Paramètres
onZéro désactive, non-zéro active. Consultez la description pour distinguer mise en sourdine et suspension des mises à jour.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
La désactivation laisse avancer le flux et traite instruments et panoramique. Elle ne coupe pas la note courante. Utilisez Audio_SetPaused pour mettre la lecture en pause.
Exemple d’utilisation
// 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();
}Résultat attendu
Écoutez une note, le silence de pause, la reprise, une note maintenue lorsque la musique est désactivée, le silence explicite du canal, la note suivante après réactivation, puis l’arrêt. La RAM confirme aussi que 30 mises à jour en pause préservent delay, tandis que la simple désactivation le fait avancer jusqu’à 30.


Commande de compilation
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-disasmImplémentation et source
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
Modifie le panoramique de base d’une voix physique, puis réapplique les remplacements des effets actifs.
Syntaxe
void __stackcall Audio_SetPan(u8 ch, u8 pan);Paramètres
chIdentifiants de canal : 0=CH1, 1=CH2, 2=CH3, 3=CH4. Les API directes et les flux musicaux utilisent les mêmes identifiants.
pan0=centre, 1=gauche, 2=droite, 3=muet. Les API d’effet interprètent les valeurs supérieures à 3, dont 0xFF, comme l’héritage du panoramique de base.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Un canal inconnu sélectionne CH4. Ici, pan hors de 0..3 coupe le son ; ce n’est pas le réglage d’héritage des API d’effet.
Exemple d’utilisation
// 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();
}Résultat attendu
A4 passe à gauche, à droite puis au centre. Au centre, le niveau descend de 7 à 1, puis remonte à 4 et s’y maintient. Le niveau 0 reste faiblement audible ; arrêter le canal produit le silence. Un changement de routage peut laisser un transitoire de filtre qui décroît.


Commande de compilation
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-disasmImplémentation et source
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
Décompacte quatre panoramiques de base depuis un octet et met à jour NR51 une seule fois.
Syntaxe
void __stackcall Audio_SetPanPacked(u8 packed);Paramètres
packedDeux bits par canal physique : CH1 bits 0..1, CH2 2..3, CH3 4..5, CH4 6..7. Chaque champ utilise les valeurs de panoramique.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Exemple d’utilisation
// 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();
}Résultat attendu
A4 passe à gauche, à droite puis au centre. Au centre, le niveau descend de 7 à 1, puis remonte à 4 et s’y maintient. Le niveau 0 reste faiblement audible ; arrêter le canal produit le silence. Un changement de routage peut laisser un transitoire de filtre qui décroît.


Commande de compilation
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-disasmImplémentation et source
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
Coupe le son en pause tout en conservant les positions musique/effets. La reprise redéclenche les notes admissibles de CH1, CH2 et CH4.
Syntaxe
void __stackcall Audio_SetPaused(u8 on);Paramètres
onZéro désactive, non-zéro active. Consultez la description pour distinguer mise en sourdine et suspension des mises à jour.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Incluez audio_hwregs_gb.c avant audio.c et appelez Audio_Init au démarrage. Appelez Audio_Update exactement une fois par image, à environ 59,7 Hz. La lecture du flux modifie temporairement le mappage ROM ; ne réentrez pas dans ce pilote depuis une interruption.
Cette routine ne redéclenche pas CH3. Les effets continuent lors d’une mise à jour ultérieure. Les appels directs de note peuvent encore sonner pendant la pause.
Exemple d’utilisation
// 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();
}Résultat attendu
Écoutez une note, le silence de pause, la reprise, une note maintenue lorsque la musique est désactivée, le silence explicite du canal, la note suivante après réactivation, puis l’arrêt. La RAM confirme aussi que 30 mises à jour en pause préservent delay, tandis que la simple désactivation le fait avancer jusqu’à 30.


Commande de compilation
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-disasmImplémentation et source
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
Autorise ou bloque les écritures de notes d’effet ; la désactivation libère aussi les emplacements d’effet.
Syntaxe
void __stackcall Audio_SetSfxEnabled(u8 on);Paramètres
onZéro désactive, non-zéro active. Consultez la description pour distinguer mise en sourdine et suspension des mises à jour.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Dans la configuration ordinaire, la libération d’un effet coupe CH3. Elle coupe CH1 si la musique est arrêtée, mais ne rejoue pas automatiquement une ancienne note lorsque la musique tourne. Avec AUDIO_VBLANK_SFX_RESTORE, elle demande la restauration par l’ISR.
Démarrer alors que les effets sont désactivés peut enregistrer un flux, mais les mises à jour suppriment ses écritures de notes. Activez les effets avant de demander une lecture audible.
Exemple d’utilisation
// 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();
}Résultat attendu
Les données de la banque 2 jouent une courte montée d’impulsion à gauche, un effet d’onde à droite puis une impulsion centrée. Les exemples suivants arrêtent tôt une impulsion droite, désactivent un effet puis réactivent la lecture. Une requête de priorité 4 ne peut pas remplacer la priorité 5.


Commande de compilation
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-disasmImplémentation et source
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
Arrête une voix physique et retire sa note musicale du masque de reprise.
Syntaxe
void __stackcall Audio_StopChannel(u8 ch);Paramètres
chIdentifiants de canal : 0=CH1, 1=CH2, 2=CH3, 3=CH4. Les API directes et les flux musicaux utilisent les mêmes identifiants.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
CH1/CH3 effacent aussi leur emplacement d’effet. Hors de 0..3, aucun effet. Les notes mémorisées par VBlank sont gérées séparément.
Exemple d’utilisation
// 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();
}Résultat attendu
Après environ une demi-seconde de silence, écoutez CH1 A4, CH2 A4, CH3 A3 puis le bruit. Chaque voix dure 30 images, avec des pauses de 15 images. SEQUENCE COMPLETE marque la fin du programme ; utilisez l’enregistrement pour apprécier le son.


Commande de compilation
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-disasmImplémentation et source
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
Efface la lecture du morceau et son masque de reprise, puis coupe immédiatement les quatre voix.
Syntaxe
void Audio_StopMusic();Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Les pointeurs d’effet restent présents ; un Audio_Update ultérieur peut donc produire un effet. Appelez aussi Audio_StopSfx pour tout arrêter.
Exemple d’utilisation
// 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();
}Résultat attendu
Écoutez une note, le silence de pause, la reprise, une note maintenue lorsque la musique est désactivée, le silence explicite du canal, la note suivante après réactivation, puis l’arrêt. La RAM confirme aussi que 30 mises à jour en pause préservent delay, tandis que la simple désactivation le fait avancer jusqu’à 30.


Commande de compilation
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-disasmImplémentation et source
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
Efface les deux flux d’effet et leurs panoramiques imposés, puis libère les canaux empruntés.
Syntaxe
void Audio_StopSfx();Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Un effet consomme une paire (note,value) par mise à jour et se termine à note=0. value correspond à NR12 pour les effets d’impulsion, à NR32 pour CH3. Préfixez les données CH3 par 0xFF. Conservez le stockage jusqu’à la fin. Les priorités s’appliquent au sein d’un emplacement ; une priorité égale peut remplacer l’effet courant.
Dans la configuration ordinaire, la libération d’un effet coupe CH3. Elle coupe CH1 si la musique est arrêtée, mais ne rejoue pas automatiquement une ancienne note lorsque la musique tourne. Avec AUDIO_VBLANK_SFX_RESTORE, elle demande la restauration par l’ISR.
Exemple d’utilisation
// 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();
}Résultat attendu
Les données de la banque 2 jouent une courte montée d’impulsion à gauche, un effet d’onde à droite puis une impulsion centrée. Les exemples suivants arrêtent tôt une impulsion droite, désactivent un effet puis réactivent la lecture. Une requête de priorité 4 ne peut pas remplacer la priorité 5.


Commande de compilation
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-disasmImplémentation et source
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
Avance le fondu de volume d’un pas ; hors pause, traite ensuite les effets puis la musique.
Syntaxe
void Audio_Update();Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Incluez audio_hwregs_gb.c avant audio.c et appelez Audio_Init au démarrage. Appelez Audio_Update exactement une fois par image, à environ 59,7 Hz. La lecture du flux modifie temporairement le mappage ROM ; ne réentrez pas dans ce pilote depuis une interruption.
Les fondus continuent pendant la pause. La lecture de WAIT n est suivie de n appels d’attente ; la commande suivante arrive donc après n+1 mises à jour.
Exemple d’utilisation
// 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();
}Résultat attendu
Écoutez une note, le silence de pause, la reprise, une note maintenue lorsque la musique est désactivée, le silence explicite du canal, la note suivante après réactivation, puis l’arrêt. La RAM confirme aussi que 30 mises à jour en pause préservent delay, tandis que la simple désactivation le fait avancer jusqu’à 30.


Commande de compilation
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-disasmImplémentation et source
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 — Lecture musicale par interruption VBlank
Traite la musique en VBlank, coordonne l’occupation des voix par les effets et fournit un hook par image. Ne faites pas aussi avancer le même morceau avec le décodeur musical ordinaire.
audio_vblank.c implémente __kq_vblank_vector ; n’installez pas un autre vecteur VBlank concurrent. L’exemple définit Audio_NoiseEffectActive, exclut le décodeur musical ordinaire et réserve Audio_Update aux effets et fondus. Masquez les interruptions lorsque vous modifiez les pointeurs de morceau ou l’état partagé.
Gardez les données musicales directes en ROM fixe ou dans une zone toujours visible par l’ISR. Un enregistrement contient cinq octets : delay, CH1, CH2, CH3, CH4. Dans les champs de note, 0xFF maintient la voix et 0xFD l’arrête. Dans delay, 0xFF termine la lecture et 0xFE boucle. Il s’agit de l’ordre des champs, pas des identifiants de canal. La file WRAM est un mode distinct ; fournissez des enregistrements complets de cinq octets avec AudioVBlank_QueueRefill.
AudioVBlank_DisableIrq
Efface seulement le bit VBlank de IE, sans modifier les autres sources d’interruption ni le son.
Syntaxe
void AudioVBlank_DisableIrq();Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
audio_vblank.c implémente __kq_vblank_vector ; n’installez pas un autre vecteur VBlank concurrent. L’exemple définit Audio_NoiseEffectActive, exclut le décodeur musical ordinaire et réserve Audio_Update aux effets et fondus. Masquez les interruptions lorsque vous modifiez les pointeurs de morceau ou l’état partagé.
Gardez les données musicales directes en ROM fixe ou dans une zone toujours visible par l’ISR. Un enregistrement contient cinq octets : delay, CH1, CH2, CH3, CH4. Dans les champs de note, 0xFF maintient la voix et 0xFD l’arrête. Dans delay, 0xFF termine la lecture et 0xFE boucle. Il s’agit de l’ordre des champs, pas des identifiants de canal. La file WRAM est un mode distinct ; fournissez des enregistrements complets de cinq octets avec AudioVBlank_QueueRefill.
Exemple d’utilisation
// 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();
}Résultat attendu
L’ISR joue un morceau de deux notes. Comparez la suspension des mises à jour musicales, qui conserve le son, Stop, qui le coupe, et la désactivation IRQ après redémarrage, qui conserve aussi le son. La RAM vérifie que le hook tourne musique désactivée et s’arrête IRQ désactivée.


Commande de compilation
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-disasmImplémentation et source
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
Active le bit VBlank de IE et exécute EI pour autoriser globalement les interruptions CPU.
Syntaxe
void AudioVBlank_EnableIrq();Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
audio_vblank.c implémente __kq_vblank_vector ; n’installez pas un autre vecteur VBlank concurrent. L’exemple définit Audio_NoiseEffectActive, exclut le décodeur musical ordinaire et réserve Audio_Update aux effets et fondus. Masquez les interruptions lorsque vous modifiez les pointeurs de morceau ou l’état partagé.
Gardez les données musicales directes en ROM fixe ou dans une zone toujours visible par l’ISR. Un enregistrement contient cinq octets : delay, CH1, CH2, CH3, CH4. Dans les champs de note, 0xFF maintient la voix et 0xFD l’arrête. Dans delay, 0xFF termine la lecture et 0xFE boucle. Il s’agit de l’ordre des champs, pas des identifiants de canal. La file WRAM est un mode distinct ; fournissez des enregistrements complets de cinq octets avec AudioVBlank_QueueRefill.
Exemple d’utilisation
// 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();
}Résultat attendu
L’ISR joue un morceau de deux notes. Comparez la suspension des mises à jour musicales, qui conserve le son, Stop, qui le coupe, et la désactivation IRQ après redémarrage, qui conserve aussi le son. La RAM vérifie que le hook tourne musique désactivée et s’arrête IRQ désactivée.


Commande de compilation
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-disasmImplémentation et source
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
Initialise l’état musical VBlank, la file, les instruments et le hook. N’initialise pas l’APU et ne masque pas les interruptions.
Syntaxe
void AudioVBlank_Init();Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
audio_vblank.c implémente __kq_vblank_vector ; n’installez pas un autre vecteur VBlank concurrent. L’exemple définit Audio_NoiseEffectActive, exclut le décodeur musical ordinaire et réserve Audio_Update aux effets et fondus. Masquez les interruptions lorsque vous modifiez les pointeurs de morceau ou l’état partagé.
Gardez les données musicales directes en ROM fixe ou dans une zone toujours visible par l’ISR. Un enregistrement contient cinq octets : delay, CH1, CH2, CH3, CH4. Dans les champs de note, 0xFF maintient la voix et 0xFD l’arrête. Dans delay, 0xFF termine la lecture et 0xFE boucle. Il s’agit de l’ordre des champs, pas des identifiants de canal. La file WRAM est un mode distinct ; fournissez des enregistrements complets de cinq octets avec AudioVBlank_QueueRefill.
Exemple d’utilisation
// 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();
}Résultat attendu
L’ISR joue un morceau de deux notes. Comparez la suspension des mises à jour musicales, qui conserve le son, Stop, qui le coupe, et la désactivation IRQ après redémarrage, qui conserve aussi le son. La RAM vérifie que le hook tourne musique désactivée et s’arrête IRQ désactivée.


Commande de compilation
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-disasmImplémentation et source
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
Redémarre le morceau choisi depuis le début et quitte le mode file. Un morceau NULL arrête la lecture.
Syntaxe
void AudioVBlank_Play();Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
audio_vblank.c implémente __kq_vblank_vector ; n’installez pas un autre vecteur VBlank concurrent. L’exemple définit Audio_NoiseEffectActive, exclut le décodeur musical ordinaire et réserve Audio_Update aux effets et fondus. Masquez les interruptions lorsque vous modifiez les pointeurs de morceau ou l’état partagé.
Gardez les données musicales directes en ROM fixe ou dans une zone toujours visible par l’ISR. Un enregistrement contient cinq octets : delay, CH1, CH2, CH3, CH4. Dans les champs de note, 0xFF maintient la voix et 0xFD l’arrête. Dans delay, 0xFF termine la lecture et 0xFE boucle. Il s’agit de l’ordre des champs, pas des identifiants de canal. La file WRAM est un mode distinct ; fournissez des enregistrements complets de cinq octets avec AudioVBlank_QueueRefill.
Exemple d’utilisation
// 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();
}Résultat attendu
L’ISR joue un morceau de deux notes. Comparez la suspension des mises à jour musicales, qui conserve le son, Stop, qui le coupe, et la désactivation IRQ après redémarrage, qui conserve aussi le son. La RAM vérifie que le hook tourne musique désactivée et s’arrête IRQ désactivée.


Commande de compilation
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-disasmImplémentation et source
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
Sélectionne un morceau en lecture directe et prépare sa lecture depuis le début.
Syntaxe
void __stackcall AudioVBlank_PlayMusic(u8 *song);Paramètres
songAdresse de début du morceau. Le pilote emprunte le tableau, qui doit rester lisible pendant toute la lecture.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
audio_vblank.c implémente __kq_vblank_vector ; n’installez pas un autre vecteur VBlank concurrent. L’exemple définit Audio_NoiseEffectActive, exclut le décodeur musical ordinaire et réserve Audio_Update aux effets et fondus. Masquez les interruptions lorsque vous modifiez les pointeurs de morceau ou l’état partagé.
Gardez les données musicales directes en ROM fixe ou dans une zone toujours visible par l’ISR. Un enregistrement contient cinq octets : delay, CH1, CH2, CH3, CH4. Dans les champs de note, 0xFF maintient la voix et 0xFD l’arrête. Dans delay, 0xFF termine la lecture et 0xFE boucle. Il s’agit de l’ordre des champs, pas des identifiants de canal. La file WRAM est un mode distinct ; fournissez des enregistrements complets de cinq octets avec AudioVBlank_QueueRefill.
Exemple d’utilisation
// 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();
}Résultat attendu
L’ISR joue un morceau de deux notes. Comparez la suspension des mises à jour musicales, qui conserve le son, Stop, qui le coupe, et la désactivation IRQ après redémarrage, qui conserve aussi le son. La RAM vérifie que le hook tourne musique désactivée et s’arrête IRQ désactivée.


Commande de compilation
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-disasmImplémentation et source
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
Consultez les changements et vérifications du 2026-10-03 pour les différences locales de cette API.
Active la lecture si le mode file est actif et si au moins un enregistrement est disponible. Conserve les curseurs, le délai, l’activation de la musique et l’état de pause. Réinitialisez et préremplissez la file avant de lancer un nouveau flux.
Syntaxe
u8 AudioVBlank_QueuePlay();Valeur renvoyée
Renvoie un si la demande est acceptée, ou zéro si la file est vide ou si le mode file est inactif. Pour consommer les enregistrements, l’interruption doit fonctionner, la musique doit être activée et le pilote ne doit pas être en pause.
Conditions et limites
Après AudioVBlank_Init, appelez QueueReset, QueueRefill puis QueuePlay, dans cet ordre. Compilez la version normale de audio_vblank.c : AUDIO_VBLANK_CORE_ONLY exclut les fonctions C qui alimentent la file. Le code principal remplit une file de seize enregistrements de cinq octets, consommés par la routine d’interruption VBlank.
Un seul producteur, dans le code principal, doit alimenter la file. Ne l’appelez ni récursivement, ni depuis une routine d’interruption ou FrameHook. Chaque brève étape rendant un enregistrement disponible sauvegarde IE et masque les sources d’interruption, puis restaure IE et SVBK. IME reste inchangé. Le code appelant doit sélectionner et maintenir la banque ROM/RAM source.
Les enregistrements temporisés contiennent delay, ch1_note, ch2_note, ch3_note et ch4_noise_param. Fournissez aussi END sous la forme d’un enregistrement complet de cinq octets. Le producteur doit développer LOOP en soumettant à nouveau les enregistrements nécessaires. Ne transmettez pas tel quel un flux de commandes de lecture directe à longueur variable.
Exemple d’utilisation
if(AudioVBlank_QueuePlay()==0) sound_result[0]++;
AudioVBlank_EnableIrq();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple joue six fois une phrase originale de huit notes, puis s’arrête. Il fait passer 49 enregistrements — 48 notes et END — par la file de seize emplacements. Les vérifications portent sur l’acceptation des 49 enregistrements, l’absence de sous-alimentation, l’arrêt de la lecture, les cas file vide ou pleine, pointeur nul et nombre nul, la restauration de la banque WRAM sur CGB, la conservation d’IME, le son pendant la lecture et le silence après celle-ci.


Commande de compilation
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-disasmImplémentation et source
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
Consultez les changements et vérifications du 2026-10-03 pour les différences locales de cette API.
Copie des enregistrements complets de cinq octets dans les emplacements libres, puis ne rend chacun disponible qu’une fois sa copie terminée. Un appel accepte au plus seize enregistrements.
Syntaxe
u8 __stackcall AudioVBlank_QueueRefill(const u8 *records, u8 count);Paramètres
recordsTableau d’enregistrements dans la banque actuellement lisible. Prévoyez cinq octets lisibles par enregistrement accepté. Un pointeur nul entraîne un retour de zéro.
countNombre d’enregistrements à proposer, et non nombre d’octets. Les valeurs supérieures à seize sont limitées à seize ; zéro ne fait rien.
Valeur renvoyée
Renvoie le nombre d’enregistrements effectivement acceptés, de 0 à 16. Renvoie zéro si la file est pleine, si le pointeur d’entrée est nul, si le nombre demandé est nul ou si le mode file est inactif. Avancez la source de cinq fois la valeur renvoyée. L’interruption peut libérer des emplacements pendant l’appel : ce résultat ne correspond donc pas forcément au nombre d’emplacements libres à l’entrée.
Conditions et limites
Après AudioVBlank_Init, appelez QueueReset, QueueRefill puis QueuePlay, dans cet ordre. Compilez la version normale de audio_vblank.c : AUDIO_VBLANK_CORE_ONLY exclut les fonctions C qui alimentent la file. Le code principal remplit une file de seize enregistrements de cinq octets, consommés par la routine d’interruption VBlank.
Un seul producteur, dans le code principal, doit alimenter la file. Ne l’appelez ni récursivement, ni depuis une routine d’interruption ou FrameHook. Chaque brève étape rendant un enregistrement disponible sauvegarde IE et masque les sources d’interruption, puis restaure IE et SVBK. IME reste inchangé. Le code appelant doit sélectionner et maintenir la banque ROM/RAM source.
Les enregistrements temporisés contiennent delay, ch1_note, ch2_note, ch3_note et ch4_noise_param. Fournissez aussi END sous la forme d’un enregistrement complet de cinq octets. Le producteur doit développer LOOP en soumettant à nouveau les enregistrements nécessaires. Ne transmettez pas tel quel un flux de commandes de lecture directe à longueur variable.
Exemple d’utilisation
next=AudioVBlank_QueueRefill(queue_song,16);
// next counts records; each record occupies five source bytes.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple joue six fois une phrase originale de huit notes, puis s’arrête. Il fait passer 49 enregistrements — 48 notes et END — par la file de seize emplacements. Les vérifications portent sur l’acceptation des 49 enregistrements, l’absence de sous-alimentation, l’arrêt de la lecture, les cas file vide ou pleine, pointeur nul et nombre nul, la restauration de la banque WRAM sur CGB, la conservation d’IME, le son pendant la lecture et le silence après celle-ci.


Commande de compilation
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-disasmImplémentation et source
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
Consultez les changements et vérifications du 2026-10-03 pour les différences locales de cette API.
Arrête et coupe le son, sélectionne le mode file, puis remet à zéro les positions de lecture et d’écriture, le nombre d’enregistrements et le compteur de sous-alimentations. Les enregistrements en attente sont abandonnés pour préparer un nouveau flux.
Syntaxe
void AudioVBlank_QueueReset();Valeur renvoyée
Aucune valeur de retour. Les réglages d’activation de la musique et de pause sont conservés.
Conditions et limites
Après AudioVBlank_Init, appelez QueueReset, QueueRefill puis QueuePlay, dans cet ordre. Compilez la version normale de audio_vblank.c : AUDIO_VBLANK_CORE_ONLY exclut les fonctions C qui alimentent la file. Le code principal remplit une file de seize enregistrements de cinq octets, consommés par la routine d’interruption VBlank.
Un seul producteur, dans le code principal, doit alimenter la file. Ne l’appelez ni récursivement, ni depuis une routine d’interruption ou FrameHook. Chaque brève étape rendant un enregistrement disponible sauvegarde IE et masque les sources d’interruption, puis restaure IE et SVBK. IME reste inchangé. Le code appelant doit sélectionner et maintenir la banque ROM/RAM source.
Les enregistrements temporisés contiennent delay, ch1_note, ch2_note, ch3_note et ch4_noise_param. Fournissez aussi END sous la forme d’un enregistrement complet de cinq octets. Le producteur doit développer LOOP en soumettant à nouveau les enregistrements nécessaires. Ne transmettez pas tel quel un flux de commandes de lecture directe à longueur variable.
Exemple d’utilisation
AudioVBlank_QueueReset(); // Silence playback and discard any queued records.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple joue six fois une phrase originale de huit notes, puis s’arrête. Il fait passer 49 enregistrements — 48 notes et END — par la file de seize emplacements. Les vérifications portent sur l’acceptation des 49 enregistrements, l’absence de sous-alimentation, l’arrêt de la lecture, les cas file vide ou pleine, pointeur nul et nombre nul, la restauration de la banque WRAM sur CGB, la conservation d’IME, le son pendant la lecture et le silence après celle-ci.


Commande de compilation
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-disasmImplémentation et source
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
Pose la demande 2 de libération seule d’impulsion si rien n’est en attente, en préservant une demande de restauration 1 existante.
Syntaxe
void AudioVBlank_RequestRestoreCh1();Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
audio_vblank.c implémente __kq_vblank_vector ; n’installez pas un autre vecteur VBlank concurrent. L’exemple définit Audio_NoiseEffectActive, exclut le décodeur musical ordinaire et réserve Audio_Update aux effets et fondus. Masquez les interruptions lorsque vous modifiez les pointeurs de morceau ou l’état partagé.
Pour une restauration directe, l’appelant vérifie que l’effet a libéré la voix, puis efface l’indicateur en attente. Les fonctions de demande seules n’écrivent pas les registres audio.
Exemple d’utilisation
// 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();
}Résultat attendu
Écoutez la restauration d’impulsion, le silence, la restauration d’onde puis le silence, chacun pendant 30 images. Une demande de libération préserve la valeur en attente 1 ; sans événement en attente, elle produit la valeur 2, libération seule. Ici, IRQ est désactivé et l’appelant gère explicitement la propriété des canaux.


Commande de compilation
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-disasmImplémentation et source
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
Pose la demande 2 de libération seule d’onde si rien n’est en attente, en préservant une demande de restauration 1 existante.
Syntaxe
void AudioVBlank_RequestRestoreCh3();Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
audio_vblank.c implémente __kq_vblank_vector ; n’installez pas un autre vecteur VBlank concurrent. L’exemple définit Audio_NoiseEffectActive, exclut le décodeur musical ordinaire et réserve Audio_Update aux effets et fondus. Masquez les interruptions lorsque vous modifiez les pointeurs de morceau ou l’état partagé.
Pour une restauration directe, l’appelant vérifie que l’effet a libéré la voix, puis efface l’indicateur en attente. Les fonctions de demande seules n’écrivent pas les registres audio.
Exemple d’utilisation
// 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();
}Résultat attendu
Écoutez la restauration d’impulsion, le silence, la restauration d’onde puis le silence, chacun pendant 30 images. Une demande de libération préserve la valeur en attente 1 ; sans événement en attente, elle produit la valeur 2, libération seule. Ici, IRQ est désactivé et l’appelant gère explicitement la propriété des canaux.


Commande de compilation
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-disasmImplémentation et source
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
Restaure une note musicale mémorisée sur la voix d’impulsion empruntée par un effet (CH1 ou CH2), ou la libère en silence.
Syntaxe
void AudioVBlank_RestoreCh1();Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
audio_vblank.c implémente __kq_vblank_vector ; n’installez pas un autre vecteur VBlank concurrent. L’exemple définit Audio_NoiseEffectActive, exclut le décodeur musical ordinaire et réserve Audio_Update aux effets et fondus. Masquez les interruptions lorsque vous modifiez les pointeurs de morceau ou l’état partagé.
Pour une restauration directe, l’appelant vérifie que l’effet a libéré la voix, puis efface l’indicateur en attente. Les fonctions de demande seules n’écrivent pas les registres audio.
Exemple d’utilisation
// 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();
}Résultat attendu
Écoutez la restauration d’impulsion, le silence, la restauration d’onde puis le silence, chacun pendant 30 images. Une demande de libération préserve la valeur en attente 1 ; sans événement en attente, elle produit la valeur 2, libération seule. Ici, IRQ est désactivé et l’appelant gère explicitement la propriété des canaux.


Commande de compilation
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-disasmImplémentation et source
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
Restaure la note mémorisée de CH3 après libération de l’effet, ou désactive son DAC.
Syntaxe
void AudioVBlank_RestoreCh3();Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
audio_vblank.c implémente __kq_vblank_vector ; n’installez pas un autre vecteur VBlank concurrent. L’exemple définit Audio_NoiseEffectActive, exclut le décodeur musical ordinaire et réserve Audio_Update aux effets et fondus. Masquez les interruptions lorsque vous modifiez les pointeurs de morceau ou l’état partagé.
Pour une restauration directe, l’appelant vérifie que l’effet a libéré la voix, puis efface l’indicateur en attente. Les fonctions de demande seules n’écrivent pas les registres audio.
Exemple d’utilisation
// 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();
}Résultat attendu
Écoutez la restauration d’impulsion, le silence, la restauration d’onde puis le silence, chacun pendant 30 images. Une demande de libération préserve la valeur en attente 1 ; sans événement en attente, elle produit la valeur 2, libération seule. Ici, IRQ est désactivé et l’appelant gère explicitement la propriété des canaux.


Commande de compilation
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-disasmImplémentation et source
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
Autorise ou bloque la musique VBlank et efface les demandes de restauration à la désactivation. Le son courant et IRQ restent inchangés.
Syntaxe
void __stackcall AudioVBlank_SetEnabled(u8 on);Paramètres
onZéro désactive, non-zéro active. Consultez la description pour distinguer mise en sourdine et suspension des mises à jour.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
audio_vblank.c implémente __kq_vblank_vector ; n’installez pas un autre vecteur VBlank concurrent. L’exemple définit Audio_NoiseEffectActive, exclut le décodeur musical ordinaire et réserve Audio_Update aux effets et fondus. Masquez les interruptions lorsque vous modifiez les pointeurs de morceau ou l’état partagé.
Gardez les données musicales directes en ROM fixe ou dans une zone toujours visible par l’ISR. Un enregistrement contient cinq octets : delay, CH1, CH2, CH3, CH4. Dans les champs de note, 0xFF maintient la voix et 0xFD l’arrête. Dans delay, 0xFF termine la lecture et 0xFE boucle. Il s’agit de l’ordre des champs, pas des identifiants de canal. La file WRAM est un mode distinct ; fournissez des enregistrements complets de cinq octets avec AudioVBlank_QueueRefill.
Exemple d’utilisation
// 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();
}Résultat attendu
L’ISR joue un morceau de deux notes. Comparez la suspension des mises à jour musicales, qui conserve le son, Stop, qui le coupe, et la désactivation IRQ après redémarrage, qui conserve aussi le son. La RAM vérifie que le hook tourne musique désactivée et s’arrête IRQ désactivée.


Commande de compilation
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-disasmImplémentation et source
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
Sélectionne un morceau en lecture directe et réinitialise ses curseurs sans changer l’indicateur de lecture.
Syntaxe
void __stackcall AudioVBlank_SetMusic(u8 *song);Paramètres
songAdresse de début du morceau. Le pilote emprunte le tableau, qui doit rester lisible pendant toute la lecture.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
audio_vblank.c implémente __kq_vblank_vector ; n’installez pas un autre vecteur VBlank concurrent. L’exemple définit Audio_NoiseEffectActive, exclut le décodeur musical ordinaire et réserve Audio_Update aux effets et fondus. Masquez les interruptions lorsque vous modifiez les pointeurs de morceau ou l’état partagé.
Gardez les données musicales directes en ROM fixe ou dans une zone toujours visible par l’ISR. Un enregistrement contient cinq octets : delay, CH1, CH2, CH3, CH4. Dans les champs de note, 0xFF maintient la voix et 0xFD l’arrête. Dans delay, 0xFF termine la lecture et 0xFE boucle. Il s’agit de l’ordre des champs, pas des identifiants de canal. La file WRAM est un mode distinct ; fournissez des enregistrements complets de cinq octets avec AudioVBlank_QueueRefill.
Exemple d’utilisation
// 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();
}Résultat attendu
L’ISR joue un morceau de deux notes. Comparez la suspension des mises à jour musicales, qui conserve le son, Stop, qui le coupe, et la désactivation IRQ après redémarrage, qui conserve aussi le son. La RAM vérifie que le hook tourne musique désactivée et s’arrête IRQ désactivée.


Commande de compilation
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-disasmImplémentation et source
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
Efface les états de lecture, delay et restauration, puis coupe immédiatement impulsions, bruit et onde. IRQ reste activé.
Syntaxe
void AudioVBlank_Stop();Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
audio_vblank.c implémente __kq_vblank_vector ; n’installez pas un autre vecteur VBlank concurrent. L’exemple définit Audio_NoiseEffectActive, exclut le décodeur musical ordinaire et réserve Audio_Update aux effets et fondus. Masquez les interruptions lorsque vous modifiez les pointeurs de morceau ou l’état partagé.
Gardez les données musicales directes en ROM fixe ou dans une zone toujours visible par l’ISR. Un enregistrement contient cinq octets : delay, CH1, CH2, CH3, CH4. Dans les champs de note, 0xFF maintient la voix et 0xFD l’arrête. Dans delay, 0xFF termine la lecture et 0xFE boucle. Il s’agit de l’ordre des champs, pas des identifiants de canal. La file WRAM est un mode distinct ; fournissez des enregistrements complets de cinq octets avec AudioVBlank_QueueRefill.
Exemple d’utilisation
// 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();
}Résultat attendu
L’ISR joue un morceau de deux notes. Comparez la suspension des mises à jour musicales, qui conserve le son, Stop, qui le coupe, et la désactivation IRQ après redémarrage, qui conserve aussi le son. La RAM vérifie que le hook tourne musique désactivée et s’arrête IRQ désactivée.


Commande de compilation
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-disasmImplémentation et source
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 — Accès au code et aux données tenant compte des banques
Une banque ROM est un bloc de stockage de la cartouche mappé dans l’espace d’adressage du CPU. Plusieurs banques peuvent apparaître à la même adresse : un pointeur de 16 bits ne suffit donc pas à identifier les données. BankPtr est un descripteur compact de trois octets : un numéro de banque sur un octet et un pointeur sur deux octets. Créez-le avec farptr_make, puis accédez aux données avec farptr_read8, farptr_read16 ou farptr_read.
L’exemple GB utilise une cartouche MBC5 : le code de la banque fixe 0 reste accessible en $0000–$3FFF, tandis que les banques 1, 2 et 3 sont sélectionnées en $4000–$7FFF. Placez bank_switch et le code exécuté après son retour en ROM fixe. Initialisez l’état de la bibliothèque avec bank_switch avant de le consulter. Sur GB, far_call accepte un pointeur de rappel ; __farcall exige un nom de fonction.
bank_get_current
Renvoie le dernier numéro de banque enregistré par bank_switch. Il s’agit d’un état logiciel, pas d’une lecture des registres de la cartouche.
Syntaxe
u8 bank_get_current();Valeur renvoyée
La valeur u8 enregistrée par le dernier bank_switch ; zéro avant l’initialisation.
Conditions et limites
L’état de la bibliothèque commence à zéro et ne détecte pas le mappage initial de la cartouche. Initialisez-le avec bank_switch. Les intrinsèques et écritures directes dans le mapper n’actualisent pas cet état distinct ; bank_get_current ne vérifie donc pas le mappage matériel réel.
Exemple d’utilisation
starting_bank=bank_get_current(); // Last value recorded by bank_switch.
bank_expect(starting_bank==2,1);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
bank_switch(2) enregistre et sélectionne d’abord la banque 2. Une commutation directe sélectionne ensuite la banque 1 et lit A1 dans home1, tandis que bank_get_current indique toujours 2 ; après restauration, home2 donne à nouveau B2.
Le programme complet montre comment identifier des données par une banque et une adresse proche, appeler des rappels entre banques et distinguer l’état de la bibliothèque du mappage réel. Tous les nombres sont hexadécimaux. BANK IN et BANK OUT doivent valoir 02 ; BYTE HEX, D3 ; WORD HEX, 5C7A ; FAILED CHECKS et FIRST FAILURE, 00. Le texte est bleu sur CGB et FC, noir sur DMG.
CALL COUNT vaut 03 : far_call, __farcall et __farcall_ptr invoquent chacun le rappel une fois.


Commande de compilation
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-disasmImplémentation et source
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
Consultez les changements et vérifications du 2026-10-03 pour les différences locales de cette API.
Sélectionne la banque ROM et enregistre son numéro dans la bibliothèque bank et dans l’état du compilateur. Les lectures et appels distants utilisent ce dernier pour rétablir la banque précédente.
Syntaxe
void bank_switch(u8 bank);Paramètres
bankNuméro de banque ROM non signé sur 8 bits. Pour un appel, il doit correspondre au placement de la fonction ; pour une lecture, il sélectionne la source. Respectez la plage du type de cartouche.
Valeur renvoyée
Aucune (void).
Conditions et limites
Un changement persistant de banque ne doit pas rendre inaccessibles le code exécuté ou son adresse de retour. Placez cet appel, bank_switch elle-même si elle est utilisée, et le code qui suit dans la banque commune ou fixe 0, comme dans l’exemple.
L’état de la bibliothèque commence à zéro et ne détecte pas le mappage initial de la cartouche. Initialisez-le avec bank_switch. Les intrinsèques et écritures directes dans le mapper n’actualisent pas cet état distinct ; bank_get_current ne vérifie donc pas le mappage matériel réel.
Ces interfaces GB transportent huit bits de banque et ne règlent pas le neuvième bit MBC5. Les règles de la cartouche restent applicables, notamment pour la banque zéro. L’exemple utilise explicitement les banques MBC5 1–3 ; ne mélangez pas cet état avec des écritures directes non suivies dans le mapper.
Exemple d’utilisation
bank_switch(2); // Select the payload window and update library bookkeeping.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
bank_switch(2) enregistre et sélectionne d’abord la banque 2. Une commutation directe sélectionne ensuite la banque 1 et lit A1 dans home1, tandis que bank_get_current indique toujours 2 ; après restauration, home2 donne à nouveau B2.
Le programme complet montre comment identifier des données par une banque et une adresse proche, appeler des rappels entre banques et distinguer l’état de la bibliothèque du mappage réel. Tous les nombres sont hexadécimaux. BANK IN et BANK OUT doivent valoir 02 ; BYTE HEX, D3 ; WORD HEX, 5C7A ; FAILED CHECKS et FIRST FAILURE, 00. Le texte est bleu sur CGB et FC, noir sur DMG.
CALL COUNT vaut 03 : far_call, __farcall et __farcall_ptr invoquent chacun le rappel une fois.


Commande de compilation
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-disasmImplémentation et source
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
Transmet un numéro de banque et un pointeur de rappel à __farcall_ptr. Cette fonction de bibliothèque exécute le rappel sans argument et revient après avoir restauré la banque de l’appelant.
Syntaxe
void far_call(u8 bank, const void* func);Paramètres
bankNuméro de banque ROM non signé sur 8 bits. Pour un appel, il doit correspondre au placement de la fonction ; pour une lecture, il sélectionne la source. Respectez la plage du type de cartouche.
funcAdresse exécutable valide d’un rappel sans paramètre, fournie par un nom de fonction ou un pointeur d’exécution. Les pointeurs nuls et les associations banque/adresse incorrectes ne sont pas vérifiés à l’exécution.
Valeur renvoyée
Aucune (void).
Conditions et limites
Ces appels ne transmettent pas d’arguments utilisateur et ne rendent pas le rappel réentrant face aux interruptions. Gérez correctement ses données, sa pile et ses interruptions. La restauration des banques est testée avec des appels imbriqués et répétés ; l’exemple ne couvre ni le matériel physique ni tous les entrelacements d’interruptions.
Ces interfaces GB transportent huit bits de banque et ne règlent pas le neuvième bit MBC5. Les règles de la cartouche restent applicables, notamment pour la banque zéro. L’exemple utilise explicitement les banques MBC5 1–3 ; ne mélangez pas cet état avec des écritures directes non suivies dans le mapper.
Exemple d’utilisation
far_call(3,callback); // No arguments; callback reads payload[0] in bank 3.
bank_expect(callback_count==1 && callback_byte==0xD3,15);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
À ce stade du programme complet, far_call porte callback_count à 1. Le rappel lit D3 dans la banque 3. Une lecture proche ultérieure de B2 dans home2 confirme le retour avec la banque 2 sélectionnée.
Le programme complet montre comment identifier des données par une banque et une adresse proche, appeler des rappels entre banques et distinguer l’état de la bibliothèque du mappage réel. Tous les nombres sont hexadécimaux. BANK IN et BANK OUT doivent valoir 02 ; BYTE HEX, D3 ; WORD HEX, 5C7A ; FAILED CHECKS et FIRST FAILURE, 00. Le texte est bleu sur CGB et FC, noir sur DMG.
CALL COUNT vaut 03 : far_call, __farcall et __farcall_ptr invoquent chacun le rappel une fois.


Commande de compilation
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-disasmImplémentation et source
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
Copie len octets de la banque ROM indiquée vers la RAM fournie par l’appelant via l’intrinsèque de copie distante. Rétablit la banque précédente avant le retour.
Syntaxe
void far_data_read(u8 bank, const void* addr, void* dst, u16 len);Paramètres
bankNuméro de banque ROM non signé sur 8 bits. Pour un appel, il doit correspondre au placement de la fonction ; pour une lecture, il sélectionne la source. Respectez la plage du type de cartouche.
addrPointeur proche vers des octets lisibles dans la banque ROM choisie. Il ne contient pas de numéro de banque.
dstDestination en mémoire accessible en écriture, assez grande pour tous les octets copiés. Hors transfert de zéro octet, les adresses nulles ou invalides ne sont pas vérifiées.
lenNombre d’octets, de 0 à 65535. Avec zéro, aucune mémoire n’est copiée, mais la sélection et le rétablissement de la banque ont bien lieu.
Valeur renvoyée
Aucune (void).
Conditions et limites
Toute la source doit être lisible dans le mappage ROM prévu, et toute la destination accessible en écriture. La copie ne passe pas automatiquement à la banque suivante, ne gère pas les chevauchements comme memmove et ne synchronise pas les écritures VRAM. Utilisez les API graphiques pour la VRAM.
Les lectures et copies distantes sont synchrones et utilisent un espace de travail partagé du compilateur. Une interruption ne doit pas y exécuter un autre transfert pendant son utilisation. Sur GB, la copie utilise aussi un emplacement HRAM partagé pour la banque sauvegardée. L’exemple exécute ces opérations depuis du code fixe, sans gestionnaire de transfert concurrent.
Ces interfaces GB transportent huit bits de banque et ne règlent pas le neuvième bit MBC5. Les règles de la cartouche restent applicables, notamment pour la banque zéro. L’exemple utilise explicitement les banques MBC5 1–3 ; ne mélangez pas cet état avec des écritures directes non suivies dans le mapper.
Exemple d’utilisation
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);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet extrait copie 4 octets via far_data_read et compare le tampon à D3 7A 5C 96. Le descripteur ou pointeur source de l’appelant est conservé ; le programme complet vérifie séparément une copie de longueur nulle et la restauration de la banque.
Le programme complet montre comment identifier des données par une banque et une adresse proche, appeler des rappels entre banques et distinguer l’état de la bibliothèque du mappage réel. Tous les nombres sont hexadécimaux. BANK IN et BANK OUT doivent valoir 02 ; BYTE HEX, D3 ; WORD HEX, 5C7A ; FAILED CHECKS et FIRST FAILURE, 00. Le texte est bleu sur CGB et FC, noir sur DMG.
CALL COUNT vaut 03 : far_call, __farcall et __farcall_ptr invoquent chacun le rappel une fois.


Commande de compilation
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-disasmImplémentation et source
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
Lit deux octets consécutifs via __farpeek16 et les assemble en un mot little-endian. Le premier octet fournit les huit bits de poids faible.
Syntaxe
u16 far_data_read16(u8 bank, const void* addr);Paramètres
bankNuméro de banque ROM non signé sur 8 bits. Pour un appel, il doit correspondre au placement de la fonction ; pour une lecture, il sélectionne la source. Respectez la plage du type de cartouche.
addrPointeur proche vers des octets lisibles dans la banque ROM choisie. Il ne contient pas de numéro de banque.
Valeur renvoyée
Le mot little-endian lu, sous forme de u16 (0–65535).
Conditions et limites
L’octet ou le mot entier doit être lisible dans le mappage CPU sélectionné. Ces lectures ne valident pas les pointeurs, ne bornent pas les adresses et ne passent pas automatiquement à une autre banque à la limite d’une fenêtre. Un mot exige deux octets consécutifs valides.
Les lectures et copies distantes sont synchrones et utilisent un espace de travail partagé du compilateur. Une interruption ne doit pas y exécuter un autre transfert pendant son utilisation. Sur GB, la copie utilise aussi un emplacement HRAM partagé pour la banque sauvegardée. L’exemple exécute ces opérations depuis du code fixe, sans gestionnaire de transfert concurrent.
Ces interfaces GB transportent huit bits de banque et ne règlent pas le neuvième bit MBC5. Les règles de la cartouche restent applicables, notamment pour la banque zéro. L’exemple utilise explicitement les banques MBC5 1–3 ; ne mélangez pas cet état avec des écritures directes non suivies dans le mapper.
Exemple d’utilisation
word_value=far_data_read16(3,payload+1); // Little-endian 7A 5C -> 0x5C7A.
bank_expect(word_value==0x5C7A,6);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet extrait utilise far_data_read16 pour lire payload+1 dans la banque 3 et vérifie 5C7A. Le programme complet lit aussi home2 avec un pointeur proche pour confirmer la restauration de la banque 2.
Le programme complet montre comment identifier des données par une banque et une adresse proche, appeler des rappels entre banques et distinguer l’état de la bibliothèque du mappage réel. Tous les nombres sont hexadécimaux. BANK IN et BANK OUT doivent valoir 02 ; BYTE HEX, D3 ; WORD HEX, 5C7A ; FAILED CHECKS et FIRST FAILURE, 00. Le texte est bleu sur CGB et FC, noir sur DMG.
CALL COUNT vaut 03 : far_call, __farcall et __farcall_ptr invoquent chacun le rappel une fois.


Commande de compilation
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-disasmImplémentation et source
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
Lit un octet dans la banque ROM à l’adresse indiquée via __farpeek8, rétablit la banque précédente et renvoie la valeur.
Syntaxe
u8 far_data_read8(u8 bank, const void* addr);Paramètres
bankNuméro de banque ROM non signé sur 8 bits. Pour un appel, il doit correspondre au placement de la fonction ; pour une lecture, il sélectionne la source. Respectez la plage du type de cartouche.
addrPointeur proche vers des octets lisibles dans la banque ROM choisie. Il ne contient pas de numéro de banque.
Valeur renvoyée
L’octet lu, sous forme de u8 (0–255).
Conditions et limites
L’octet ou le mot entier doit être lisible dans le mappage CPU sélectionné. Ces lectures ne valident pas les pointeurs, ne bornent pas les adresses et ne passent pas automatiquement à une autre banque à la limite d’une fenêtre. Un mot exige deux octets consécutifs valides.
Les lectures et copies distantes sont synchrones et utilisent un espace de travail partagé du compilateur. Une interruption ne doit pas y exécuter un autre transfert pendant son utilisation. Sur GB, la copie utilise aussi un emplacement HRAM partagé pour la banque sauvegardée. L’exemple exécute ces opérations depuis du code fixe, sans gestionnaire de transfert concurrent.
Ces interfaces GB transportent huit bits de banque et ne règlent pas le neuvième bit MBC5. Les règles de la cartouche restent applicables, notamment pour la banque zéro. L’exemple utilise explicitement les banques MBC5 1–3 ; ne mélangez pas cet état avec des écritures directes non suivies dans le mapper.
Exemple d’utilisation
byte_value=far_data_read8(3,payload); // One byte: 0xD3.
bank_expect(byte_value==0xD3,5);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet extrait utilise far_data_read8 pour lire payload dans la banque 3 et vérifie D3. Le programme complet lit aussi home2 avec un pointeur proche pour confirmer la restauration de la banque 2.
Le programme complet montre comment identifier des données par une banque et une adresse proche, appeler des rappels entre banques et distinguer l’état de la bibliothèque du mappage réel. Tous les nombres sont hexadécimaux. BANK IN et BANK OUT doivent valoir 02 ; BYTE HEX, D3 ; WORD HEX, 5C7A ; FAILED CHECKS et FIRST FAILURE, 00. Le texte est bleu sur CGB et FC, noir sur DMG.
CALL COUNT vaut 03 : far_call, __farcall et __farcall_ptr invoquent chacun le rappel une fois.


Commande de compilation
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-disasmImplémentation et source
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
Enregistre un octet de banque et un pointeur visible par le CPU dans le BankPtr de l’appelant. Construit un descripteur, sans changer de banque ni lire les données pointées.
Syntaxe
void farptr_make(BankPtr* out, u8 bank, const u8* ptr);Paramètres
outPointeur vers un espace accessible en écriture pour un BankPtr de trois octets. Si out est nul, aucune écriture n’a lieu.
bankNuméro de banque ROM non signé sur 8 bits. Pour un appel, il doit correspondre au placement de la fonction ; pour une lecture, il sélectionne la source. Respectez la plage du type de cartouche.
ptrAdresse de 16 bits visible par le CPU à stocker dans le descripteur. Elle est copiée telle quelle, sans vérifier sa validité dans la banque choisie.
Valeur renvoyée
Aucune (void).
Exemple d’utilisation
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.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le descripteur est réglé sur la banque 3 et payload+1. Ses lectures donnent 7A, 5C7A et les trois octets 7A 5C 96. L’appel avec une sortie nulle ne doit modifier aucun état.
Le programme complet montre comment identifier des données par une banque et une adresse proche, appeler des rappels entre banques et distinguer l’état de la bibliothèque du mappage réel. Tous les nombres sont hexadécimaux. BANK IN et BANK OUT doivent valoir 02 ; BYTE HEX, D3 ; WORD HEX, 5C7A ; FAILED CHECKS et FIRST FAILURE, 00. Le texte est bleu sur CGB et FC, noir sur DMG.
CALL COUNT vaut 03 : far_call, __farcall et __farcall_ptr invoquent chacun le rappel une fois.


Commande de compilation
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-disasmImplémentation et source
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
Copie len octets depuis un BankPtr vers une RAM accessible en écriture. Le descripteur étant passé par valeur, le pointeur de l’appelant reste au début de la source.
Syntaxe
void farptr_read(BankPtr ptr, void* dst, u16 len);Paramètres
ptrUne valeur BankPtr contenant bank et ptr. Passez le descripteur lui-même, pas son adresse. Le descripteur de l’appelant n’est pas modifié.
dstDestination en mémoire accessible en écriture, assez grande pour tous les octets copiés. Hors transfert de zéro octet, les adresses nulles ou invalides ne sont pas vérifiées.
lenNombre d’octets, de 0 à 65535. Avec zéro, aucune mémoire n’est copiée, mais la sélection et le rétablissement de la banque ont bien lieu.
Valeur renvoyée
Aucune (void).
Conditions et limites
Toute la source doit être lisible dans le mappage ROM prévu, et toute la destination accessible en écriture. La copie ne passe pas automatiquement à la banque suivante, ne gère pas les chevauchements comme memmove et ne synchronise pas les écritures VRAM. Utilisez les API graphiques pour la VRAM.
Les lectures et copies distantes sont synchrones et utilisent un espace de travail partagé du compilateur. Une interruption ne doit pas y exécuter un autre transfert pendant son utilisation. Sur GB, la copie utilise aussi un emplacement HRAM partagé pour la banque sauvegardée. L’exemple exécute ces opérations depuis du code fixe, sans gestionnaire de transfert concurrent.
Ces interfaces GB transportent huit bits de banque et ne règlent pas le neuvième bit MBC5. Les règles de la cartouche restent applicables, notamment pour la banque zéro. L’exemple utilise explicitement les banques MBC5 1–3 ; ne mélangez pas cet état avec des écritures directes non suivies dans le mapper.
Exemple d’utilisation
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);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet extrait copie 3 octets via farptr_read et compare le tampon à 7A 5C 96. Le descripteur ou pointeur source de l’appelant est conservé ; le programme complet vérifie séparément une copie de longueur nulle et la restauration de la banque.
Le programme complet montre comment identifier des données par une banque et une adresse proche, appeler des rappels entre banques et distinguer l’état de la bibliothèque du mappage réel. Tous les nombres sont hexadécimaux. BANK IN et BANK OUT doivent valoir 02 ; BYTE HEX, D3 ; WORD HEX, 5C7A ; FAILED CHECKS et FIRST FAILURE, 00. Le texte est bleu sur CGB et FC, noir sur DMG.
CALL COUNT vaut 03 : far_call, __farcall et __farcall_ptr invoquent chacun le rappel une fois.


Commande de compilation
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-disasmImplémentation et source
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
Lit un mot little-endian dans la banque à l’adresse contenues dans un BankPtr. Le descripteur est passé par valeur et son pointeur n’avance pas.
Syntaxe
u16 farptr_read16(BankPtr ptr);Paramètres
ptrUne valeur BankPtr contenant bank et ptr. Passez le descripteur lui-même, pas son adresse. Le descripteur de l’appelant n’est pas modifié.
Valeur renvoyée
Le mot little-endian lu, sous forme de u16 (0–65535).
Conditions et limites
L’octet ou le mot entier doit être lisible dans le mappage CPU sélectionné. Ces lectures ne valident pas les pointeurs, ne bornent pas les adresses et ne passent pas automatiquement à une autre banque à la limite d’une fenêtre. Un mot exige deux octets consécutifs valides.
Les lectures et copies distantes sont synchrones et utilisent un espace de travail partagé du compilateur. Une interruption ne doit pas y exécuter un autre transfert pendant son utilisation. Sur GB, la copie utilise aussi un emplacement HRAM partagé pour la banque sauvegardée. L’exemple exécute ces opérations depuis du code fixe, sans gestionnaire de transfert concurrent.
Ces interfaces GB transportent huit bits de banque et ne règlent pas le neuvième bit MBC5. Les règles de la cartouche restent applicables, notamment pour la banque zéro. L’exemple utilise explicitement les banques MBC5 1–3 ; ne mélangez pas cet état avec des écritures directes non suivies dans le mapper.
Exemple d’utilisation
bank_expect(farptr_read16(pointer)==0x5C7A,10);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet extrait utilise farptr_read16 pour lire pointer.ptr dans la banque 3 et vérifie 5C7A. Le programme complet lit aussi home2 avec un pointeur proche pour confirmer la restauration de la banque 2.
Le programme complet montre comment identifier des données par une banque et une adresse proche, appeler des rappels entre banques et distinguer l’état de la bibliothèque du mappage réel. Tous les nombres sont hexadécimaux. BANK IN et BANK OUT doivent valoir 02 ; BYTE HEX, D3 ; WORD HEX, 5C7A ; FAILED CHECKS et FIRST FAILURE, 00. Le texte est bleu sur CGB et FC, noir sur DMG.
CALL COUNT vaut 03 : far_call, __farcall et __farcall_ptr invoquent chacun le rappel une fois.


Commande de compilation
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-disasmImplémentation et source
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
Lit un octet à partir des deux champs d’un BankPtr passé par valeur. Le descripteur fournit la banque absente d’un pointeur proche ordinaire.
Syntaxe
u8 farptr_read8(BankPtr ptr);Paramètres
ptrUne valeur BankPtr contenant bank et ptr. Passez le descripteur lui-même, pas son adresse. Le descripteur de l’appelant n’est pas modifié.
Valeur renvoyée
L’octet lu, sous forme de u8 (0–255).
Conditions et limites
L’octet ou le mot entier doit être lisible dans le mappage CPU sélectionné. Ces lectures ne valident pas les pointeurs, ne bornent pas les adresses et ne passent pas automatiquement à une autre banque à la limite d’une fenêtre. Un mot exige deux octets consécutifs valides.
Les lectures et copies distantes sont synchrones et utilisent un espace de travail partagé du compilateur. Une interruption ne doit pas y exécuter un autre transfert pendant son utilisation. Sur GB, la copie utilise aussi un emplacement HRAM partagé pour la banque sauvegardée. L’exemple exécute ces opérations depuis du code fixe, sans gestionnaire de transfert concurrent.
Ces interfaces GB transportent huit bits de banque et ne règlent pas le neuvième bit MBC5. Les règles de la cartouche restent applicables, notamment pour la banque zéro. L’exemple utilise explicitement les banques MBC5 1–3 ; ne mélangez pas cet état avec des écritures directes non suivies dans le mapper.
Exemple d’utilisation
bank_expect(farptr_read8(pointer)==0x7A,9);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet extrait utilise farptr_read8 pour lire pointer.ptr dans la banque 3 et vérifie 7A. Le programme complet lit aussi home2 avec un pointeur proche pour confirmer la restauration de la banque 2.
Le programme complet montre comment identifier des données par une banque et une adresse proche, appeler des rappels entre banques et distinguer l’état de la bibliothèque du mappage réel. Tous les nombres sont hexadécimaux. BANK IN et BANK OUT doivent valoir 02 ; BYTE HEX, D3 ; WORD HEX, 5C7A ; FAILED CHECKS et FIRST FAILURE, 00. Le texte est bleu sur CGB et FC, noir sur DMG.
CALL COUNT vaut 03 : far_call, __farcall et __farcall_ptr invoquent chacun le rappel une fois.


Commande de compilation
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-disasmImplémentation et source
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 — Coordonnées du monde et zones visibles
Gère les positions, cibles et limites de caméra Q8.8 et convertit les coordonnées monde/écran. Choisissez des objets Camera8_8 détenus par l’appelant ou l’API en minuscules pour une caméra partagée.
Camera_Add
Ajoute les déplacements Q8.8 à la position courante, puis applique les limites activées.
Syntaxe
void Camera_Add(Camera8_8* cam, s16 dfx, s16 dfy);Paramètres
camPointeur valide vers un
Camera8_8initialisé et détenu par l’appelant.dfxDéplacement Q8.8 signé ; 256 correspond à un pixel.
dfyDéplacement Q8.8 signé ; 256 correspond à un pixel.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Les coordonnées ont huit bits fractionnaires. Gardez les positions, les cibles et les sommes ou différences intermédiaires dans la plage de s16. Mettez l’affichage à jour séparément avec Camera_ApplyBg ou en appliquant les valeurs mises en tampon.
Exemple d’utilisation
Camera_Add(&cam,256,512);result[13]=cam.fx;result[14]=cam.fy;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple présente le suivi Q8.8, les limites et la conversion de coordonnées. Le suivi donne X/Y=3584/4096 ; les limites ramènent ces valeurs à 3072/3584. BG X reste à 13 tant que la valeur est en attente, puis passe à 8 après application. L’image supplémentaire montre une caméra en (8,16) déplaçant un rectangle de 32×24 du monde (32,32) vers l’écran (24,16).


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Applique immédiatement la position courante de la caméra partagée au défilement du fond.
Syntaxe
void camera_apply();Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Aucune attente VBlank n’est effectuée ; synchronisez l’appel si vous ne voulez pas de modification en cours de trame. Les fractions négatives sont arrondies vers le bas : −1/256 devient −1 pixel, soit la valeur 255 dans le registre.
Exemple d’utilisation
camera_apply();result[31]=M_SCX;result[32]=M_SCY;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple présente le suivi Q8.8, les limites et la conversion de coordonnées. Le suivi donne X/Y=3584/4096 ; les limites ramènent ces valeurs à 3072/3584. BG X reste à 13 tant que la valeur est en attente, puis passe à 8 après application. L’image supplémentaire montre une caméra en (8,16) déplaçant un rectangle de 32×24 du monde (32,32) vers l’écran (24,16).


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Arrondit la position de la caméra vers le bas en pixels entiers et écrit immédiatement ses huit bits de poids faible dans le défilement du fond.
Syntaxe
void Camera_ApplyBg(const Camera8_8* cam);Paramètres
camPointeur valide vers un
Camera8_8initialisé et détenu par l’appelant.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Aucune attente VBlank n’est effectuée ; synchronisez l’appel si vous ne voulez pas de modification en cours de trame. Les fractions négatives sont arrondies vers le bas : −1/256 devient −1 pixel, soit la valeur 255 dans le registre.
Exemple d’utilisation
Camera_ApplyBg(&cam);result[21]=M_SCX;result[22]=M_SCY;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple présente le suivi Q8.8, les limites et la conversion de coordonnées. Le suivi donne X/Y=3584/4096 ; les limites ramènent ces valeurs à 3072/3584. BG X reste à 13 tant que la valeur est en attente, puis passe à 8 après application. L’image supplémentaire montre une caméra en (8,16) déplaçant un rectangle de 32×24 du monde (32,32) vers l’écran (24,16).


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Arrondit la position de la caméra vers le bas en pixels entiers et la prépare comme prochaine valeur de défilement du fond.
Syntaxe
void Camera_ApplyBgBuffered(const Camera8_8* cam);Paramètres
camPointeur valide vers un
Camera8_8initialisé et détenu par l’appelant.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Le matériel et les valeurs courantes suivies restent inchangés jusqu’à Scroll_Flush ou __scroll_flush. Cet appel n’attend pas VBlank.
Exemple d’utilisation
Camera_Set(&cam,2048,4096);Camera_ApplyBgBuffered(&cam);result[23]=M_SCX;Scroll_Flush();result[24]=M_SCX;result[25]=M_SCY;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple présente le suivi Q8.8, les limites et la conversion de coordonnées. Le suivi donne X/Y=3584/4096 ; les limites ramènent ces valeurs à 3072/3584. BG X reste à 13 tant que la valeur est en attente, puis passe à 8 après application. L’image supplémentaire montre une caméra en (8,16) déplaçant un rectangle de 32×24 du monde (32,32) vers l’écran (24,16).


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Applique à la caméra partagée les limites calculées par la différence entre monde et écran.
Syntaxe
void camera_clamp(u16 world_w_px, u16 world_h_px, u8 screen_w_px, u8 screen_h_px);Paramètres
world_w_pxDimension du monde en pixels entiers ; l’excédent positif sur l’écran doit rester entre 0 et 127.
world_h_pxDimension du monde en pixels entiers ; l’excédent positif sur l’écran doit rester entre 0 et 127.
screen_w_pxDimension de la zone visible en pixels entiers ; si elle est au moins égale à celle du monde, la course sur cet axe est nulle.
screen_h_pxDimension de la zone visible en pixels entiers ; si elle est au moins égale à celle du monde, la course sur cet axe est nulle.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Un monde plus petit que la zone visible donne une course nulle. Un écart positif de 128 ou plus dépasse la plage Q8.8 signée lors de la conversion. Les paramètres u16 ne signifient pas que la caméra peut parcourir des mondes arbitrairement grands. Ces appels partagent une même caméra ; utilisez l’API commençant par une majuscule pour des objets caméra indépendants. Les positions converties de pixels entiers en Q8.8 doivent être comprises entre −128 et 127.
Exemple d’utilisation
camera_clamp(176,160,160,144);result[29]=camera_world_to_screen_x(100);result[30]=camera_world_to_screen_y(90);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple présente le suivi Q8.8, les limites et la conversion de coordonnées. Le suivi donne X/Y=3584/4096 ; les limites ramènent ces valeurs à 3072/3584. BG X reste à 13 tant que la valeur est en attente, puis passe à 8 après application. L’image supplémentaire montre une caméra en (8,16) déplaçant un rectangle de 32×24 du monde (32,32) vers l’écran (24,16).


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Soustrait les dimensions de l’écran à celles du monde et installe les limites de caméra non négatives obtenues.
Syntaxe
void Camera_ClampToSize(Camera8_8* cam, u16 world_w_px, u16 world_h_px, u8 screen_w_px, u8 screen_h_px);Paramètres
camPointeur valide vers un
Camera8_8initialisé et détenu par l’appelant.world_w_pxDimension du monde en pixels entiers ; l’excédent positif sur l’écran doit rester entre 0 et 127.
world_h_pxDimension du monde en pixels entiers ; l’excédent positif sur l’écran doit rester entre 0 et 127.
screen_w_pxDimension de la zone visible en pixels entiers ; si elle est au moins égale à celle du monde, la course sur cet axe est nulle.
screen_h_pxDimension de la zone visible en pixels entiers ; si elle est au moins égale à celle du monde, la course sur cet axe est nulle.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Un monde plus petit que la zone visible donne une course nulle. Un écart positif de 128 ou plus dépasse la plage Q8.8 signée lors de la conversion. Les paramètres u16 ne signifient pas que la caméra peut parcourir des mondes arbitrairement grands.
Exemple d’utilisation
Camera_ClampToSize(&cam,176,160,160,144);result[15]=cam.max_fx;result[16]=cam.max_fy;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple présente le suivi Q8.8, les limites et la conversion de coordonnées. Le suivi donne X/Y=3584/4096 ; les limites ramènent ces valeurs à 3072/3584. BG X reste à 13 tant que la valeur est en attente, puis passe à 8 après application. L’image supplémentaire montre une caméra en (8,16) déplaçant un rectangle de 32×24 du monde (32,32) vers l’écran (24,16).


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Désactive la limitation sans modifier la position, la cible ni les bornes enregistrées.
Syntaxe
void Camera_ClearBounds(Camera8_8* cam);Paramètres
camPointeur valide vers un
Camera8_8initialisé et détenu par l’appelant.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Les coordonnées ont huit bits fractionnaires. Gardez les positions, les cibles et les sommes ou différences intermédiaires dans la plage de s16. Mettez l’affichage à jour séparément avec Camera_ApplyBg ou en appliquant les valeurs mises en tampon.
Exemple d’utilisation
Camera_ClearBounds(&cam);result[12]=cam.use_bounds;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple présente le suivi Q8.8, les limites et la conversion de coordonnées. Le suivi donne X/Y=3584/4096 ; les limites ramènent ces valeurs à 3072/3584. BG X reste à 13 tant que la valeur est en attente, puis passe à 8 après application. L’image supplémentaire montre une caméra en (8,16) déplaçant un rectangle de 32×24 du monde (32,32) vers l’écran (24,16).


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Désactive le suivi en conservant la position courante et la cible enregistrée.
Syntaxe
void Camera_ClearTarget(Camera8_8* cam);Paramètres
camPointeur valide vers un
Camera8_8initialisé et détenu par l’appelant.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Les coordonnées ont huit bits fractionnaires. Gardez les positions, les cibles et les sommes ou différences intermédiaires dans la plage de s16. Mettez l’affichage à jour séparément avec Camera_ApplyBg ou en appliquant les valeurs mises en tampon.
Exemple d’utilisation
Camera_ClearTarget(&cam);result[8]=cam.use_target;result[9]=cam.target_fx;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple présente le suivi Q8.8, les limites et la conversion de coordonnées. Le suivi donne X/Y=3584/4096 ; les limites ramènent ces valeurs à 3072/3584. BG X reste à 13 tant que la valeur est en attente, puis passe à 8 après application. L’image supplémentaire montre une caméra en (8,16) déplaçant un rectangle de 32×24 du monde (32,32) vers l’écran (24,16).


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Déplace immédiatement la caméra partagée pour qu’un point du monde apparaisse au point d’ancrage demandé à l’écran.
Syntaxe
void camera_follow_xy(s16 x, s16 y, u8 screen_cx, u8 screen_cy);Paramètres
xCoordonnée X du monde en pixels entiers ; le résultat et la différence intermédiaire doivent tenir dans
s16.yCoordonnée Y du monde en pixels entiers ; le résultat et la différence intermédiaire doivent tenir dans
s16.screen_cxCoordonnée du point d’ancrage à l’écran en pixels entiers, de 0 à 255.
screen_cyCoordonnée du point d’ancrage à l’écran en pixels entiers, de 0 à 255.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Les coordonnées ont huit bits fractionnaires. Gardez les positions, les cibles et les sommes ou différences intermédiaires dans la plage de s16. Mettez l’affichage à jour séparément avec Camera_ApplyBg ou en appliquant les valeurs mises en tampon. Ces appels partagent une même caméra ; utilisez l’API commençant par une majuscule pour des objets caméra indépendants. Les positions converties de pixels entiers en Q8.8 doivent être comprises entre −128 et 127.
Exemple d’utilisation
camera_follow_xy(100,90,80,72);result[27]=camera_world_to_screen_x(100);result[28]=camera_world_to_screen_y(90);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple présente le suivi Q8.8, les limites et la conversion de coordonnées. Le suivi donne X/Y=3584/4096 ; les limites ramènent ces valeurs à 3072/3584. BG X reste à 13 tant que la valeur est en attente, puis passe à 8 après application. L’image supplémentaire montre une caméra en (8,16) déplaçant un rectangle de 32×24 du monde (32,32) vers l’écran (24,16).


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Met la position, la cible et les limites à zéro, puis désactive le suivi et la limitation aux bornes.
Syntaxe
void Camera_Init(Camera8_8* cam);Paramètres
camCamera8_8accessible en écriture à initialiser ; ne doit pas être NULL.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Les coordonnées ont huit bits fractionnaires. Gardez les positions, les cibles et les sommes ou différences intermédiaires dans la plage de s16. Mettez l’affichage à jour séparément avec Camera_ApplyBg ou en appliquant les valeurs mises en tampon.
Exemple d’utilisation
Camera_Init(&cam);result[0]=cam.fx;result[1]=cam.use_target;result[2]=cam.use_bounds;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple présente le suivi Q8.8, les limites et la conversion de coordonnées. Le suivi donne X/Y=3584/4096 ; les limites ramènent ces valeurs à 3072/3584. BG X reste à 13 tant que la valeur est en attente, puis passe à 8 après application. L’image supplémentaire montre une caméra en (8,16) déplaçant un rectangle de 32×24 du monde (32,32) vers l’écran (24,16).


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Ajoute la composante entière X de la caméra au X entier de l’écran pour obtenir le X du monde.
Syntaxe
s16 Camera_ScreenToWorldX(const Camera8_8* cam, s16 screen_x);Paramètres
camPointeur valide vers un
Camera8_8initialisé et détenu par l’appelant.screen_xCoordonnée X de l’écran en pixels entiers ; le résultat et la différence intermédiaire doivent tenir dans
s16.
Valeur renvoyée
Renvoie la coordonnée convertie en pixels entiers sous forme de s16 ; ne teste pas sa visibilité et ne la tronque pas aux limites de l’écran.
Conditions et limites
Les coordonnées ont huit bits fractionnaires. Gardez les positions, les cibles et les sommes ou différences intermédiaires dans la plage de s16. Mettez l’affichage à jour séparément avec Camera_ApplyBg ou en appliquant les valeurs mises en tampon.
Exemple d’utilisation
result[19]=Camera_ScreenToWorldX(&cam,27);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple présente le suivi Q8.8, les limites et la conversion de coordonnées. Le suivi donne X/Y=3584/4096 ; les limites ramènent ces valeurs à 3072/3584. BG X reste à 13 tant que la valeur est en attente, puis passe à 8 après application. L’image supplémentaire montre une caméra en (8,16) déplaçant un rectangle de 32×24 du monde (32,32) vers l’écran (24,16).


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Ajoute la composante entière Y de la caméra au Y entier de l’écran pour obtenir le Y du monde.
Syntaxe
s16 Camera_ScreenToWorldY(const Camera8_8* cam, s16 screen_y);Paramètres
camPointeur valide vers un
Camera8_8initialisé et détenu par l’appelant.screen_yCoordonnée Y de l’écran en pixels entiers ; le résultat et la différence intermédiaire doivent tenir dans
s16.
Valeur renvoyée
Renvoie la coordonnée convertie en pixels entiers sous forme de s16 ; ne teste pas sa visibilité et ne la tronque pas aux limites de l’écran.
Conditions et limites
Les coordonnées ont huit bits fractionnaires. Gardez les positions, les cibles et les sommes ou différences intermédiaires dans la plage de s16. Mettez l’affichage à jour séparément avec Camera_ApplyBg ou en appliquant les valeurs mises en tampon.
Exemple d’utilisation
result[20]=Camera_ScreenToWorldY(&cam,24);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple présente le suivi Q8.8, les limites et la conversion de coordonnées. Le suivi donne X/Y=3584/4096 ; les limites ramènent ces valeurs à 3072/3584. BG X reste à 13 tant que la valeur est en attente, puis passe à 8 après application. L’image supplémentaire montre une caméra en (8,16) déplaçant un rectangle de 32×24 du monde (32,32) vers l’écran (24,16).


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Remplace la position courante de la caméra et la ramène immédiatement dans les limites si elles sont activées.
Syntaxe
void Camera_Set(Camera8_8* cam, s16 fx, s16 fy);Paramètres
camPointeur valide vers un
Camera8_8initialisé et détenu par l’appelant.fxCoordonnée X. Coordonnée Q8.8 signée : 256 correspond à un pixel ; la plage va de −128 à 127+255/256 pixels.
fyCoordonnée Y. Coordonnée Q8.8 signée : 256 correspond à un pixel ; la plage va de −128 à 127+255/256 pixels.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Les coordonnées ont huit bits fractionnaires. Gardez les positions, les cibles et les sommes ou différences intermédiaires dans la plage de s16. Mettez l’affichage à jour séparément avec Camera_ApplyBg ou en appliquant les valeurs mises en tampon.
Exemple d’utilisation
Camera_Set(&cam,2560,5120);result[3]=cam.fx;result[4]=cam.fy;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple présente le suivi Q8.8, les limites et la conversion de coordonnées. Le suivi donne X/Y=3584/4096 ; les limites ramènent ces valeurs à 3072/3584. BG X reste à 13 tant que la valeur est en attente, puis passe à 8 après application. L’image supplémentaire montre une caméra en (8,16) déplaçant un rectangle de 32×24 du monde (32,32) vers l’écran (24,16).


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Déplace la caméra partagée en coordonnées de pixels entiers et applique ses limites activées.
Syntaxe
void camera_set(s16 x, s16 y);Paramètres
xCoordonnée X du monde en pixels entiers ; le résultat et la différence intermédiaire doivent tenir dans
s16.yCoordonnée Y du monde en pixels entiers ; le résultat et la différence intermédiaire doivent tenir dans
s16.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Les coordonnées ont huit bits fractionnaires. Gardez les positions, les cibles et les sommes ou différences intermédiaires dans la plage de s16. Mettez l’affichage à jour séparément avec Camera_ApplyBg ou en appliquant les valeurs mises en tampon. Ces appels partagent une même caméra ; utilisez l’API commençant par une majuscule pour des objets caméra indépendants. Les positions converties de pixels entiers en Q8.8 doivent être comprises entre −128 et 127.
Exemple d’utilisation
camera_set(5,6);result[26]=camera_world_to_screen_x(20);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple présente le suivi Q8.8, les limites et la conversion de coordonnées. Le suivi donne X/Y=3584/4096 ; les limites ramènent ces valeurs à 3072/3584. BG X reste à 13 tant que la valeur est en attente, puis passe à 8 après application. L’image supplémentaire montre une caméra en (8,16) déplaçant un rectangle de 32×24 du monde (32,32) vers l’écran (24,16).


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Installe les coordonnées minimales et maximales, active la limitation et l’applique immédiatement à la position courante.
Syntaxe
void Camera_SetBounds(Camera8_8* cam, s16 min_fx, s16 min_fy, s16 max_fx, s16 max_fy);Paramètres
camPointeur valide vers un
Camera8_8initialisé et détenu par l’appelant.min_fxCoordonnée X minimale. Coordonnée Q8.8 signée : 256 correspond à un pixel ; la plage va de −128 à 127+255/256 pixels.
min_fyCoordonnée Y minimale. Coordonnée Q8.8 signée : 256 correspond à un pixel ; la plage va de −128 à 127+255/256 pixels.
max_fxCoordonnée X maximale. Coordonnée Q8.8 signée : 256 correspond à un pixel ; la plage va de −128 à 127+255/256 pixels.
max_fyCoordonnée Y maximale. Coordonnée Q8.8 signée : 256 correspond à un pixel ; la plage va de −128 à 127+255/256 pixels.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Fournissez un minimum ≤ maximum sur chaque axe ; les bornes ne sont pas réordonnées. La cible enregistrée n’est pas ramenée dans ces limites.
Exemple d’utilisation
Camera_SetBounds(&cam,0,0,3072,3584);result[10]=cam.fx;result[11]=cam.fy;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple présente le suivi Q8.8, les limites et la conversion de coordonnées. Le suivi donne X/Y=3584/4096 ; les limites ramènent ces valeurs à 3072/3584. BG X reste à 13 tant que la valeur est en attente, puis passe à 8 après application. L’image supplémentaire montre une caméra en (8,16) déplaçant un rectangle de 32×24 du monde (32,32) vers l’écran (24,16).


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Enregistre une cible et active le suivi sans déplacer la position courante.
Syntaxe
void Camera_SetTarget(Camera8_8* cam, s16 fx, s16 fy);Paramètres
camPointeur valide vers un
Camera8_8initialisé et détenu par l’appelant.fxCoordonnée X. Coordonnée Q8.8 signée : 256 correspond à un pixel ; la plage va de −128 à 127+255/256 pixels.
fyCoordonnée Y. Coordonnée Q8.8 signée : 256 correspond à un pixel ; la plage va de −128 à 127+255/256 pixels.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Les coordonnées ont huit bits fractionnaires. Gardez les positions, les cibles et les sommes ou différences intermédiaires dans la plage de s16. Mettez l’affichage à jour séparément avec Camera_ApplyBg ou en appliquant les valeurs mises en tampon.
Exemple d’utilisation
Camera_SetTarget(&cam,4608,3072);result[5]=cam.use_target;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple présente le suivi Q8.8, les limites et la conversion de coordonnées. Le suivi donne X/Y=3584/4096 ; les limites ramènent ces valeurs à 3072/3584. BG X reste à 13 tant que la valeur est en attente, puis passe à 8 après application. L’image supplémentaire montre une caméra en (8,16) déplaçant un rectangle de 32×24 du monde (32,32) vers l’écran (24,16).


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Se rapproche de la cible d’une fraction de la distance restante, obtenue par décalage à droite ; ne fait rien si le suivi est désactivé.
Syntaxe
void Camera_StepTowardTarget(Camera8_8* cam, u8 shift);Paramètres
camPointeur valide vers un
Camera8_8initialisé et détenu par l’appelant.shiftExposant de la puissance de deux qui divise l’écart : 0 utilise l’écart entier, 1 sa moitié. Les valeurs supérieures à 7 sont ramenées à 7.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Un petit écart positif peut être tronqué à zéro ; un décalage arithmétique à droite peut transformer un petit écart négatif en −1. L’égalité avec la cible est testée avant la limitation. Une cible hors limites peut donc maintenir le suivi actif, ou le désactiver alors que la position finale limitée diffère de la cible.
Exemple d’utilisation
Camera_StepTowardTarget(&cam,1);result[6]=cam.fx;result[7]=cam.fy;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple présente le suivi Q8.8, les limites et la conversion de coordonnées. Le suivi donne X/Y=3584/4096 ; les limites ramènent ces valeurs à 3072/3584. BG X reste à 13 tant que la valeur est en attente, puis passe à 8 après application. L’image supplémentaire montre une caméra en (8,16) déplaçant un rectangle de 32×24 du monde (32,32) vers l’écran (24,16).


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Convertit le X du monde en X de l’écran en soustrayant la composante entière X de la caméra partagée.
Syntaxe
s16 camera_world_to_screen_x(s16 world_x);Paramètres
world_xCoordonnée X du monde en pixels entiers ; le résultat et la différence intermédiaire doivent tenir dans
s16.
Valeur renvoyée
Renvoie la coordonnée convertie en pixels entiers sous forme de s16 ; ne teste pas sa visibilité et ne la tronque pas aux limites de l’écran.
Conditions et limites
Les coordonnées ont huit bits fractionnaires. Gardez les positions, les cibles et les sommes ou différences intermédiaires dans la plage de s16. Mettez l’affichage à jour séparément avec Camera_ApplyBg ou en appliquant les valeurs mises en tampon. Ces appels partagent une même caméra ; utilisez l’API commençant par une majuscule pour des objets caméra indépendants. Les positions converties de pixels entiers en Q8.8 doivent être comprises entre −128 et 127.
Exemple d’utilisation
result[33]=camera_world_to_screen_x(20);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple présente le suivi Q8.8, les limites et la conversion de coordonnées. Le suivi donne X/Y=3584/4096 ; les limites ramènent ces valeurs à 3072/3584. BG X reste à 13 tant que la valeur est en attente, puis passe à 8 après application. L’image supplémentaire montre une caméra en (8,16) déplaçant un rectangle de 32×24 du monde (32,32) vers l’écran (24,16).


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Convertit le Y du monde en Y de l’écran en soustrayant la composante entière Y de la caméra partagée.
Syntaxe
s16 camera_world_to_screen_y(s16 world_y);Paramètres
world_yCoordonnée Y du monde en pixels entiers ; le résultat et la différence intermédiaire doivent tenir dans
s16.
Valeur renvoyée
Renvoie la coordonnée convertie en pixels entiers sous forme de s16 ; ne teste pas sa visibilité et ne la tronque pas aux limites de l’écran.
Conditions et limites
Les coordonnées ont huit bits fractionnaires. Gardez les positions, les cibles et les sommes ou différences intermédiaires dans la plage de s16. Mettez l’affichage à jour séparément avec Camera_ApplyBg ou en appliquant les valeurs mises en tampon. Ces appels partagent une même caméra ; utilisez l’API commençant par une majuscule pour des objets caméra indépendants. Les positions converties de pixels entiers en Q8.8 doivent être comprises entre −128 et 127.
Exemple d’utilisation
result[34]=camera_world_to_screen_y(20);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple présente le suivi Q8.8, les limites et la conversion de coordonnées. Le suivi donne X/Y=3584/4096 ; les limites ramènent ces valeurs à 3072/3584. BG X reste à 13 tant que la valeur est en attente, puis passe à 8 après application. L’image supplémentaire montre une caméra en (8,16) déplaçant un rectangle de 32×24 du monde (32,32) vers l’écran (24,16).


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Soustrait la composante entière X de la caméra à une coordonnée X entière du monde pour obtenir le X à l’écran.
Syntaxe
s16 Camera_WorldToScreenX(const Camera8_8* cam, s16 world_x);Paramètres
camPointeur valide vers un
Camera8_8initialisé et détenu par l’appelant.world_xCoordonnée X du monde en pixels entiers ; le résultat et la différence intermédiaire doivent tenir dans
s16.
Valeur renvoyée
Renvoie la coordonnée convertie en pixels entiers sous forme de s16 ; ne teste pas sa visibilité et ne la tronque pas aux limites de l’écran.
Conditions et limites
Les coordonnées ont huit bits fractionnaires. Gardez les positions, les cibles et les sommes ou différences intermédiaires dans la plage de s16. Mettez l’affichage à jour séparément avec Camera_ApplyBg ou en appliquant les valeurs mises en tampon.
Exemple d’utilisation
result[17]=Camera_WorldToScreenX(&cam,40);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple présente le suivi Q8.8, les limites et la conversion de coordonnées. Le suivi donne X/Y=3584/4096 ; les limites ramènent ces valeurs à 3072/3584. BG X reste à 13 tant que la valeur est en attente, puis passe à 8 après application. L’image supplémentaire montre une caméra en (8,16) déplaçant un rectangle de 32×24 du monde (32,32) vers l’écran (24,16).


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Soustrait la composante entière Y de la caméra à une coordonnée Y entière du monde pour obtenir le Y à l’écran.
Syntaxe
s16 Camera_WorldToScreenY(const Camera8_8* cam, s16 world_y);Paramètres
camPointeur valide vers un
Camera8_8initialisé et détenu par l’appelant.world_yCoordonnée Y du monde en pixels entiers ; le résultat et la différence intermédiaire doivent tenir dans
s16.
Valeur renvoyée
Renvoie la coordonnée convertie en pixels entiers sous forme de s16 ; ne teste pas sa visibilité et ne la tronque pas aux limites de l’écran.
Conditions et limites
Les coordonnées ont huit bits fractionnaires. Gardez les positions, les cibles et les sommes ou différences intermédiaires dans la plage de s16. Mettez l’affichage à jour séparément avec Camera_ApplyBg ou en appliquant les valeurs mises en tampon.
Exemple d’utilisation
result[18]=Camera_WorldToScreenY(&cam,40);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple présente le suivi Q8.8, les limites et la conversion de coordonnées. Le suivi donne X/Y=3584/4096 ; les limites ramènent ces valeurs à 3072/3584. BG X reste à 13 tant que la valeur est en attente, puis passe à 8 après application. L’image supplémentaire montre une caméra en (8,16) déplaçant un rectangle de 32×24 du monde (32,32) vers l’écran (24,16).


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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 — Palettes BG et OBJ de la CGB
cgb_palette.h et cgb_palette.c proposent le compactage RGB15 et la mise à jour immédiate des palettes CGB. Utilisez BG pour fond/fenêtre et OBJ pour sprites. Les fonctions de couleur ou de composantes modifient une couleur ; les plages écrivent des mots consécutifs ; une palette entière écrit quatre mots. Les plages raw utilisent des emplacements de couleur absolus, les intrinsèques de registre des positions d'octet. Attribuez la palette par la carte ou l'OAM. Incluez l'implémentation une seule fois, comme dans l'exemple complet.
Les écritures de palette et de registres protégés n'écrivent rien en mode DMG. Safe désigne ici le contrôle du mode CGB, pas une attente d'accès PPU ni une section critique. Configurez avec le LCD éteint ou effectuez une mise à jour assez courte pendant une phase accessible. Aucune attente VBlank ni protection contre les interruptions n'est ajoutée.
Les palettes BG/fenêtre et OBJ sont stockées séparément. Les écritures de la bibliothèque activent l'incrément et laissent le registre d'indice modifié. La couleur OBJ zéro reste transparente au rendu des sprites, même si ses octets peuvent être écrits et lus.
cgb_bg_color
Consultez les changements et vérifications du 2026-10-03 pour les différences locales de cette API.
Écrit immédiatement une couleur RGB15 compactée dans les palettes de fond/fenêtre. Les indices de palette et de couleur désignent l'un des 32 emplacements ; ni les motifs ni la palette attribuée à une tuile ne changent.
Syntaxe
void cgb_bg_color(u8 palette_index, u8 color_index, u16 rgb15);Paramètres
palette_indexNuméro de palette, 0–7 ; seuls les trois bits faibles sont utilisés (
& 7).color_indexIndice de couleur dans la palette, 0–3 ; seuls les deux bits faibles sont utilisés (
& 3).rgb15Couleur RGB sur 15 bits compactée, normalement 0–32767. Les deux octets du
u16sont écrits, faible puis fort ; la bibliothèque n'efface pas explicitement le bit 15. UtilisezCGB_RGB15oucgb_rgb15pour la construire.
Valeur renvoyée
Aucune (void).
Conditions et limites
Les écritures de palette et de registres protégés n'écrivent rien en mode DMG. Safe désigne ici le contrôle du mode CGB, pas une attente d'accès PPU ni une section critique. Configurez avec le LCD éteint ou effectuez une mise à jour assez courte pendant une phase accessible. Aucune attente VBlank ni protection contre les interruptions n'est ajoutée.
Les palettes BG/fenêtre et OBJ sont stockées séparément. Les écritures de la bibliothèque activent l'incrément et laissent le registre d'indice modifié. La couleur OBJ zéro reste transparente au rendu des sprites, même si ses octets peuvent être écrits et lus.
Exemple d’utilisation
cgb_bg_color(1,3,31); // Red background color 3 of palette 1.
expect_color(0,7,31);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme montre comment les palettes BG et OBJ colorent indépendamment un même motif. Chaque triangle occupe 8 × 8 pixels, d'un seul pixel à gauche en haut jusqu'à une ligne complète en bas. Aux abscisses 16, 32, 48, 64, 80, 96, 112, la ligne BG à y = 24 est rouge, bleue, verte, rouge, bleue, verte, rouge ; la ligne OBJ à y = 64 est bleue, verte, rouge, bleue, verte, rouge, bleue. Les colonnes utilisent respectivement une couleur, les composantes, une plage indexée, une palette entière, une plage absolue, un registre canonique et son alias.
À y = 88, sept cases de 8 × 8 montrent : triangle rouge (x = 16), contour carré bleu d'un pixel provenant de la banque 1 (32), triangle vert réfléchi horizontalement (48), rouge réfléchi verticalement (64), bleu réfléchi sur les deux axes (80), triangle vert devant un sprite rouge visible dans les pixels de couleur zéro (96), puis sprite rouge plein devant le triangle BG, témoin sans priorité (112). Les coordonnées sont en pixels depuis le coin supérieur gauche. Le fond reste blanc et le texte noir.
FAILED CHECKS 000 confirme les masques RGB, les booléens (dont 2), la normalisation des indices, le franchissement de palettes, l'arrêt à l'emplacement 31, l'absence d'écriture pour pointeur nul ou longueur nulle et la relecture des couleurs LCD éteint. Quatre combinaisons sont testées : ROM mixte sur DMG/CGB, ROM DMG seule sur DMG, ROM CGB seule sur CGB. Sur DMG, CGB MODE vaut 0, les triangles sont noirs, banque et réflexions n'affectent pas l'image et les deux dernières cases du bas sont des carrés noirs. Sur CGB, CGB MODE vaut 1. Le matériel réel et les conflits d'accès LCD allumé ne sont pas testés.




Commande de compilation
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-disasmImplémentation et source
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
Écrit des mots RGB15 consécutifs dans les palettes de fond/fenêtre, à partir des indices indiqués. La plage peut franchir une limite de palette de quatre couleurs, mais s'arrête à la fin des 32 emplacements.
Syntaxe
void cgb_bg_colors(u8 palette_index, u8 start_color_index, const u16* colors, u8 color_count);Paramètres
palette_indexNuméro de palette, 0–7 ; seuls les trois bits faibles sont utilisés (
& 7).start_color_indexIndice de couleur dans la palette, 0–3 ; seuls les deux bits faibles sont utilisés (
& 3).colorsconst u16*lisible contenant les mots de couleur nécessaires. Les données sont lues pendant l'appel, sans mise en file. Gardez la source et sa banque ROM accessibles ; aucun changement de banque n'est automatique. Un pointeur nul n'entraîne aucune écriture.color_countNombre de mots de couleur, et non d'octets, en
u8(0–255). Zéro ne fait rien. La quantité est limitée à32 - emplacement_initial_normalisé; seuls ces mots source sont lus.
Valeur renvoyée
Aucune (void).
Conditions et limites
Les écritures de palette et de registres protégés n'écrivent rien en mode DMG. Safe désigne ici le contrôle du mode CGB, pas une attente d'accès PPU ni une section critique. Configurez avec le LCD éteint ou effectuez une mise à jour assez courte pendant une phase accessible. Aucune attente VBlank ni protection contre les interruptions n'est ajoutée.
Les palettes BG/fenêtre et OBJ sont stockées séparément. Les écritures de la bibliothèque activent l'incrément et laissent le registre d'indice modifié. La couleur OBJ zéro reste transparente au rendu des sprites, même si ses octets peuvent être écrits et lus.
Exemple d’utilisation
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);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme montre comment les palettes BG et OBJ colorent indépendamment un même motif. Chaque triangle occupe 8 × 8 pixels, d'un seul pixel à gauche en haut jusqu'à une ligne complète en bas. Aux abscisses 16, 32, 48, 64, 80, 96, 112, la ligne BG à y = 24 est rouge, bleue, verte, rouge, bleue, verte, rouge ; la ligne OBJ à y = 64 est bleue, verte, rouge, bleue, verte, rouge, bleue. Les colonnes utilisent respectivement une couleur, les composantes, une plage indexée, une palette entière, une plage absolue, un registre canonique et son alias.
À y = 88, sept cases de 8 × 8 montrent : triangle rouge (x = 16), contour carré bleu d'un pixel provenant de la banque 1 (32), triangle vert réfléchi horizontalement (48), rouge réfléchi verticalement (64), bleu réfléchi sur les deux axes (80), triangle vert devant un sprite rouge visible dans les pixels de couleur zéro (96), puis sprite rouge plein devant le triangle BG, témoin sans priorité (112). Les coordonnées sont en pixels depuis le coin supérieur gauche. Le fond reste blanc et le texte noir.
FAILED CHECKS 000 confirme les masques RGB, les booléens (dont 2), la normalisation des indices, le franchissement de palettes, l'arrêt à l'emplacement 31, l'absence d'écriture pour pointeur nul ou longueur nulle et la relecture des couleurs LCD éteint. Quatre combinaisons sont testées : ROM mixte sur DMG/CGB, ROM DMG seule sur DMG, ROM CGB seule sur CGB. Sur DMG, CGB MODE vaut 0, les triangles sont noirs, banque et réflexions n'affectent pas l'image et les deux dernières cases du bas sont des carrés noirs. Sur CGB, CGB MODE vaut 1. Le matériel réel et les conflits d'accès LCD allumé ne sont pas testés.




Commande de compilation
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-disasmImplémentation et source
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
Écrit des mots RGB15 consécutifs dans les palettes de fond/fenêtre à partir d'un emplacement absolu. Le départ est un seul indice de 0 à 31, et non une paire palette/couleur. Les données sont des mots de couleur, pas des octets de motifs.
Syntaxe
void cgb_bg_colors_raw(u8 start_color_slot, const u16* colors, u8 color_count);Paramètres
start_color_slotEmplacement absolu de couleur, 0–31, normalisé par
& 31avant limitation de la longueur. Emplacement = palette × 4 + couleur ; ce n'est pas un décalage en octets.colorsconst u16*lisible contenant les mots de couleur nécessaires. Les données sont lues pendant l'appel, sans mise en file. Gardez la source et sa banque ROM accessibles ; aucun changement de banque n'est automatique. Un pointeur nul n'entraîne aucune écriture.color_countNombre de mots de couleur, et non d'octets, en
u8(0–255). Zéro ne fait rien. La quantité est limitée à32 - emplacement_initial_normalisé; seuls ces mots source sont lus.
Valeur renvoyée
Aucune (void).
Conditions et limites
Les écritures de palette et de registres protégés n'écrivent rien en mode DMG. Safe désigne ici le contrôle du mode CGB, pas une attente d'accès PPU ni une section critique. Configurez avec le LCD éteint ou effectuez une mise à jour assez courte pendant une phase accessible. Aucune attente VBlank ni protection contre les interruptions n'est ajoutée.
Les palettes BG/fenêtre et OBJ sont stockées séparément. Les écritures de la bibliothèque activent l'incrément et laissent le registre d'indice modifié. La couleur OBJ zéro reste transparente au rendu des sprites, même si ses octets peuvent être écrits et lus.
Exemple d’utilisation
cgb_bg_colors_raw(23,blue_word,1); // Absolute slot 23 = palette 5, color 3.
expect_color(0,23,31744);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme montre comment les palettes BG et OBJ colorent indépendamment un même motif. Chaque triangle occupe 8 × 8 pixels, d'un seul pixel à gauche en haut jusqu'à une ligne complète en bas. Aux abscisses 16, 32, 48, 64, 80, 96, 112, la ligne BG à y = 24 est rouge, bleue, verte, rouge, bleue, verte, rouge ; la ligne OBJ à y = 64 est bleue, verte, rouge, bleue, verte, rouge, bleue. Les colonnes utilisent respectivement une couleur, les composantes, une plage indexée, une palette entière, une plage absolue, un registre canonique et son alias.
À y = 88, sept cases de 8 × 8 montrent : triangle rouge (x = 16), contour carré bleu d'un pixel provenant de la banque 1 (32), triangle vert réfléchi horizontalement (48), rouge réfléchi verticalement (64), bleu réfléchi sur les deux axes (80), triangle vert devant un sprite rouge visible dans les pixels de couleur zéro (96), puis sprite rouge plein devant le triangle BG, témoin sans priorité (112). Les coordonnées sont en pixels depuis le coin supérieur gauche. Le fond reste blanc et le texte noir.
FAILED CHECKS 000 confirme les masques RGB, les booléens (dont 2), la normalisation des indices, le franchissement de palettes, l'arrêt à l'emplacement 31, l'absence d'écriture pour pointeur nul ou longueur nulle et la relecture des couleurs LCD éteint. Quatre combinaisons sont testées : ROM mixte sur DMG/CGB, ROM DMG seule sur DMG, ROM CGB seule sur CGB. Sur DMG, CGB MODE vaut 0, les triangles sont noirs, banque et réflexions n'affectent pas l'image et les deux dernières cases du bas sont des carrés noirs. Sur CGB, CGB MODE vaut 1. Le matériel réel et les conflits d'accès LCD allumé ne sont pas testés.




Commande de compilation
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-disasmImplémentation et source
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
Remplace les quatre couleurs d'une palette de fond/fenêtre par quatre mots RGB15. Cela revient à écrire une plage débutant à la couleur zéro, de longueur quatre ; aucune tuile ni aucun sprite ne reçoit automatiquement cette palette.
Syntaxe
void cgb_bg_palette(u8 palette_index, const u16* colors);Paramètres
palette_indexNuméro de palette, 0–7 ; seuls les trois bits faibles sont utilisés (
& 7).colorsconst u16*lisible contenant les mots de couleur nécessaires. Les données sont lues pendant l'appel, sans mise en file. Gardez la source et sa banque ROM accessibles ; aucun changement de banque n'est automatique. Un pointeur nul n'entraîne aucune écriture.
Valeur renvoyée
Aucune (void).
Conditions et limites
Les écritures de palette et de registres protégés n'écrivent rien en mode DMG. Safe désigne ici le contrôle du mode CGB, pas une attente d'accès PPU ni une section critique. Configurez avec le LCD éteint ou effectuez une mise à jour assez courte pendant une phase accessible. Aucune attente VBlank ni protection contre les interruptions n'est ajoutée.
Les palettes BG/fenêtre et OBJ sont stockées séparément. Les écritures de la bibliothèque activent l'incrément et laissent le registre d'indice modifié. La couleur OBJ zéro reste transparente au rendu des sprites, même si ses octets peuvent être écrits et lus.
Exemple d’utilisation
cgb_bg_palette(4,red_palette); // Exactly four color words for BG palette 4.
expect_color(0,16,32767); expect_color(0,19,31);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme montre comment les palettes BG et OBJ colorent indépendamment un même motif. Chaque triangle occupe 8 × 8 pixels, d'un seul pixel à gauche en haut jusqu'à une ligne complète en bas. Aux abscisses 16, 32, 48, 64, 80, 96, 112, la ligne BG à y = 24 est rouge, bleue, verte, rouge, bleue, verte, rouge ; la ligne OBJ à y = 64 est bleue, verte, rouge, bleue, verte, rouge, bleue. Les colonnes utilisent respectivement une couleur, les composantes, une plage indexée, une palette entière, une plage absolue, un registre canonique et son alias.
À y = 88, sept cases de 8 × 8 montrent : triangle rouge (x = 16), contour carré bleu d'un pixel provenant de la banque 1 (32), triangle vert réfléchi horizontalement (48), rouge réfléchi verticalement (64), bleu réfléchi sur les deux axes (80), triangle vert devant un sprite rouge visible dans les pixels de couleur zéro (96), puis sprite rouge plein devant le triangle BG, témoin sans priorité (112). Les coordonnées sont en pixels depuis le coin supérieur gauche. Le fond reste blanc et le texte noir.
FAILED CHECKS 000 confirme les masques RGB, les booléens (dont 2), la normalisation des indices, le franchissement de palettes, l'arrêt à l'emplacement 31, l'absence d'écriture pour pointeur nul ou longueur nulle et la relecture des couleurs LCD éteint. Quatre combinaisons sont testées : ROM mixte sur DMG/CGB, ROM DMG seule sur DMG, ROM CGB seule sur CGB. Sur DMG, CGB MODE vaut 0, les triangles sont noirs, banque et réflexions n'affectent pas l'image et les deux dernières cases du bas sont des carrés noirs. Sur CGB, CGB MODE vaut 1. Le matériel réel et les conflits d'accès LCD allumé ne sont pas testés.




Commande de compilation
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-disasmImplémentation et source
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
Consultez les changements et vérifications du 2026-10-03 pour les différences locales de cette API.
Regroupe les composantes rouge, verte et bleue avec cgb_rgb15, puis écrit une couleur dans les palettes de fond/fenêtre. Convient aux composantes fournies séparément plutôt qu'à une valeur déjà compactée.
Syntaxe
void cgb_bg_rgb(u8 palette_index, u8 color_index, u8 r5, u8 g5, u8 b5);Paramètres
palette_indexNuméro de palette, 0–7 ; seuls les trois bits faibles sont utilisés (
& 7).color_indexIndice de couleur dans la palette, 0–3 ; seuls les deux bits faibles sont utilisés (
& 3).r5, g5, b5Composantes rouge, verte et bleue, normalement 0–31 chacune. Elles sont masquées, sans saturation ; chaque argument apparaît une seule fois dans le développement de la macro.
Valeur renvoyée
Aucune (void).
Conditions et limites
Les écritures de palette et de registres protégés n'écrivent rien en mode DMG. Safe désigne ici le contrôle du mode CGB, pas une attente d'accès PPU ni une section critique. Configurez avec le LCD éteint ou effectuez une mise à jour assez courte pendant une phase accessible. Aucune attente VBlank ni protection contre les interruptions n'est ajoutée.
Les palettes BG/fenêtre et OBJ sont stockées séparément. Les écritures de la bibliothèque activent l'incrément et laissent le registre d'indice modifié. La couleur OBJ zéro reste transparente au rendu des sprites, même si ses octets peuvent être écrits et lus.
Exemple d’utilisation
cgb_bg_rgb(2,3,0,0,31); // Blue, supplied as three five-bit components.
expect_color(0,11,31744);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme montre comment les palettes BG et OBJ colorent indépendamment un même motif. Chaque triangle occupe 8 × 8 pixels, d'un seul pixel à gauche en haut jusqu'à une ligne complète en bas. Aux abscisses 16, 32, 48, 64, 80, 96, 112, la ligne BG à y = 24 est rouge, bleue, verte, rouge, bleue, verte, rouge ; la ligne OBJ à y = 64 est bleue, verte, rouge, bleue, verte, rouge, bleue. Les colonnes utilisent respectivement une couleur, les composantes, une plage indexée, une palette entière, une plage absolue, un registre canonique et son alias.
À y = 88, sept cases de 8 × 8 montrent : triangle rouge (x = 16), contour carré bleu d'un pixel provenant de la banque 1 (32), triangle vert réfléchi horizontalement (48), rouge réfléchi verticalement (64), bleu réfléchi sur les deux axes (80), triangle vert devant un sprite rouge visible dans les pixels de couleur zéro (96), puis sprite rouge plein devant le triangle BG, témoin sans priorité (112). Les coordonnées sont en pixels depuis le coin supérieur gauche. Le fond reste blanc et le texte noir.
FAILED CHECKS 000 confirme les masques RGB, les booléens (dont 2), la normalisation des indices, le franchissement de palettes, l'arrêt à l'emplacement 31, l'absence d'écriture pour pointeur nul ou longueur nulle et la relecture des couleurs LCD éteint. Quatre combinaisons sont testées : ROM mixte sur DMG/CGB, ROM DMG seule sur DMG, ROM CGB seule sur CGB. Sur DMG, CGB MODE vaut 0, les triangles sont noirs, banque et réflexions n'affectent pas l'image et les deux dernières cases du bas sont des carrés noirs. Sur CGB, CGB MODE vaut 1. Le matériel réel et les conflits d'accès LCD allumé ne sont pas testés.




Commande de compilation
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-disasmImplémentation et source
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
Consultez les changements et vérifications du 2026-10-03 pour les différences locales de cette API.
Écrit immédiatement une couleur RGB15 compactée dans les palettes de sprites (OBJ). Les indices de palette et de couleur désignent l'un des 32 emplacements ; ni les motifs ni la palette attribuée à une tuile ne changent.
Syntaxe
void cgb_obj_color(u8 palette_index, u8 color_index, u16 rgb15);Paramètres
palette_indexNuméro de palette, 0–7 ; seuls les trois bits faibles sont utilisés (
& 7).color_indexIndice de couleur dans la palette, 0–3 ; seuls les deux bits faibles sont utilisés (
& 3).rgb15Couleur RGB sur 15 bits compactée, normalement 0–32767. Les deux octets du
u16sont écrits, faible puis fort ; la bibliothèque n'efface pas explicitement le bit 15. UtilisezCGB_RGB15oucgb_rgb15pour la construire.
Valeur renvoyée
Aucune (void).
Conditions et limites
Les écritures de palette et de registres protégés n'écrivent rien en mode DMG. Safe désigne ici le contrôle du mode CGB, pas une attente d'accès PPU ni une section critique. Configurez avec le LCD éteint ou effectuez une mise à jour assez courte pendant une phase accessible. Aucune attente VBlank ni protection contre les interruptions n'est ajoutée.
Les palettes BG/fenêtre et OBJ sont stockées séparément. Les écritures de la bibliothèque activent l'incrément et laissent le registre d'indice modifié. La couleur OBJ zéro reste transparente au rendu des sprites, même si ses octets peuvent être écrits et lus.
Exemple d’utilisation
cgb_obj_color(1,3,31744); // Blue sprite color at the same palette/color indices.
expect_color(1,7,31744);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme montre comment les palettes BG et OBJ colorent indépendamment un même motif. Chaque triangle occupe 8 × 8 pixels, d'un seul pixel à gauche en haut jusqu'à une ligne complète en bas. Aux abscisses 16, 32, 48, 64, 80, 96, 112, la ligne BG à y = 24 est rouge, bleue, verte, rouge, bleue, verte, rouge ; la ligne OBJ à y = 64 est bleue, verte, rouge, bleue, verte, rouge, bleue. Les colonnes utilisent respectivement une couleur, les composantes, une plage indexée, une palette entière, une plage absolue, un registre canonique et son alias.
À y = 88, sept cases de 8 × 8 montrent : triangle rouge (x = 16), contour carré bleu d'un pixel provenant de la banque 1 (32), triangle vert réfléchi horizontalement (48), rouge réfléchi verticalement (64), bleu réfléchi sur les deux axes (80), triangle vert devant un sprite rouge visible dans les pixels de couleur zéro (96), puis sprite rouge plein devant le triangle BG, témoin sans priorité (112). Les coordonnées sont en pixels depuis le coin supérieur gauche. Le fond reste blanc et le texte noir.
FAILED CHECKS 000 confirme les masques RGB, les booléens (dont 2), la normalisation des indices, le franchissement de palettes, l'arrêt à l'emplacement 31, l'absence d'écriture pour pointeur nul ou longueur nulle et la relecture des couleurs LCD éteint. Quatre combinaisons sont testées : ROM mixte sur DMG/CGB, ROM DMG seule sur DMG, ROM CGB seule sur CGB. Sur DMG, CGB MODE vaut 0, les triangles sont noirs, banque et réflexions n'affectent pas l'image et les deux dernières cases du bas sont des carrés noirs. Sur CGB, CGB MODE vaut 1. Le matériel réel et les conflits d'accès LCD allumé ne sont pas testés.




Commande de compilation
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-disasmImplémentation et source
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
Écrit des mots RGB15 consécutifs dans les palettes de sprites (OBJ), à partir des indices indiqués. La plage peut franchir une limite de palette de quatre couleurs, mais s'arrête à la fin des 32 emplacements.
Syntaxe
void cgb_obj_colors(u8 palette_index, u8 start_color_index, const u16* colors, u8 color_count);Paramètres
palette_indexNuméro de palette, 0–7 ; seuls les trois bits faibles sont utilisés (
& 7).start_color_indexIndice de couleur dans la palette, 0–3 ; seuls les deux bits faibles sont utilisés (
& 3).colorsconst u16*lisible contenant les mots de couleur nécessaires. Les données sont lues pendant l'appel, sans mise en file. Gardez la source et sa banque ROM accessibles ; aucun changement de banque n'est automatique. Un pointeur nul n'entraîne aucune écriture.color_countNombre de mots de couleur, et non d'octets, en
u8(0–255). Zéro ne fait rien. La quantité est limitée à32 - emplacement_initial_normalisé; seuls ces mots source sont lus.
Valeur renvoyée
Aucune (void).
Conditions et limites
Les écritures de palette et de registres protégés n'écrivent rien en mode DMG. Safe désigne ici le contrôle du mode CGB, pas une attente d'accès PPU ni une section critique. Configurez avec le LCD éteint ou effectuez une mise à jour assez courte pendant une phase accessible. Aucune attente VBlank ni protection contre les interruptions n'est ajoutée.
Les palettes BG/fenêtre et OBJ sont stockées séparément. Les écritures de la bibliothèque activent l'incrément et laissent le registre d'indice modifié. La couleur OBJ zéro reste transparente au rendu des sprites, même si ses octets peuvent être écrits et lus.
Exemple d’utilisation
cgb_obj_colors(3,2,tail_red,2); // Sprite color 3 becomes red.
expect_color(1,14,0); expect_color(1,15,31);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme montre comment les palettes BG et OBJ colorent indépendamment un même motif. Chaque triangle occupe 8 × 8 pixels, d'un seul pixel à gauche en haut jusqu'à une ligne complète en bas. Aux abscisses 16, 32, 48, 64, 80, 96, 112, la ligne BG à y = 24 est rouge, bleue, verte, rouge, bleue, verte, rouge ; la ligne OBJ à y = 64 est bleue, verte, rouge, bleue, verte, rouge, bleue. Les colonnes utilisent respectivement une couleur, les composantes, une plage indexée, une palette entière, une plage absolue, un registre canonique et son alias.
À y = 88, sept cases de 8 × 8 montrent : triangle rouge (x = 16), contour carré bleu d'un pixel provenant de la banque 1 (32), triangle vert réfléchi horizontalement (48), rouge réfléchi verticalement (64), bleu réfléchi sur les deux axes (80), triangle vert devant un sprite rouge visible dans les pixels de couleur zéro (96), puis sprite rouge plein devant le triangle BG, témoin sans priorité (112). Les coordonnées sont en pixels depuis le coin supérieur gauche. Le fond reste blanc et le texte noir.
FAILED CHECKS 000 confirme les masques RGB, les booléens (dont 2), la normalisation des indices, le franchissement de palettes, l'arrêt à l'emplacement 31, l'absence d'écriture pour pointeur nul ou longueur nulle et la relecture des couleurs LCD éteint. Quatre combinaisons sont testées : ROM mixte sur DMG/CGB, ROM DMG seule sur DMG, ROM CGB seule sur CGB. Sur DMG, CGB MODE vaut 0, les triangles sont noirs, banque et réflexions n'affectent pas l'image et les deux dernières cases du bas sont des carrés noirs. Sur CGB, CGB MODE vaut 1. Le matériel réel et les conflits d'accès LCD allumé ne sont pas testés.




Commande de compilation
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-disasmImplémentation et source
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
Écrit des mots RGB15 consécutifs dans les palettes de sprites (OBJ) à partir d'un emplacement absolu. Le départ est un seul indice de 0 à 31, et non une paire palette/couleur. Les données sont des mots de couleur, pas des octets de motifs.
Syntaxe
void cgb_obj_colors_raw(u8 start_color_slot, const u16* colors, u8 color_count);Paramètres
start_color_slotEmplacement absolu de couleur, 0–31, normalisé par
& 31avant limitation de la longueur. Emplacement = palette × 4 + couleur ; ce n'est pas un décalage en octets.colorsconst u16*lisible contenant les mots de couleur nécessaires. Les données sont lues pendant l'appel, sans mise en file. Gardez la source et sa banque ROM accessibles ; aucun changement de banque n'est automatique. Un pointeur nul n'entraîne aucune écriture.color_countNombre de mots de couleur, et non d'octets, en
u8(0–255). Zéro ne fait rien. La quantité est limitée à32 - emplacement_initial_normalisé; seuls ces mots source sont lus.
Valeur renvoyée
Aucune (void).
Conditions et limites
Les écritures de palette et de registres protégés n'écrivent rien en mode DMG. Safe désigne ici le contrôle du mode CGB, pas une attente d'accès PPU ni une section critique. Configurez avec le LCD éteint ou effectuez une mise à jour assez courte pendant une phase accessible. Aucune attente VBlank ni protection contre les interruptions n'est ajoutée.
Les palettes BG/fenêtre et OBJ sont stockées séparément. Les écritures de la bibliothèque activent l'incrément et laissent le registre d'indice modifié. La couleur OBJ zéro reste transparente au rendu des sprites, même si ses octets peuvent être écrits et lus.
Exemple d’utilisation
cgb_obj_colors_raw(23,green_word,1); // Same absolute slot in the separate OBJ store.
expect_color(1,23,992);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme montre comment les palettes BG et OBJ colorent indépendamment un même motif. Chaque triangle occupe 8 × 8 pixels, d'un seul pixel à gauche en haut jusqu'à une ligne complète en bas. Aux abscisses 16, 32, 48, 64, 80, 96, 112, la ligne BG à y = 24 est rouge, bleue, verte, rouge, bleue, verte, rouge ; la ligne OBJ à y = 64 est bleue, verte, rouge, bleue, verte, rouge, bleue. Les colonnes utilisent respectivement une couleur, les composantes, une plage indexée, une palette entière, une plage absolue, un registre canonique et son alias.
À y = 88, sept cases de 8 × 8 montrent : triangle rouge (x = 16), contour carré bleu d'un pixel provenant de la banque 1 (32), triangle vert réfléchi horizontalement (48), rouge réfléchi verticalement (64), bleu réfléchi sur les deux axes (80), triangle vert devant un sprite rouge visible dans les pixels de couleur zéro (96), puis sprite rouge plein devant le triangle BG, témoin sans priorité (112). Les coordonnées sont en pixels depuis le coin supérieur gauche. Le fond reste blanc et le texte noir.
FAILED CHECKS 000 confirme les masques RGB, les booléens (dont 2), la normalisation des indices, le franchissement de palettes, l'arrêt à l'emplacement 31, l'absence d'écriture pour pointeur nul ou longueur nulle et la relecture des couleurs LCD éteint. Quatre combinaisons sont testées : ROM mixte sur DMG/CGB, ROM DMG seule sur DMG, ROM CGB seule sur CGB. Sur DMG, CGB MODE vaut 0, les triangles sont noirs, banque et réflexions n'affectent pas l'image et les deux dernières cases du bas sont des carrés noirs. Sur CGB, CGB MODE vaut 1. Le matériel réel et les conflits d'accès LCD allumé ne sont pas testés.




Commande de compilation
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-disasmImplémentation et source
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
Remplace les quatre couleurs d'une palette de sprites (OBJ) par quatre mots RGB15. Cela revient à écrire une plage débutant à la couleur zéro, de longueur quatre ; aucune tuile ni aucun sprite ne reçoit automatiquement cette palette.
Syntaxe
void cgb_obj_palette(u8 palette_index, const u16* colors);Paramètres
palette_indexNuméro de palette, 0–7 ; seuls les trois bits faibles sont utilisés (
& 7).colorsconst u16*lisible contenant les mots de couleur nécessaires. Les données sont lues pendant l'appel, sans mise en file. Gardez la source et sa banque ROM accessibles ; aucun changement de banque n'est automatique. Un pointeur nul n'entraîne aucune écriture.
Valeur renvoyée
Aucune (void).
Conditions et limites
Les écritures de palette et de registres protégés n'écrivent rien en mode DMG. Safe désigne ici le contrôle du mode CGB, pas une attente d'accès PPU ni une section critique. Configurez avec le LCD éteint ou effectuez une mise à jour assez courte pendant une phase accessible. Aucune attente VBlank ni protection contre les interruptions n'est ajoutée.
Les palettes BG/fenêtre et OBJ sont stockées séparément. Les écritures de la bibliothèque activent l'incrément et laissent le registre d'indice modifié. La couleur OBJ zéro reste transparente au rendu des sprites, même si ses octets peuvent être écrits et lus.
Exemple d’utilisation
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);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme montre comment les palettes BG et OBJ colorent indépendamment un même motif. Chaque triangle occupe 8 × 8 pixels, d'un seul pixel à gauche en haut jusqu'à une ligne complète en bas. Aux abscisses 16, 32, 48, 64, 80, 96, 112, la ligne BG à y = 24 est rouge, bleue, verte, rouge, bleue, verte, rouge ; la ligne OBJ à y = 64 est bleue, verte, rouge, bleue, verte, rouge, bleue. Les colonnes utilisent respectivement une couleur, les composantes, une plage indexée, une palette entière, une plage absolue, un registre canonique et son alias.
À y = 88, sept cases de 8 × 8 montrent : triangle rouge (x = 16), contour carré bleu d'un pixel provenant de la banque 1 (32), triangle vert réfléchi horizontalement (48), rouge réfléchi verticalement (64), bleu réfléchi sur les deux axes (80), triangle vert devant un sprite rouge visible dans les pixels de couleur zéro (96), puis sprite rouge plein devant le triangle BG, témoin sans priorité (112). Les coordonnées sont en pixels depuis le coin supérieur gauche. Le fond reste blanc et le texte noir.
FAILED CHECKS 000 confirme les masques RGB, les booléens (dont 2), la normalisation des indices, le franchissement de palettes, l'arrêt à l'emplacement 31, l'absence d'écriture pour pointeur nul ou longueur nulle et la relecture des couleurs LCD éteint. Quatre combinaisons sont testées : ROM mixte sur DMG/CGB, ROM DMG seule sur DMG, ROM CGB seule sur CGB. Sur DMG, CGB MODE vaut 0, les triangles sont noirs, banque et réflexions n'affectent pas l'image et les deux dernières cases du bas sont des carrés noirs. Sur CGB, CGB MODE vaut 1. Le matériel réel et les conflits d'accès LCD allumé ne sont pas testés.




Commande de compilation
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-disasmImplémentation et source
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
Consultez les changements et vérifications du 2026-10-03 pour les différences locales de cette API.
Regroupe les composantes rouge, verte et bleue avec cgb_rgb15, puis écrit une couleur dans les palettes de sprites (OBJ). Convient aux composantes fournies séparément plutôt qu'à une valeur déjà compactée.
Syntaxe
void cgb_obj_rgb(u8 palette_index, u8 color_index, u8 r5, u8 g5, u8 b5);Paramètres
palette_indexNuméro de palette, 0–7 ; seuls les trois bits faibles sont utilisés (
& 7).color_indexIndice de couleur dans la palette, 0–3 ; seuls les deux bits faibles sont utilisés (
& 3).r5, g5, b5Composantes rouge, verte et bleue, normalement 0–31 chacune. Elles sont masquées, sans saturation ; chaque argument apparaît une seule fois dans le développement de la macro.
Valeur renvoyée
Aucune (void).
Conditions et limites
Les écritures de palette et de registres protégés n'écrivent rien en mode DMG. Safe désigne ici le contrôle du mode CGB, pas une attente d'accès PPU ni une section critique. Configurez avec le LCD éteint ou effectuez une mise à jour assez courte pendant une phase accessible. Aucune attente VBlank ni protection contre les interruptions n'est ajoutée.
Les palettes BG/fenêtre et OBJ sont stockées séparément. Les écritures de la bibliothèque activent l'incrément et laissent le registre d'indice modifié. La couleur OBJ zéro reste transparente au rendu des sprites, même si ses octets peuvent être écrits et lus.
Exemple d’utilisation
cgb_obj_rgb(2,3,0,31,0); // Green sprite color.
expect_color(1,11,992);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme montre comment les palettes BG et OBJ colorent indépendamment un même motif. Chaque triangle occupe 8 × 8 pixels, d'un seul pixel à gauche en haut jusqu'à une ligne complète en bas. Aux abscisses 16, 32, 48, 64, 80, 96, 112, la ligne BG à y = 24 est rouge, bleue, verte, rouge, bleue, verte, rouge ; la ligne OBJ à y = 64 est bleue, verte, rouge, bleue, verte, rouge, bleue. Les colonnes utilisent respectivement une couleur, les composantes, une plage indexée, une palette entière, une plage absolue, un registre canonique et son alias.
À y = 88, sept cases de 8 × 8 montrent : triangle rouge (x = 16), contour carré bleu d'un pixel provenant de la banque 1 (32), triangle vert réfléchi horizontalement (48), rouge réfléchi verticalement (64), bleu réfléchi sur les deux axes (80), triangle vert devant un sprite rouge visible dans les pixels de couleur zéro (96), puis sprite rouge plein devant le triangle BG, témoin sans priorité (112). Les coordonnées sont en pixels depuis le coin supérieur gauche. Le fond reste blanc et le texte noir.
FAILED CHECKS 000 confirme les masques RGB, les booléens (dont 2), la normalisation des indices, le franchissement de palettes, l'arrêt à l'emplacement 31, l'absence d'écriture pour pointeur nul ou longueur nulle et la relecture des couleurs LCD éteint. Quatre combinaisons sont testées : ROM mixte sur DMG/CGB, ROM DMG seule sur DMG, ROM CGB seule sur CGB. Sur DMG, CGB MODE vaut 0, les triangles sont noirs, banque et réflexions n'affectent pas l'image et les deux dernières cases du bas sont des carrés noirs. Sur CGB, CGB MODE vaut 1. Le matériel réel et les conflits d'accès LCD allumé ne sont pas testés.




Commande de compilation
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-disasmImplémentation et source
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
Regroupe RGB dans un u16 : rouge aux bits 0–4, vert aux bits 5–9, bleu aux bits 10–14 ; le bit 15 vaut zéro. Le masque 31 conserve les cinq bits faibles de chaque composante, sans saturation. Calcule uniquement une valeur, sur DMG comme sur CGB, sans écriture matérielle.
Syntaxe
#define CGB_RGB15(r5, g5, b5) ((u16)((u16)((r5) & 31) | ((u16)((g5) & 31) << 5) | ((u16)((b5) & 31) << 10)))Paramètres
r5, g5, b5Composantes rouge, verte et bleue, normalement 0–31 chacune. Elles sont masquées, sans saturation ; chaque argument apparaît une seule fois dans le développement de la macro.
Valeur renvoyée
Valeur RGB15 compactée en u16, de 0 à 32767.
Exemple d’utilisation
if (CGB_RGB15(component,64,95)!=31775) failures++; // (31,0,31), not saturation.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme montre comment les palettes BG et OBJ colorent indépendamment un même motif. Chaque triangle occupe 8 × 8 pixels, d'un seul pixel à gauche en haut jusqu'à une ligne complète en bas. Aux abscisses 16, 32, 48, 64, 80, 96, 112, la ligne BG à y = 24 est rouge, bleue, verte, rouge, bleue, verte, rouge ; la ligne OBJ à y = 64 est bleue, verte, rouge, bleue, verte, rouge, bleue. Les colonnes utilisent respectivement une couleur, les composantes, une plage indexée, une palette entière, une plage absolue, un registre canonique et son alias.
À y = 88, sept cases de 8 × 8 montrent : triangle rouge (x = 16), contour carré bleu d'un pixel provenant de la banque 1 (32), triangle vert réfléchi horizontalement (48), rouge réfléchi verticalement (64), bleu réfléchi sur les deux axes (80), triangle vert devant un sprite rouge visible dans les pixels de couleur zéro (96), puis sprite rouge plein devant le triangle BG, témoin sans priorité (112). Les coordonnées sont en pixels depuis le coin supérieur gauche. Le fond reste blanc et le texte noir.
FAILED CHECKS 000 confirme les masques RGB, les booléens (dont 2), la normalisation des indices, le franchissement de palettes, l'arrêt à l'emplacement 31, l'absence d'écriture pour pointeur nul ou longueur nulle et la relecture des couleurs LCD éteint. Quatre combinaisons sont testées : ROM mixte sur DMG/CGB, ROM DMG seule sur DMG, ROM CGB seule sur CGB. Sur DMG, CGB MODE vaut 0, les triangles sont noirs, banque et réflexions n'affectent pas l'image et les deux dernières cases du bas sont des carrés noirs. Sur CGB, CGB MODE vaut 1. Le matériel réel et les conflits d'accès LCD allumé ne sont pas testés.




Commande de compilation
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-disasmImplémentation et source
kitaqgb/lib/cgb_palette.h:16
cgb_rgb15
Regroupe RGB dans un u16 : rouge aux bits 0–4, vert aux bits 5–9, bleu aux bits 10–14 ; le bit 15 vaut zéro. Le masque 31 conserve les cinq bits faibles de chaque composante, sans saturation. Calcule uniquement une valeur, sur DMG comme sur CGB, sans écriture matérielle.
Syntaxe
u16 cgb_rgb15(u8 r5, u8 g5, u8 b5);Paramètres
r5, g5, b5Composantes rouge, verte et bleue, normalement 0–31 chacune. Elles sont masquées, sans saturation ; chaque argument apparaît une seule fois dans le développement de la macro.
Valeur renvoyée
Valeur RGB15 compactée en u16, de 0 à 32767.
Exemple d’utilisation
if (cgb_rgb15(component,64,95)!=31775) failures++; // Same packed value through a function.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme montre comment les palettes BG et OBJ colorent indépendamment un même motif. Chaque triangle occupe 8 × 8 pixels, d'un seul pixel à gauche en haut jusqu'à une ligne complète en bas. Aux abscisses 16, 32, 48, 64, 80, 96, 112, la ligne BG à y = 24 est rouge, bleue, verte, rouge, bleue, verte, rouge ; la ligne OBJ à y = 64 est bleue, verte, rouge, bleue, verte, rouge, bleue. Les colonnes utilisent respectivement une couleur, les composantes, une plage indexée, une palette entière, une plage absolue, un registre canonique et son alias.
À y = 88, sept cases de 8 × 8 montrent : triangle rouge (x = 16), contour carré bleu d'un pixel provenant de la banque 1 (32), triangle vert réfléchi horizontalement (48), rouge réfléchi verticalement (64), bleu réfléchi sur les deux axes (80), triangle vert devant un sprite rouge visible dans les pixels de couleur zéro (96), puis sprite rouge plein devant le triangle BG, témoin sans priorité (112). Les coordonnées sont en pixels depuis le coin supérieur gauche. Le fond reste blanc et le texte noir.
FAILED CHECKS 000 confirme les masques RGB, les booléens (dont 2), la normalisation des indices, le franchissement de palettes, l'arrêt à l'emplacement 31, l'absence d'écriture pour pointeur nul ou longueur nulle et la relecture des couleurs LCD éteint. Quatre combinaisons sont testées : ROM mixte sur DMG/CGB, ROM DMG seule sur DMG, ROM CGB seule sur CGB. Sur DMG, CGB MODE vaut 0, les triangles sont noirs, banque et réflexions n'affectent pas l'image et les deux dernières cases du bas sont des carrés noirs. Sur CGB, CGB MODE vaut 1. Le matériel réel et les conflits d'accès LCD allumé ne sont pas testés.




Commande de compilation
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-disasmImplémentation et source
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 — Numéros et attributs de tuiles CGB
cgb_tile.h regroupe les déclarations des fonctions intrinsèques de carte de tuiles et les macros de construction des attributs CGB. Le numéro de tuile choisit un motif ; son attribut choisit palette, banque VRAM du motif, retournements et priorité du fond. Modifier les attributs ne change pas les pixels du motif.
La famille __settile vise la carte 0x9800 ; __settileat utilise une base explicite ; __settilebg, la carte de fond choisie par LCDC ; __settilewin, sa carte de fenêtre. Les formes attr n’écrivent que les attributs, les formes cgb écrivent numéros et attributs. Les formes bulk transfèrent des octets consécutifs à l’adresse fournie. Choisissez selon la destination et les données à écrire.
Utilisez des macros comme KQ_CGB_ATTR_PAL pour les bits individuels, ou KQ_CGB_ATTR pour combiner les champs. Le champ bank choisit la banque VRAM du motif, pas une banque ROM. Les écritures ordinaires de numéros utilisent la banque VRAM courante : sélectionnez la banque zéro avant les opérations combinées tuile/attribut. Sur DMG, les opérations d’attribut seul sont sans effet ; les opérations combinées écrivent toujours les numéros.
Le compilateur génère l’implémentation des fonctions intrinsèques __ ; il n’est pas nécessaire de lier cgb_tile.c. Les chemins d’écriture ordinaires attendent l’accès VRAM, mais certains changent aussi l’activation des interruptions. Les formes _unsafe et _fast omettent ces attentes : utilisez-les seulement si l’appelant garantit une VRAM accessible en écriture, par exemple LCD éteint. Vérifiez les conditions d’interruption, de banque et de longueur de chaque entrée.
KQ_CGB_ATTR
Construit l'octet complet d'attribut de carte CGB : palette, banque de motifs, réflexion horizontale, réflexion verticale et priorité BG. La palette occupe les bits 0–2 ; les quatre booléens règlent les bits 3, 5, 6 et 7. Le bit 4 reste nul.
Syntaxe
#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)))Paramètres
paletteNuméro de palette, 0–7 ; seuls les trois bits faibles sont utilisés (
& 7).bank, xflip, yflip, priorityZéro désactive le champ ; toute valeur non nulle l'active. Le 2 l'active aussi : le test porte sur la non-nullité, pas sur le bit faible.
Valeur renvoyée
Champ d'attribut ou octet combiné en u8, selon la disposition de bits décrite.
Conditions et limites
Ces macros calculent uniquement des valeurs u8, sans écrire en VRAM ni dans les registres. Chaque argument apparaît une fois. Appliquez le résultat par une API d'attributs CGB ou une écriture explicite dans la carte de banque 1. DMG n'affiche pas les attributs CGB.
Construit le bit 3 d'un attribut de carte CGB : 0x08 si bank est non nul, sinon 0. Choisit la banque VRAM du motif affiché, sans écrire VBK ni changer la banque de la CPU.
Construit le drapeau de réflexion horizontale : 0x20 si enabled est non nul, sinon 0. Dans un attribut de carte CGB, inverse l'affichage des huit pixels de chaque ligne sans modifier le motif stocké.
Construit le drapeau de réflexion verticale : 0x40 si enabled est non nul, sinon 0. Dans la carte CGB, affiche les huit lignes dans l'ordre inverse sans modifier le motif stocké.
Construit la priorité BG sur OBJ : 0x80 si enabled est non nul, sinon 0. Quand la priorité générale CGB est active (bit 0 de LCDC), les indices de couleur BG non nuls masquent les sprites. L'indice zéro les laisse passer ; le drapeau ne rend pas toute la tuile opaque.
Exemple d’utilisation
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);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme montre comment les palettes BG et OBJ colorent indépendamment un même motif. Chaque triangle occupe 8 × 8 pixels, d'un seul pixel à gauche en haut jusqu'à une ligne complète en bas. Aux abscisses 16, 32, 48, 64, 80, 96, 112, la ligne BG à y = 24 est rouge, bleue, verte, rouge, bleue, verte, rouge ; la ligne OBJ à y = 64 est bleue, verte, rouge, bleue, verte, rouge, bleue. Les colonnes utilisent respectivement une couleur, les composantes, une plage indexée, une palette entière, une plage absolue, un registre canonique et son alias.
À y = 88, sept cases de 8 × 8 montrent : triangle rouge (x = 16), contour carré bleu d'un pixel provenant de la banque 1 (32), triangle vert réfléchi horizontalement (48), rouge réfléchi verticalement (64), bleu réfléchi sur les deux axes (80), triangle vert devant un sprite rouge visible dans les pixels de couleur zéro (96), puis sprite rouge plein devant le triangle BG, témoin sans priorité (112). Les coordonnées sont en pixels depuis le coin supérieur gauche. Le fond reste blanc et le texte noir.
FAILED CHECKS 000 confirme les masques RGB, les booléens (dont 2), la normalisation des indices, le franchissement de palettes, l'arrêt à l'emplacement 31, l'absence d'écriture pour pointeur nul ou longueur nulle et la relecture des couleurs LCD éteint. Quatre combinaisons sont testées : ROM mixte sur DMG/CGB, ROM DMG seule sur DMG, ROM CGB seule sur CGB. Sur DMG, CGB MODE vaut 0, les triangles sont noirs, banque et réflexions n'affectent pas l'image et les deux dernières cases du bas sont des carrés noirs. Sur CGB, CGB MODE vaut 1. Le matériel réel et les conflits d'accès LCD allumé ne sont pas testés.




Commande de compilation
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-disasmImplémentation et source
kitaqgb/lib/cgb_tile.h:23
KQ_CGB_ATTR_BANK
Construit le bit 3 d'un attribut de carte CGB : 0x08 si bank est non nul, sinon 0. Choisit la banque VRAM du motif affiché, sans écrire VBK ni changer la banque de la CPU.
Syntaxe
#define KQ_CGB_ATTR_BANK(bank) ((u8)((bank) ? KQ_CGB_ATTR_BANK1 : 0))Paramètres
bankZéro désactive le champ ; toute valeur non nulle l'active. Le 2 l'active aussi : le test porte sur la non-nullité, pas sur le bit faible.
Valeur renvoyée
Champ d'attribut ou octet combiné en u8, selon la disposition de bits décrite.
Conditions et limites
Ces macros calculent uniquement des valeurs u8, sans écrire en VRAM ni dans les registres. Chaque argument apparaît une fois. Appliquez le résultat par une API d'attributs CGB ou une écriture explicite dans la carte de banque 1. DMG n'affiche pas les attributs CGB.
Exemple d’utilisation
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.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme montre comment les palettes BG et OBJ colorent indépendamment un même motif. Chaque triangle occupe 8 × 8 pixels, d'un seul pixel à gauche en haut jusqu'à une ligne complète en bas. Aux abscisses 16, 32, 48, 64, 80, 96, 112, la ligne BG à y = 24 est rouge, bleue, verte, rouge, bleue, verte, rouge ; la ligne OBJ à y = 64 est bleue, verte, rouge, bleue, verte, rouge, bleue. Les colonnes utilisent respectivement une couleur, les composantes, une plage indexée, une palette entière, une plage absolue, un registre canonique et son alias.
À y = 88, sept cases de 8 × 8 montrent : triangle rouge (x = 16), contour carré bleu d'un pixel provenant de la banque 1 (32), triangle vert réfléchi horizontalement (48), rouge réfléchi verticalement (64), bleu réfléchi sur les deux axes (80), triangle vert devant un sprite rouge visible dans les pixels de couleur zéro (96), puis sprite rouge plein devant le triangle BG, témoin sans priorité (112). Les coordonnées sont en pixels depuis le coin supérieur gauche. Le fond reste blanc et le texte noir.
FAILED CHECKS 000 confirme les masques RGB, les booléens (dont 2), la normalisation des indices, le franchissement de palettes, l'arrêt à l'emplacement 31, l'absence d'écriture pour pointeur nul ou longueur nulle et la relecture des couleurs LCD éteint. Quatre combinaisons sont testées : ROM mixte sur DMG/CGB, ROM DMG seule sur DMG, ROM CGB seule sur CGB. Sur DMG, CGB MODE vaut 0, les triangles sont noirs, banque et réflexions n'affectent pas l'image et les deux dernières cases du bas sont des carrés noirs. Sur CGB, CGB MODE vaut 1. Le matériel réel et les conflits d'accès LCD allumé ne sont pas testés.




Commande de compilation
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-disasmImplémentation et source
kitaqgb/lib/cgb_tile.h:19
KQ_CGB_ATTR_PAL
Construit le champ de palette d'un attribut de carte CGB : n & 7, en u8. Combinez-le avec les autres drapeaux par OU binaire.
Syntaxe
#define KQ_CGB_ATTR_PAL(n) ((u8)((n) & KQ_CGB_ATTR_PAL_MASK))Paramètres
nNuméro de palette, 0–7 ; seuls les trois bits faibles sont utilisés (
& 7).
Valeur renvoyée
Champ d'attribut ou octet combiné en u8, selon la disposition de bits décrite.
Conditions et limites
Ces macros calculent uniquement des valeurs u8, sans écrire en VRAM ni dans les registres. Chaque argument apparaît une fois. Appliquez le résultat par une API d'attributs CGB ou une écriture explicite dans la carte de banque 1. DMG n'affiche pas les attributs CGB.
Exemple d’utilisation
attr=KQ_CGB_ATTR_PAL(9); // 9 & 7 = palette 1, red in this BG example.
if (attr!=1) failures++;
cell(2,11,1,attr);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme montre comment les palettes BG et OBJ colorent indépendamment un même motif. Chaque triangle occupe 8 × 8 pixels, d'un seul pixel à gauche en haut jusqu'à une ligne complète en bas. Aux abscisses 16, 32, 48, 64, 80, 96, 112, la ligne BG à y = 24 est rouge, bleue, verte, rouge, bleue, verte, rouge ; la ligne OBJ à y = 64 est bleue, verte, rouge, bleue, verte, rouge, bleue. Les colonnes utilisent respectivement une couleur, les composantes, une plage indexée, une palette entière, une plage absolue, un registre canonique et son alias.
À y = 88, sept cases de 8 × 8 montrent : triangle rouge (x = 16), contour carré bleu d'un pixel provenant de la banque 1 (32), triangle vert réfléchi horizontalement (48), rouge réfléchi verticalement (64), bleu réfléchi sur les deux axes (80), triangle vert devant un sprite rouge visible dans les pixels de couleur zéro (96), puis sprite rouge plein devant le triangle BG, témoin sans priorité (112). Les coordonnées sont en pixels depuis le coin supérieur gauche. Le fond reste blanc et le texte noir.
FAILED CHECKS 000 confirme les masques RGB, les booléens (dont 2), la normalisation des indices, le franchissement de palettes, l'arrêt à l'emplacement 31, l'absence d'écriture pour pointeur nul ou longueur nulle et la relecture des couleurs LCD éteint. Quatre combinaisons sont testées : ROM mixte sur DMG/CGB, ROM DMG seule sur DMG, ROM CGB seule sur CGB. Sur DMG, CGB MODE vaut 0, les triangles sont noirs, banque et réflexions n'affectent pas l'image et les deux dernières cases du bas sont des carrés noirs. Sur CGB, CGB MODE vaut 1. Le matériel réel et les conflits d'accès LCD allumé ne sont pas testés.




Commande de compilation
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-disasmImplémentation et source
kitaqgb/lib/cgb_tile.h:18
KQ_CGB_ATTR_PRIORITY_IF
Construit la priorité BG sur OBJ : 0x80 si enabled est non nul, sinon 0. Quand la priorité générale CGB est active (bit 0 de LCDC), les indices de couleur BG non nuls masquent les sprites. L'indice zéro les laisse passer ; le drapeau ne rend pas toute la tuile opaque.
Syntaxe
#define KQ_CGB_ATTR_PRIORITY_IF(enabled) ((u8)((enabled) ? KQ_CGB_ATTR_PRIORITY : 0))Paramètres
enabledZéro désactive le champ ; toute valeur non nulle l'active. Le 2 l'active aussi : le test porte sur la non-nullité, pas sur le bit faible.
Valeur renvoyée
Champ d'attribut ou octet combiné en u8, selon la disposition de bits décrite.
Conditions et limites
Ces macros calculent uniquement des valeurs u8, sans écrire en VRAM ni dans les registres. Chaque argument apparaît une fois. Appliquez le résultat par une API d'attributs CGB ou une écriture explicite dans la carte de banque 1. DMG n'affiche pas les attributs CGB.
Exemple d’utilisation
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.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme montre comment les palettes BG et OBJ colorent indépendamment un même motif. Chaque triangle occupe 8 × 8 pixels, d'un seul pixel à gauche en haut jusqu'à une ligne complète en bas. Aux abscisses 16, 32, 48, 64, 80, 96, 112, la ligne BG à y = 24 est rouge, bleue, verte, rouge, bleue, verte, rouge ; la ligne OBJ à y = 64 est bleue, verte, rouge, bleue, verte, rouge, bleue. Les colonnes utilisent respectivement une couleur, les composantes, une plage indexée, une palette entière, une plage absolue, un registre canonique et son alias.
À y = 88, sept cases de 8 × 8 montrent : triangle rouge (x = 16), contour carré bleu d'un pixel provenant de la banque 1 (32), triangle vert réfléchi horizontalement (48), rouge réfléchi verticalement (64), bleu réfléchi sur les deux axes (80), triangle vert devant un sprite rouge visible dans les pixels de couleur zéro (96), puis sprite rouge plein devant le triangle BG, témoin sans priorité (112). Les coordonnées sont en pixels depuis le coin supérieur gauche. Le fond reste blanc et le texte noir.
FAILED CHECKS 000 confirme les masques RGB, les booléens (dont 2), la normalisation des indices, le franchissement de palettes, l'arrêt à l'emplacement 31, l'absence d'écriture pour pointeur nul ou longueur nulle et la relecture des couleurs LCD éteint. Quatre combinaisons sont testées : ROM mixte sur DMG/CGB, ROM DMG seule sur DMG, ROM CGB seule sur CGB. Sur DMG, CGB MODE vaut 0, les triangles sont noirs, banque et réflexions n'affectent pas l'image et les deux dernières cases du bas sont des carrés noirs. Sur CGB, CGB MODE vaut 1. Le matériel réel et les conflits d'accès LCD allumé ne sont pas testés.




Commande de compilation
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-disasmImplémentation et source
kitaqgb/lib/cgb_tile.h:22
KQ_CGB_ATTR_XFLIP_IF
Construit le drapeau de réflexion horizontale : 0x20 si enabled est non nul, sinon 0. Dans un attribut de carte CGB, inverse l'affichage des huit pixels de chaque ligne sans modifier le motif stocké.
Syntaxe
#define KQ_CGB_ATTR_XFLIP_IF(enabled) ((u8)((enabled) ? KQ_CGB_ATTR_XFLIP : 0))Paramètres
enabledZéro désactive le champ ; toute valeur non nulle l'active. Le 2 l'active aussi : le test porte sur la non-nullité, pas sur le bit faible.
Valeur renvoyée
Champ d'attribut ou octet combiné en u8, selon la disposition de bits décrite.
Conditions et limites
Ces macros calculent uniquement des valeurs u8, sans écrire en VRAM ni dans les registres. Chaque argument apparaît une fois. Appliquez le résultat par une API d'attributs CGB ou une écriture explicite dans la carte de banque 1. DMG n'affiche pas les attributs CGB.
Exemple d’utilisation
attr=(u8)(3|KQ_CGB_ATTR_XFLIP_IF(enabled));
if (attr!=35) failures++;
cell(6,11,1,attr); // Green triangle reflected horizontally.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme montre comment les palettes BG et OBJ colorent indépendamment un même motif. Chaque triangle occupe 8 × 8 pixels, d'un seul pixel à gauche en haut jusqu'à une ligne complète en bas. Aux abscisses 16, 32, 48, 64, 80, 96, 112, la ligne BG à y = 24 est rouge, bleue, verte, rouge, bleue, verte, rouge ; la ligne OBJ à y = 64 est bleue, verte, rouge, bleue, verte, rouge, bleue. Les colonnes utilisent respectivement une couleur, les composantes, une plage indexée, une palette entière, une plage absolue, un registre canonique et son alias.
À y = 88, sept cases de 8 × 8 montrent : triangle rouge (x = 16), contour carré bleu d'un pixel provenant de la banque 1 (32), triangle vert réfléchi horizontalement (48), rouge réfléchi verticalement (64), bleu réfléchi sur les deux axes (80), triangle vert devant un sprite rouge visible dans les pixels de couleur zéro (96), puis sprite rouge plein devant le triangle BG, témoin sans priorité (112). Les coordonnées sont en pixels depuis le coin supérieur gauche. Le fond reste blanc et le texte noir.
FAILED CHECKS 000 confirme les masques RGB, les booléens (dont 2), la normalisation des indices, le franchissement de palettes, l'arrêt à l'emplacement 31, l'absence d'écriture pour pointeur nul ou longueur nulle et la relecture des couleurs LCD éteint. Quatre combinaisons sont testées : ROM mixte sur DMG/CGB, ROM DMG seule sur DMG, ROM CGB seule sur CGB. Sur DMG, CGB MODE vaut 0, les triangles sont noirs, banque et réflexions n'affectent pas l'image et les deux dernières cases du bas sont des carrés noirs. Sur CGB, CGB MODE vaut 1. Le matériel réel et les conflits d'accès LCD allumé ne sont pas testés.




Commande de compilation
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-disasmImplémentation et source
kitaqgb/lib/cgb_tile.h:20
KQ_CGB_ATTR_YFLIP_IF
Construit le drapeau de réflexion verticale : 0x40 si enabled est non nul, sinon 0. Dans la carte CGB, affiche les huit lignes dans l'ordre inverse sans modifier le motif stocké.
Syntaxe
#define KQ_CGB_ATTR_YFLIP_IF(enabled) ((u8)((enabled) ? KQ_CGB_ATTR_YFLIP : 0))Paramètres
enabledZéro désactive le champ ; toute valeur non nulle l'active. Le 2 l'active aussi : le test porte sur la non-nullité, pas sur le bit faible.
Valeur renvoyée
Champ d'attribut ou octet combiné en u8, selon la disposition de bits décrite.
Conditions et limites
Ces macros calculent uniquement des valeurs u8, sans écrire en VRAM ni dans les registres. Chaque argument apparaît une fois. Appliquez le résultat par une API d'attributs CGB ou une écriture explicite dans la carte de banque 1. DMG n'affiche pas les attributs CGB.
Exemple d’utilisation
attr=(u8)(1|KQ_CGB_ATTR_YFLIP_IF(enabled));
if (attr!=65) failures++;
cell(8,11,1,attr); // Red triangle reflected vertically.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme montre comment les palettes BG et OBJ colorent indépendamment un même motif. Chaque triangle occupe 8 × 8 pixels, d'un seul pixel à gauche en haut jusqu'à une ligne complète en bas. Aux abscisses 16, 32, 48, 64, 80, 96, 112, la ligne BG à y = 24 est rouge, bleue, verte, rouge, bleue, verte, rouge ; la ligne OBJ à y = 64 est bleue, verte, rouge, bleue, verte, rouge, bleue. Les colonnes utilisent respectivement une couleur, les composantes, une plage indexée, une palette entière, une plage absolue, un registre canonique et son alias.
À y = 88, sept cases de 8 × 8 montrent : triangle rouge (x = 16), contour carré bleu d'un pixel provenant de la banque 1 (32), triangle vert réfléchi horizontalement (48), rouge réfléchi verticalement (64), bleu réfléchi sur les deux axes (80), triangle vert devant un sprite rouge visible dans les pixels de couleur zéro (96), puis sprite rouge plein devant le triangle BG, témoin sans priorité (112). Les coordonnées sont en pixels depuis le coin supérieur gauche. Le fond reste blanc et le texte noir.
FAILED CHECKS 000 confirme les masques RGB, les booléens (dont 2), la normalisation des indices, le franchissement de palettes, l'arrêt à l'emplacement 31, l'absence d'écriture pour pointeur nul ou longueur nulle et la relecture des couleurs LCD éteint. Quatre combinaisons sont testées : ROM mixte sur DMG/CGB, ROM DMG seule sur DMG, ROM CGB seule sur CGB. Sur DMG, CGB MODE vaut 0, les triangles sont noirs, banque et réflexions n'affectent pas l'image et les deux dernières cases du bas sont des carrés noirs. Sur CGB, CGB MODE vaut 1. Le matériel réel et les conflits d'accès LCD allumé ne sont pas testés.




Commande de compilation
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-disasmImplémentation et source
kitaqgb/lib/cgb_tile.h:21
chain.h — Tampons circulaires pour l'historique des positions
Utilisez ChainBody pour les serpents ou cordes articulés, et Chain pour conserver un historique de positions. Chaque articulation stocke sa position courante et l’une des 16 orientations ; les courbures se propagent vers l’arrière d’une articulation par mise à jour. Les opérations sur le corps gèrent les terrains à rebouclage, l’allongement par duplication de la queue et les corrections de deux pixels au plus par axe.
chain_wrap_delta
Calcule le plus court déplacement signé de la position courante vers une cible sur un axe dont les extrémités se rejoignent. Utilisez-le pour le suivi ou la comparaison de distances à travers un bord du terrain.
Syntaxe
s16 chain_wrap_delta(u8 target, u8 current, u16 size);Paramètres
targetCoordonnée cible, de 0 à size−1.
currentCoordonnée courante, de 0 à size−1.
sizeLongueur de l’axe à rebouclage, de 1 à 256 : largeur pour X, hauteur pour Y. L’argument est sur 16 bits pour représenter 256.
Valeur renvoyée
Renvoie le plus court déplacement en s16 : positif vers les coordonnées croissantes, négatif vers les décroissantes, zéro à la même position. Les entrées valides donnent −128..+128. À l’écran, droite et bas sont positifs.
Conditions et limites
Incluez chain.h et compilez chain.c exactement une fois. Aucune initialisation de Chain ou ChainBody n’est nécessaire. La fonction calcule seulement un déplacement, sans modifier tableaux de coordonnées, nombre d’articulations ni écran.
La fonction ne valide ni ne normalise les entrées. Ne passez pas size=0, size>256 ou des coordonnées supérieures ou égales à size. Ramenez les coordonnées d’un système plus grand dans 0..size−1 par rebouclage avant l’appel.
Si les deux chemins ont la même longueur, conserve le signe du déplacement direct target−current. Avec size=160, 0→80 renvoie +80 et 80→0 renvoie −80. Avec size=1, zéro est la seule coordonnée valide et le résultat vaut zéro.
Exemple d’utilisation
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.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple présente les coordonnées à rebouclage. Chaque flèche va de la position courante à la cible. Il affiche +02/−02 pour traverser un bord de largeur 160, +80/−80 pour un demi-terrain et +00 pour la largeur 1. Le zéro initial est un remplissage décimal. L’exemple ne dessine ni ne déplace d’objet.


Commande de compilation
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-disasmImplémentation et source
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
Associe trois tableaux d’articulations fournis par l’appelant et met leur nombre à zéro, sans allouer de mémoire.
Syntaxe
u8 chain_body_init(ChainBody* body, u8* x, u8* y, u8* heading, u8 capacity, u16 width, u16 height);Paramètres
bodyChainBodycible ; null est ignoré. Sauf pour l’initialisation, passez un état déjà initialisé.xTableau des coordonnées X des articulations.
yTableau des coordonnées Y des articulations.
headingTableau des orientations des articulations.
capacityLongueur allouée du tableau, de 1 à 255.
widthLargeur du terrain à rebouclage, de 1 à 256.
heightHauteur du terrain à rebouclage, de 1 à 256.
Valeur renvoyée
Renvoie 1 en cas de succès, 0 pour des arguments invalides. Un échec avec un corps non nul met capacity et count à zéro, désactivant les mises à jour.
Conditions et limites
Incluez chain.h et compilez chain.c exactement une fois. ChainBody contient la position et l’orientation courantes de chaque articulation. Ce type d’état est distinct de l’historique circulaire de positions Chain.
Fournissez trois tableaux distincts accessibles en écriture, x, y et heading, de capacity octets chacun. Conservez-les pendant l’utilisation du corps. L’indice zéro est la tête, comprise dans count. Ne modifiez pas les pointeurs, la capacité ou les dimensions du terrain après l’initialisation.
Les orientations suivent 16 secteurs horaires : 0=droite, 4=bas, 8=gauche, 12=haut. Seuls les quatre bits de poids faible sont utilisés. Les coordonnées d’écran augmentent vers la droite et le bas ; chaque dimension va de 1 à 256 pixels.
Exemple d’utilisation
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.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’image montre en haut un corps droit, au milieu une mise à jour après un virage vers le bas et en bas quatre mises à jour après ce virage. Les coordonnées sont dessinées au double de leur taille logique. La courbure se propage depuis la tête à droite vers l’arrière. CGB et FC utilisent rouge pour la tête, bleu pour le corps et vert pour la queue ; DMG utilise noir. Quatre mises à jour de stabilisation séparent la queue dupliquée après croissance. Ce sont trois vues des mêmes huit articulations, pas un corps de 24 articulations.


Commande de compilation
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-disasmImplémentation et source
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
Construit une pose initiale droite en plaçant les articulations derrière la tête indiquée.
Syntaxe
u8 chain_body_reset(ChainBody* body, u8 count, u8 head_x, u8 head_y, u8 heading);Paramètres
bodyChainBodycible ; null est ignoré. Sauf pour l’initialisation, passez un état déjà initialisé.countNombre d’articulations, tête comprise, de 1 à capacity.
head_xCoordonnée X de la tête, ramenée par rebouclage à la largeur du terrain.
head_yCoordonnée Y de la tête, ramenée par rebouclage à la hauteur du terrain.
headingOrientation de la tête dans le système à 16 secteurs.
Valeur renvoyée
Renvoie 1 en cas de succès. Un nombre nul ou excessif, ou un corps nul, renvoie 0 sans modifier la pose.
Conditions et limites
Incluez chain.h et compilez chain.c exactement une fois. ChainBody contient la position et l’orientation courantes de chaque articulation. Ce type d’état est distinct de l’historique circulaire de positions Chain.
Fournissez trois tableaux distincts accessibles en écriture, x, y et heading, de capacity octets chacun. Conservez-les pendant l’utilisation du corps. L’indice zéro est la tête, comprise dans count. Ne modifiez pas les pointeurs, la capacité ou les dimensions du terrain après l’initialisation.
Les orientations suivent 16 secteurs horaires : 0=droite, 4=bas, 8=gauche, 12=haut. Seuls les quatre bits de poids faible sont utilisés. Les coordonnées d’écran augmentent vers la droite et le bas ; chaque dimension va de 1 à 256 pixels.
L’espacement cardinal est de quatre pixels. Les orientations intermédiaires utilisent des vecteurs entiers comme (4,1), (3,3) et (1,4) ; la distance euclidienne n’est donc pas exactement quatre pixels. La pose initiale peut franchir un bord du terrain.
Exemple d’utilisation
chain_body_reset(&body,7,48,16,0); // Seven joints, facing right.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’image montre en haut un corps droit, au milieu une mise à jour après un virage vers le bas et en bas quatre mises à jour après ce virage. Les coordonnées sont dessinées au double de leur taille logique. La courbure se propage depuis la tête à droite vers l’arrière. CGB et FC utilisent rouge pour la tête, bleu pour le corps et vert pour la queue ; DMG utilise noir. Quatre mises à jour de stabilisation séparent la queue dupliquée après croissance. Ce sont trois vues des mêmes huit articulations, pas un corps de 24 articulations.


Commande de compilation
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-disasmImplémentation et source
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
Définit la pose de la tête et attire progressivement chaque articulation vers un point d’attache derrière la précédente. Les changements d’orientation se propagent d’une articulation par mise à jour.
Syntaxe
void chain_body_step(ChainBody* body, u8 head_x, u8 head_y, u8 heading);Paramètres
bodyChainBodycible ; null est ignoré. Sauf pour l’initialisation, passez un état déjà initialisé.head_xCoordonnée X de la tête, ramenée par rebouclage à la largeur du terrain.
head_yCoordonnée Y de la tête, ramenée par rebouclage à la hauteur du terrain.
headingOrientation de la tête dans le système à 16 secteurs.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Incluez chain.h et compilez chain.c exactement une fois. ChainBody contient la position et l’orientation courantes de chaque articulation. Ce type d’état est distinct de l’historique circulaire de positions Chain.
Fournissez trois tableaux distincts accessibles en écriture, x, y et heading, de capacity octets chacun. Conservez-les pendant l’utilisation du corps. L’indice zéro est la tête, comprise dans count. Ne modifiez pas les pointeurs, la capacité ou les dimensions du terrain après l’initialisation.
Les orientations suivent 16 secteurs horaires : 0=droite, 4=bas, 8=gauche, 12=haut. Seuls les quatre bits de poids faible sont utilisés. Les coordonnées d’écran augmentent vers la droite et le bas ; chaque dimension va de 1 à 256 pixels.
Utilise la position mise à jour du prédécesseur pour trouver le point d’attache cible, puis calcule le plus court déplacement avec rebouclage sur chaque axe. Un déplacement nul ne bouge pas ; une amplitude de 1 à 4 avance d’un pixel, 5 ou plus de deux. À exactement un demi-terrain, conserve le signe initial.
Transmet à l’articulation suivante l’orientation sauvegardée avant la mise à jour de chacune, pour propager la courbure dans le corps. Un corps vide reste inchangé.
L’appelant gère vitesse et accélération de la tête, collisions, dessin et attente. Mettez normalement la tête à jour d’abord, puis appelez chain_body_step une fois par pas de simulation. Il s’agit de suivi d’articulations, pas d’un solveur de corps rigides ou de contraintes de longueur exactes.
Exemple d’utilisation
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.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’image montre en haut un corps droit, au milieu une mise à jour après un virage vers le bas et en bas quatre mises à jour après ce virage. Les coordonnées sont dessinées au double de leur taille logique. La courbure se propage depuis la tête à droite vers l’arrière. CGB et FC utilisent rouge pour la tête, bleu pour le corps et vert pour la queue ; DMG utilise noir. Quatre mises à jour de stabilisation séparent la queue dupliquée après croissance. Ce sont trois vues des mêmes huit articulations, pas un corps de 24 articulations.


Commande de compilation
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-disasmImplémentation et source
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
Copie la position et l’orientation actuelles de la queue dans le prochain emplacement libre et augmente le nombre d’un.
Syntaxe
u8 chain_body_grow(ChainBody* body);Paramètres
bodyChainBodycible ; null est ignoré. Sauf pour l’initialisation, passez un état déjà initialisé.
Valeur renvoyée
Renvoie 1 si une articulation a été ajoutée ; 0 pour un corps vide, plein, désactivé ou nul.
Conditions et limites
Incluez chain.h et compilez chain.c exactement une fois. ChainBody contient la position et l’orientation courantes de chaque articulation. Ce type d’état est distinct de l’historique circulaire de positions Chain.
Fournissez trois tableaux distincts accessibles en écriture, x, y et heading, de capacity octets chacun. Conservez-les pendant l’utilisation du corps. L’indice zéro est la tête, comprise dans count. Ne modifiez pas les pointeurs, la capacité ou les dimensions du terrain après l’initialisation.
Les orientations suivent 16 secteurs horaires : 0=droite, 4=bas, 8=gauche, 12=haut. Seuls les quatre bits de poids faible sont utilisés. Les coordonnées d’écran augmentent vers la droite et le bas ; chaque dimension va de 1 à 256 pixels.
La nouvelle queue chevauche d’abord l’ancienne, puis s’en sépare lors des appels suivants à chain_body_step. La croissance seule ne déplace ni la tête ni les autres articulations.
Exemple d’utilisation
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.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’image montre en haut un corps droit, au milieu une mise à jour après un virage vers le bas et en bas quatre mises à jour après ce virage. Les coordonnées sont dessinées au double de leur taille logique. La courbure se propage depuis la tête à droite vers l’arrière. CGB et FC utilisent rouge pour la tête, bleu pour le corps et vert pour la queue ; DMG utilise noir. Quatre mises à jour de stabilisation séparent la queue dupliquée après croissance. Ce sont trois vues des mêmes huit articulations, pas un corps de 24 articulations.


Commande de compilation
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-disasmImplémentation et source
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
Met le nombre d’articulations à zéro en conservant les tableaux et les réglages du terrain.
Syntaxe
void chain_body_clear(ChainBody* body);Paramètres
bodyChainBodycible ; null est ignoré. Sauf pour l’initialisation, passez un état déjà initialisé.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Incluez chain.h et compilez chain.c exactement une fois. ChainBody contient la position et l’orientation courantes de chaque articulation. Ce type d’état est distinct de l’historique circulaire de positions Chain.
Fournissez trois tableaux distincts accessibles en écriture, x, y et heading, de capacity octets chacun. Conservez-les pendant l’utilisation du corps. L’indice zéro est la tête, comprise dans count. Ne modifiez pas les pointeurs, la capacité ou les dimensions du terrain après l’initialisation.
Les orientations suivent 16 secteurs horaires : 0=droite, 4=bas, 8=gauche, 12=haut. Seuls les quatre bits de poids faible sont utilisés. Les coordonnées d’écran augmentent vers la droite et le bas ; chaque dimension va de 1 à 256 pixels.
Les octets des tableaux ne sont pas effacés. Utilisez chain_body_reset pour recommencer ; appeler chain_body_grow juste après le vidage n’ajoute pas d’articulation.
Exemple d’utilisation
chain_body_clear(&body); // Forget the pose; the three arrays remain owned by us.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’image montre en haut un corps droit, au milieu une mise à jour après un virage vers le bas et en bas quatre mises à jour après ce virage. Les coordonnées sont dessinées au double de leur taille logique. La courbure se propage depuis la tête à droite vers l’arrière. CGB et FC utilisent rouge pour la tête, bleu pour le corps et vert pour la queue ; DMG utilise noir. Quatre mises à jour de stabilisation séparent la queue dupliquée après croissance. Ce sont trois vues des mêmes huit articulations, pas un corps de 24 articulations.


Commande de compilation
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-disasmImplémentation et source
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
Oublie l’historique enregistré pour réutiliser le même tableau de stockage.
Syntaxe
void chain_clear(Chain* chain);Paramètres
chainPointeur vers le
Chaininitialisé.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Remet le nombre d’éléments et head à zéro sans effacer ni libérer le tableau. L’appelant possède Chain et son tableau de points et doit les maintenir valides. Limitez la capacité à 128 pour éviter un débordement de l’addition des indices sur huit bits lors de la lecture.
La version GB exige un pointeur chain valide.
Exemple d’utilisation
chain_clear(&trail);result[11]=chain_get_count(&trail);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple vide un historique de quatre points et vérifie que son nombre d’éléments devient nul.


Commande de compilation
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=64kImplémentation et source
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
Lit le nombre de positions actuellement disponibles dans l’historique.
Syntaxe
u8 chain_get_count(const Chain* chain);Paramètres
chainPointeur vers le
Chaininitialisé.
Valeur renvoyée
Renvoie un nombre compris entre zéro et la capacité, ou zéro si la chaîne est nulle.
Conditions et limites
L’appelant possède à la fois Chain et son tableau de points, et doit les maintenir valides. Limitez la capacité à 128 pour éviter un débordement lors de l’addition des indices sur huit bits dans la fonction de lecture.
Exemple d’utilisation
result[4]=chain_get_count(&trail);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Après cinq insertions dans quatre emplacements, le nombre reste quatre. Il passe à zéro après effacement et reste nul pour un historique de capacité nulle.


Commande de compilation
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=64kImplémentation et source
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
Lit une position stockée en indiquant son ancienneté dans l’historique.
Syntaxe
u8 chain_get_segment(const Chain* chain, u8 index, ChainPoint* out);Paramètres
chainPointeur vers le
Chaininitialisé.indexAncienneté du point : 0 désigne le plus récent et
count - 1le plus ancien conservé.outObjet
ChainPointmodifiable et distinct pour recevoir le résultat ; un pointeur nul provoque un échec.
Valeur renvoyée
Renvoie 1 en cas de succès, ou 0 si la demande est invalide. Si out n’est pas nul, il est mis à (0,0) avant la validation.
Conditions et limites
out ne doit pas partager sa mémoire avec le tableau de stockage ou avec Chain : la remise à zéro de la sortie détruirait les données sources. L’appelant possède Chain et son tableau de points et doit les maintenir valides. Limitez la capacité à 128 pour éviter un débordement de l’addition des indices sur huit bits lors de la lecture.
Exemple d’utilisation
result[1]=chain_get_segment(&trail,0,&point);result[2]=point.x;result[3]=point.y;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’indice 0 lit le point le plus récent (40,24), l’indice 3 le plus ancien (16,8), et l’indice invalide 4 renvoie un échec avec une sortie (0,0).


Commande de compilation
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=64kImplémentation et source
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
Associe une zone de stockage à un historique circulaire de positions, initialement vide.
Syntaxe
void chain_init(Chain* chain, ChainPoint* storage, u8 capacity);Paramètres
chainObjet
Chainmodifiable à initialiser.storageTableau pouvant contenir
capacityélémentsChainPoint.capacityNombre d’emplacements de points. Utilisez 1 à 128 pour un historique exploitable ; zéro désactive l’enregistrement.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
L’appelant possède à la fois Chain et son tableau de points, et doit les maintenir valides. Limitez la capacité à 128 pour éviter un débordement lors de l’addition des indices sur huit bits dans la fonction de lecture.
La version GB exige un pointeur chain valide.
Exemple d’utilisation
chain_init(&trail,storage,4);result[0]=chain_get_count(&trail);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple associe quatre emplacements de points et vérifie que le nombre initial est nul.


Commande de compilation
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=64kImplémentation et source
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
Ajoute la position la plus récente en tête de l’historique et remplace le point le plus ancien lorsque le tableau est plein.
Syntaxe
void chain_push_head(Chain* chain, s16 x, s16 y);Paramètres
chainPointeur vers le
Chaininitialisé.xCoordonnée X signée du nouveau point.
yCoordonnée Y signée du nouveau point.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Un pointeur de chaîne nul ou une capacité nulle ne produit aucun effet. L’appelant possède Chain et son tableau de points et doit les maintenir valides. Limitez la capacité à 128 pour éviter un débordement de l’addition des indices sur huit bits lors de la lecture.
Exemple d’utilisation
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);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Après cinq insertions dans quatre emplacements, (40,24) est le point le plus récent et (16,8) le plus ancien conservé ; le point initial (8,8) a été remplacé.


Commande de compilation
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=64kImplémentation et source
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 — Réserves de projectiles, éventails, impacts et frôlements
Champ de projectiles sans allocation dynamique, jusqu’à 96 tirs sur 160×128 pixels. Offre déplacement au seizième de pixel, éventails à 32 directions, touches/frôlements et composition de tuiles à quatre quadrants. La simulation fonctionne sur GB ; le transfert present_now est réservé au CGB.
danmaku_clear
Désactive tous les projectiles et efface le nombre actif, les événements courants de touche/frôlement et le curseur d’allocation.
Syntaxe
void danmaku_clear();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Conserve les compteurs de pic et cumulés. Effacez puis transférez la carte RAM pour retirer les projectiles de l’écran.
Exemple d’utilisation
danmaku_clear();result[6]=dm_count;result[7]=dm_spawned;result[8]=dm_peak;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exemple de dessin réservé au CGB. Créez huit directions en (80,64), avancez huit fois et affichez huit points rouges de 3×3 disposés en étoile. Les projectiles cardinaux parcourent 32 pixels ; les diagonales utilisent une approximation entière. Vérifiez aussi le vidage du pool et la conservation des créations cumulées.

Commande de compilation
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=noneImplémentation et source
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
Efface les 576 octets de la carte de tuiles RAM de 32×18.
Syntaxe
void danmaku_clear_map();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Laisse inchangés l’état des projectiles et la VRAM. À chaque trame, appelez clear_map, écrivez les décors, exécutez step puis transférez.
Exemple d’utilisation
danmaku_clear_map();result[11]=dm_map[0];Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exemple de dessin réservé au CGB. Créez huit directions en (80,64), avancez huit fois et affichez huit points rouges de 3×3 disposés en étoile. Les projectiles cardinaux parcourent 32 pixels ; les diagonales utilisent une approximation entière. Vérifiez aussi le vidage du pool et la conservation des créations cumulées.

Commande de compilation
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=noneImplémentation et source
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
Génère un éventail à partir d’une table de vitesses à 32 directions et d’un pas angulaire fixe.
Syntaxe
void danmaku_fan(u8 x, u8 y, u8 direction, u8 step, u8 count, u8 speed);Paramètres
xX initial en pixels, de 0 à 159.
yY initial en pixels, de 0 à 127.
directionAngle initial, masqué sur cinq bits : 0=droite, 8=bas, 16=gauche, 24=haut.
stepIncrément d’angle par projectile, avec rebouclage sur 32 directions.
countNombre de tentatives, limité à 96.
speedVitesse en seizièmes de pixel, limitée à 64, soit quatre pixels par mise à jour.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Continue les tentatives de création restantes même si le pool est plein. Les valeurs entières des tables sin/cos introduisent des arrondis dans le mouvement diagonal.
Exemple d’utilisation
danmaku_fan(80,64,0,4,8,64);result[9]=dm_count;result[10]=dm_spawned;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exemple de dessin réservé au CGB. Créez huit directions en (80,64), avancez huit fois et affichez huit points rouges de 3×3 disposés en étoile. Les projectiles cardinaux parcourent 32 pixels ; les diagonales utilisent une approximation entière. Vérifiez aussi le vidage du pool et la conservation des créations cumulées.

Commande de compilation
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=noneImplémentation et source
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
Transfère de manière synchrone les 576 octets de dm_map vers la carte de fond $9800 par GDMA CGB.
Syntaxe
void danmaku_present_now();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
CGB uniquement ; ne l’appelez pas sur DMG. Utilisez-la LCD éteint ou au début de VBlank. Sélectionne la banque VRAM zéro sans restaurer l’ancien VBK. L’application fournit les graphismes de projectiles dans les tuiles 0..15.
Exemple d’utilisation
// CGB general DMA; the LCD is stopped for this complete-map upload.
danmaku_present_now();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exemple de dessin réservé au CGB. Créez huit directions en (80,64), avancez huit fois et affichez huit points rouges de 3×3 disposés en étoile. Les projectiles cardinaux parcourent 32 pixels ; les diagonales utilisent une approximation entière. Vérifiez aussi le vidage du pool et la conservation des créations cumulées.

Commande de compilation
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=noneImplémentation et source
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
Vide le pool de 96 projectiles et réinitialise les compteurs de pic, de créations cumulées et de refus pour pool plein.
Syntaxe
void danmaku_reset();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Laisse inchangés les coordonnées du joueur, l’invulnérabilité et la carte de tuiles en RAM ; réglez-les séparément au début du jeu.
Exemple d’utilisation
danmaku_reset();result[0]=dm_count;result[1]=dm_peak;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exemple de dessin réservé au CGB. Créez huit directions en (80,64), avancez huit fois et affichez huit points rouges de 3×3 disposés en étoile. Les projectiles cardinaux parcourent 32 pixels ; les diagonales utilisent une approximation entière. Vérifiez aussi le vidage du pool et la conservation des créations cumulées.

Commande de compilation
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=noneImplémentation et source
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
Recherche cycliquement un emplacement libre et crée un projectile à la position et à la vitesse demandées.
Syntaxe
u8 danmaku_spawn(u8 x, u8 y, s8 vx, s8 vy);Paramètres
xX initial en pixels, de 0 à 159.
yY initial en pixels, de 0 à 127.
vxVitesse Q4.4 signée de −128 à 127 ; 16 déplace d’un pixel vers la droite par mise à jour.
vyVitesse Q4.4 signée ; une valeur positive déplace vers le bas.
Valeur renvoyée
Renvoie 1 après allocation, 0 pour des coordonnées extérieures ou un pool plein. Les demandes extérieures n’incrémentent pas dm_rejected.
Conditions et limites
Les positions sont stockées en seizièmes de pixel. Les totaux u16 de créations/refus rebouclent après 65535. Aucune allocation dynamique n’est utilisée.
Exemple d’utilisation
result[2]=danmaku_spawn(40,40,16,0);result[3]=danmaku_spawn(160,40,0,0);result[4]=dm_count;result[5]=dm_rejected;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exemple de dessin réservé au CGB. Créez huit directions en (80,64), avancez huit fois et affichez huit points rouges de 3×3 disposés en étoile. Les projectiles cardinaux parcourent 32 pixels ; les diagonales utilisent une approximation entière. Vérifiez aussi le vidage du pool et la conservation des créations cumulées.

Commande de compilation
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=noneImplémentation et source
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
Avance chaque projectile une fois, retire ceux hors limites, compose les tuiles de projectiles et détecte touches et frôlements.
Syntaxe
void danmaku_step();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Les centres dessinés sont alignés sur une grille de quatre pixels. Des écarts d’au plus huit sur chaque axe donnent un premier frôlement ; d’au plus trois, une touche. L’invulnérabilité supprime seulement les touches. dm_hit/dm_graze sont remis à zéro à chaque appel ; chaque projectile ne frôle qu’une fois. Les ID de tuile 0..15 codent les quatre bits de quadrant ; les tuiles de décor occupées d’ID 16 ou plus sont remplacées.
Exemple d’utilisation
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;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exemple de dessin réservé au CGB. Créez huit directions en (80,64), avancez huit fois et affichez huit points rouges de 3×3 disposés en étoile. Les projectiles cardinaux parcourent 32 pixels ; les diagonales utilisent une approximation entière. Vérifiez aussi le vidage du pool et la conservation des créations cumulées.

Commande de compilation
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=noneImplémentation et source
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 — Enregistrements en RAM et assertions
Enregistre des noms, des valeurs et des repères de trame dans un journal RAM de capacité fixe. Les assertions conservent les informations de diagnostic sans interrompre l’exécution.
debug_assert_fail
Conserve un code d’échec d’assertion et tente d’ajouter une entrée ASSERT.
Syntaxe
void debug_assert_fail(u16 code);Paramètres
codeIdentifiant d’erreur sur 16 bits à conserver.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
L’exécution continue. Le dernier code d’assertion est mis à jour même si le journal est plein. Le journal contient par défaut 32 entrées et abandonne les nouvelles lorsqu’il est plein. Si vous redéfinissez DEBUG_TRACE_MAX, utilisez partout la même valeur, entre 1 et 255, dans chaque unité de traduction. Les noms sont conservés sous forme de pointeurs, sans copie ; leur mémoire doit rester lisible jusqu’à la fin de l’inspection. Vous devez coordonner vous-même les écritures du code principal et des interruptions.
Exemple d’utilisation
debug_assert_fail(42);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple enregistre le code 42, remplit le journal, puis enregistre le code 999. Le nombre d’entrées reste 32, mais le dernier code devient 999.


Commande de compilation
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=64kImplémentation et source
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
Lit le dernier code d’assertion, indépendamment de la place disponible dans le journal.
Syntaxe
u16 debug_get_last_assert();Valeur renvoyée
Renvoie le dernier code sur 16 bits ; sa valeur initiale après initialisation est zéro.
Conditions et limites
Zéro est aussi la valeur initiale : il ne permet pas de distinguer un échec enregistré avec le code zéro. La lecture n’efface pas le code.
Exemple d’utilisation
result[22]=debug_get_last_assert();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple vérifie 77 après la macro d’assertion, 999 une fois le journal plein et zéro après réinitialisation.


Commande de compilation
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=64kImplémentation et source
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
Lit le nombre d’entrées valides dans le tableau de trace.
Syntaxe
u8 debug_get_trace_count();Valeur renvoyée
Renvoie un nombre compris entre zéro et DEBUG_TRACE_MAX.
Conditions et limites
Le journal contient par défaut 32 entrées et abandonne les nouvelles lorsqu’il est plein. Si vous redéfinissez DEBUG_TRACE_MAX, utilisez partout la même valeur, entre 1 et 255, dans chaque unité de traduction. Les noms sont conservés sous forme de pointeurs, sans copie ; leur mémoire doit rester lisible jusqu’à la fin de l’inspection. Vous devez coordonner vous-même les écritures du code principal et des interruptions.
Exemple d’utilisation
result[1]=debug_get_trace_count();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple vérifie les dix premières entrées, puis la limite de 32 après d’autres écritures. Le compteur ne revient pas à zéro lorsque le journal est plein.


Commande de compilation
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=64kImplémentation et source
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
Fournit une référence au tableau interne pour examiner les noms, valeurs et numéros de trame enregistrés.
Syntaxe
const DebugTraceEntry* debug_get_trace_log();Valeur renvoyée
Renvoie un pointeur en lecture seule vers le tableau interne DebugTraceEntry.
Conditions et limites
Il ne s’agit pas d’une copie. Ne lisez que le nombre d’entrées indiqué par debug_get_trace_count(). Les anciens octets restants après initialisation ne sont pas des enregistrements valides. Le journal contient par défaut 32 entrées et abandonne les nouvelles lorsqu’il est plein. Si vous redéfinissez DEBUG_TRACE_MAX, utilisez partout la même valeur, entre 1 et 255, dans chaque unité de traduction. Les noms sont conservés sous forme de pointeurs, sans copie ; leur mémoire doit rester lisible jusqu’à la fin de l’inspection. Vous devez coordonner vous-même les écritures du code principal et des interruptions.
Exemple d’utilisation
entries=debug_get_trace_log();for(i=0;i<10;i++){result[2+i]=entries[i].value;result[12+i]=entries[i].frame;}Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple lit les dix champs de valeur et de trame, et vérifie le B initial du libellé BEGIN.


Commande de compilation
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=64kImplémentation et source
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
Initialise la longueur valide du journal, le numéro de trame associé et le dernier code d’assertion.
Syntaxe
void debug_init();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Les octets des entrées existantes ne sont pas effacés. Appelez cette fonction avant d’enregistrer la première entrée. Le journal contient par défaut 32 entrées et abandonne les nouvelles lorsqu’il est plein. Si vous redéfinissez DEBUG_TRACE_MAX, utilisez partout la même valeur, entre 1 et 255, dans chaque unité de traduction. Les noms sont conservés sous forme de pointeurs, sans copie ; leur mémoire doit rester lisible jusqu’à la fin de l’inspection. Vous devez coordonner vous-même les écritures du code principal et des interruptions.
Exemple d’utilisation
debug_init();result[0]=debug_get_trace_count();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple vérifie que le nombre initial est nul, puis réinitialise un journal rempli. Il contrôle que le nombre d’entrées et le code d’assertion sont effacés, alors que les anciennes valeurs du tableau subsistent.


Commande de compilation
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=64kImplémentation et source
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
Enregistre un marqueur de trame nommé pour repérer une étape du traitement.
Syntaxe
void debug_mark_frame(const u8* label);Paramètres
labelLibellé terminé par zéro, dans une mémoire qui doit rester lisible jusqu’à l’inspection.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Le journal contient par défaut 32 entrées et abandonne les nouvelles lorsqu’il est plein. Si vous redéfinissez DEBUG_TRACE_MAX, utilisez partout la même valeur, entre 1 et 255, dans chaque unité de traduction. Les noms sont conservés sous forme de pointeurs, sans copie ; leur mémoire doit rester lisible jusqu’à la fin de l’inspection. Vous devez coordonner vous-même les écritures du code principal et des interruptions.
Exemple d’utilisation
debug_mark_frame("BEGIN");Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’ajout du marqueur BEGIN enregistre la valeur 65535 (0xFFFF) avec le numéro de trame 513.


Commande de compilation
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=64kImplémentation et source
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
Définit le numéro de trame qui sera copié dans les entrées suivantes du journal.
Syntaxe
void debug_set_frame(u16 frame);Paramètres
frameNuméro de trame sur 16 bits pour les entrées suivantes.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Cette fonction n’attend pas de trame et n’incrémente pas automatiquement le numéro. Passez explicitement le compteur de trames du jeu. Le journal contient par défaut 32 entrées et abandonne les nouvelles lorsqu’il est plein. Si vous redéfinissez DEBUG_TRACE_MAX, utilisez partout la même valeur, entre 1 et 255, dans chaque unité de traduction. Les noms sont conservés sous forme de pointeurs, sans copie ; leur mémoire doit rester lisible jusqu’à la fin de l’inspection. Vous devez coordonner vous-même les écritures du code principal et des interruptions.
Exemple d’utilisation
debug_set_frame(513);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple définit 513, écrit dix entrées, puis relit leurs dix champs de trame pour vérifier ce numéro.


Commande de compilation
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=64kImplémentation et source
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
Enregistre un score ou un compteur sur 16 bits avec son nom.
Syntaxe
void debug_trace_u16(const u8* name, u16 value);Paramètres
nameLibellé terminé par zéro, dans une mémoire qui doit rester lisible jusqu’à l’inspection.
valueValeur de 0 à 65535 à enregistrer.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Le journal contient par défaut 32 entrées et abandonne les nouvelles lorsqu’il est plein. Si vous redéfinissez DEBUG_TRACE_MAX, utilisez partout la même valeur, entre 1 et 255, dans chaque unité de traduction. Les noms sont conservés sous forme de pointeurs, sans copie ; leur mémoire doit rester lisible jusqu’à la fin de l’inspection. Vous devez coordonner vous-même les écritures du code principal et des interruptions.
Exemple d’utilisation
debug_trace_u16("WORD",4660);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’entrée WORD stocke 4660 (0x1234), puis l’exemple la relit pour vérifier les deux octets.


Commande de compilation
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=64kImplémentation et source
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
Enregistre une valeur d’état sur huit bits avec son nom et le numéro de trame courant.
Syntaxe
void debug_trace_u8(const u8* name, u8 value);Paramètres
nameLibellé terminé par zéro, dans une mémoire qui doit rester lisible jusqu’à l’inspection.
valueValeur de 0 à 255, étendue par des zéros dans le champ de 16 bits du journal.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Le journal contient par défaut 32 entrées et abandonne les nouvelles lorsqu’il est plein. Si vous redéfinissez DEBUG_TRACE_MAX, utilisez partout la même valeur, entre 1 et 255, dans chaque unité de traduction. Les noms sont conservés sous forme de pointeurs, sans copie ; leur mémoire doit rester lisible jusqu’à la fin de l’inspection. Vous devez coordonner vous-même les écritures du code principal et des interruptions.
Exemple d’utilisation
debug_trace_u8("BYTE",255);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’entrée BYTE enregistre 255 et vérifie que le champ de valeur sur 16 bits du journal contient bien 255.


Commande de compilation
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=64kImplémentation et source
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
Macro utilisable comme une instruction, qui enregistre le code d’assertion 1 si sa condition est fausse.
Syntaxe
#define KITAQGB_ASSERT(cond) do { if (!(cond)) debug_assert_fail((u16)1); } while (0)Paramètres
condCondition qui doit être vraie ; zéro signifie un échec.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
La condition est évaluée une seule fois. Si elle est vraie, rien n’est enregistré ; sinon, l’échec est consigné sans arrêter l’exécution. La forme do…while (0) permet d’utiliser la macro comme une seule instruction dans un if…else.
Exemple d’utilisation
KITAQGB_ASSERT(1);KITAQGB_ASSERT(0);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Une assertion vraie et une assertion fausse produisent exactement une entrée de code 1.


Commande de compilation
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=64kImplémentation et source
kitaqgb/lib/debug.h:45
#define KITAQGB_ASSERT(cond) do { if (!(cond)) debug_assert_fail((u16)1); } while (0)KITAQGB_ASSERT_CODE
Enregistre le code d’assertion choisi uniquement si la condition est fausse.
Syntaxe
#define KITAQGB_ASSERT_CODE(cond, code) do { if (!(cond)) debug_assert_fail((u16)(code)); } while (0)Paramètres
condCondition censée être vraie.
codeExpression du code, évaluée en cas d’échec et convertie sur 16 bits.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
La condition est évaluée une seule fois ; l’expression du code ne l’est qu’en cas d’échec. L’exécution continue après l’enregistrement.
Exemple d’utilisation
KITAQGB_ASSERT_CODE(1,++side_effect);KITAQGB_ASSERT_CODE(0,77);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Si la condition est vraie, l’expression de code ++side_effect n’est pas évaluée et la variable reste à zéro. Une condition fausse enregistre le code 77.


Commande de compilation
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=64kImplémentation et source
kitaqgb/lib/debug.h:46
#define KITAQGB_ASSERT_CODE(cond, code) do { if (!(cond)) debug_assert_fail((u16)(code)); } while (0)KITAQGB_MARK_FRAME
Convertit un libellé en pointeur de chaîne et ajoute un marqueur de trame de valeur 0xFFFF.
Syntaxe
#define KITAQGB_MARK_FRAME(label) debug_mark_frame((const u8*)(label))Paramètres
labelLibellé terminé par zéro, dans une mémoire qui doit rester lisible jusqu’à l’inspection.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Le journal contient par défaut 32 entrées et abandonne les nouvelles lorsqu’il est plein. Si vous redéfinissez DEBUG_TRACE_MAX, utilisez partout la même valeur, entre 1 et 255, dans chaque unité de traduction. Les noms sont conservés sous forme de pointeurs, sans copie ; leur mémoire doit rester lisible jusqu’à la fin de l’inspection. Vous devez coordonner vous-même les écritures du code principal et des interruptions.
Exemple d’utilisation
KITAQGB_MARK_FRAME("END");Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le marqueur END est vérifié avec la valeur 65535 et le numéro de trame 513.


Commande de compilation
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=64kImplémentation et source
kitaqgb/lib/debug.h:44
#define KITAQGB_MARK_FRAME(label) debug_mark_frame((const u8*)(label))KITAQGB_TRACE
Convertit explicitement une valeur sur 16 bits, puis l’enregistre avec son nom.
Syntaxe
#define KITAQGB_TRACE(name, value) debug_trace_u16((const u8*)(name), (u16)(value))Paramètres
nameLibellé terminé par zéro, dans une mémoire qui doit rester lisible jusqu’à l’inspection.
valueExpression convertie sur 16 bits avant enregistrement.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
La macro reste toujours active ; les paramètres de compilation ne la désactivent pas automatiquement. Elle enregistre les valeurs sur 16 bits comme KITAQGB_TRACE_U16. Le journal contient par défaut 32 entrées et abandonne les nouvelles lorsqu’il est plein. Si vous redéfinissez DEBUG_TRACE_MAX, utilisez partout la même valeur, entre 1 et 255, dans chaque unité de traduction. Les noms sont conservés sous forme de pointeurs, sans copie ; leur mémoire doit rester lisible jusqu’à la fin de l’inspection. Vous devez coordonner vous-même les écritures du code principal et des interruptions.
Exemple d’utilisation
KITAQGB_TRACE("SCORE",600);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple enregistre 600, puis relit cette valeur dans le journal pour la vérifier.


Commande de compilation
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=64kImplémentation et source
kitaqgb/lib/debug.h:43
#define KITAQGB_TRACE(name, value) debug_trace_u16((const u8*)(name), (u16)(value))KITAQGB_TRACE_U16
Convertit explicitement une valeur sur 16 bits, puis l’enregistre avec son nom.
Syntaxe
#define KITAQGB_TRACE_U16(name, value) debug_trace_u16((const u8*)(name), (u16)(value))Paramètres
nameLibellé terminé par zéro, dans une mémoire qui doit rester lisible jusqu’à l’inspection.
valueExpression convertie sur 16 bits avant enregistrement.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
La macro reste toujours active ; les paramètres de compilation ne la désactivent pas automatiquement. Le journal contient par défaut 32 entrées et abandonne les nouvelles lorsqu’il est plein. Si vous redéfinissez DEBUG_TRACE_MAX, utilisez partout la même valeur, entre 1 et 255, dans chaque unité de traduction. Les noms sont conservés sous forme de pointeurs, sans copie ; leur mémoire doit rester lisible jusqu’à la fin de l’inspection. Vous devez coordonner vous-même les écritures du code principal et des interruptions.
Exemple d’utilisation
KITAQGB_TRACE_U16("WORD2",500);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple enregistre 500, puis relit cette valeur dans le journal pour la vérifier.


Commande de compilation
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=64kImplémentation et source
kitaqgb/lib/debug.h:42
#define KITAQGB_TRACE_U16(name, value) debug_trace_u16((const u8*)(name), (u16)(value))KITAQGB_TRACE_U8
Convertit explicitement une valeur sur huit bits, puis l’enregistre avec son nom.
Syntaxe
#define KITAQGB_TRACE_U8(name, value) debug_trace_u8((const u8*)(name), (u8)(value))Paramètres
nameLibellé terminé par zéro, dans une mémoire qui doit rester lisible jusqu’à l’inspection.
valueExpression convertie sur huit bits avant enregistrement.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
La macro reste toujours active ; les paramètres de compilation ne la désactivent pas automatiquement. Le journal contient par défaut 32 entrées et abandonne les nouvelles lorsqu’il est plein. Si vous redéfinissez DEBUG_TRACE_MAX, utilisez partout la même valeur, entre 1 et 255, dans chaque unité de traduction. Les noms sont conservés sous forme de pointeurs, sans copie ; leur mémoire doit rester lisible jusqu’à la fin de l’inspection. Vous devez coordonner vous-même les écritures du code principal et des interruptions.
Exemple d’utilisation
KITAQGB_TRACE_U8("CAST",0x1234);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple enregistre 52. Seul l’octet de poids faible 0x34 de 0x1234 est conservé.


Commande de compilation
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=64kImplémentation et source
kitaqgb/lib/debug.h:41
#define KITAQGB_TRACE_U8(name, value) debug_trace_u8((const u8*)(name), (u8)(value))dmg3d.h — Rendu filaire monochrome de 128×120 pour DMG
Dessin de lignes 3D monochromes. Fournissez sommets, arêtes et faces du modèle, ainsi que position, rotation et échelle de l’objet. Suivez l’ordre initialisation, début d’image, dessin, transfert. La physique est séparée. Les angles ont seize pas par tour ; l’échelle de modèle 256 vaut l’unité.
Vec3 contient x/y/z, Edge les indices de sommets a/b, et Face les indices de triangle a/b/c. Les champs vertices, edges et faces de Model pointent vers ces tableaux ; chaque compteur en donne la longueur. edge_faces contient les indices des faces adjacentes f0/f1, avec FACE_NONE pour une face absente. MODEL_HIDDEN_LINES dans flags demande une sélection d’arêtes fondée sur les faces. L’aire projetée signée détermine l’orientation d’une face : l’ordre des sommets compte.
Object mémorise une référence au modèle, la position x/y/z, les angles rx/ry/rz, scale_q8 et visible. Les objets peuvent partager un modèle, mais le dessin ne copie pas les tables et ne change pas automatiquement leurs banques ROM. Gardez les données référencées lisibles pendant tout le dessin. L’Object CGB possède aussi un indice de couleur.
DMG3D_BeginFrame
Commence le dessin d’une image et désactive le test d’occlusion.
Syntaxe
void DMG3D_BeginFrame();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 120. Désactive uniquement le filtrage d’occlusion. La zone de préparation est normalement effacée pendant le transfert ; Init fournit la première zone vierge. Ne supprime pas une image non soumise, n’efface pas le masque et ne réinitialise ni écritures BG en attente ni indicateurs de modification.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.


Commande de compilation
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-disasmImplémentation et source
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
Dessine un modèle de lignes à échelle entière à partir de sommets et de paires d’indices d’arêtes sur deux octets.
Syntaxe
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);Paramètres
verticesTableau de sommets 3D.
vertex_countNombre d’entrées du tableau de sommets.
edgesIndices des sommets de chaque arête, dans le format déclaré de structure ou de paire d’octets.
edge_countNombre d’arêtes.
xComposante X du point ou de l’origine de l’objet en coordonnées du monde.
yComposante Y du point ou de l’origine de l’objet en coordonnées du monde.
zComposante Z du point ou de l’origine de l’objet en coordonnées du monde.
scaleÉchelle entière ; zéro est traité comme un.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 120. Trace les arêtes indexées par paires d’octets après mise à l’échelle entière et translation ; l’échelle zéro signifie un, sans rotation d’objet ni filtrage de faces. Projette au plus 24 sommets. Fournissez au plus 128 paires d’arêtes, car les décalages sur octets bouclent après 255. Ignore les ID de sommets invalides, les extrémités rejetées en profondeur et les tableaux null. Produits et sommes de coordonnées doivent tenir dans s16.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Une ligne horizontale projetée et un bloc auxiliaire de 8×8 illustrent les transferts directs ; un octet source passe de 255 à 0 lorsqu’il est consommé.


Commande de compilation
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-disasmImplémentation et source
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
Trace dans la zone de préparation une ligne en coordonnées écran à connexité 4, extrémités incluses.
Syntaxe
void DMG3D_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by);Paramètres
axCoordonnée X du sommet A en pixels du viewport.
ayCoordonnée Y du sommet A en pixels du viewport.
bxCoordonnée X du sommet B en pixels du viewport.
byCoordonnée Y du sommet B en pixels du viewport.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 120. Si le transfert des zones modifiées est actif, marque le rectangle englobant en tuiles, puis trace une ligne connexe préparée. Le dessin de scène peut la rejeter avec cinq échantillons du masque. Fournissez des extrémités dans le viewport 128×120 ; les contrôles de pixels bas niveau ne découpent pas géométriquement le segment.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.


Commande de compilation
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-disasmImplémentation et source
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
Projette deux extrémités du monde et trace une ligne entre elles.
Syntaxe
void DMG3D_DrawLine3D(w3ddmg_i16 ax, w3ddmg_i16 ay, w3ddmg_i16 az, w3ddmg_i16 bx, w3ddmg_i16 by, w3ddmg_i16 bz);Paramètres
axComposante X du point de départ en coordonnées du monde.
ayComposante Y du point de départ en coordonnées du monde.
azComposante Z du point de départ en coordonnées du monde.
bxComposante X du point d’arrivée en coordonnées du monde.
byComposante Y du point d’arrivée en coordonnées du monde.
bzComposante Z du point d’arrivée en coordonnées du monde.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 120. Projette les deux extrémités du monde et dessine uniquement si les deux passent la plage de profondeur. Ne calcule pas l’intersection d’un segment traversant avec les plans proche ou lointain ; chaque extrémité projetée est bornée indépendamment aux bords de l’écran.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.


Commande de compilation
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-disasmImplémentation et source
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
Dessine un modèle de sommets et d’arêtes à la position et avec la rotation demandées, à l’échelle unitaire.
Syntaxe
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);Paramètres
modelModèle contenant les tableaux de sommets, d’arêtes et de faces, ainsi que leurs nombres ; ses tables doivent rester lisibles pendant l’appel.
xComposante X du point ou de l’origine de l’objet en coordonnées du monde.
yComposante Y du point ou de l’origine de l’objet en coordonnées du monde.
zComposante Z du point ou de l’origine de l’objet en coordonnées du monde.
rxRotation autour de X ; seize pas font un tour complet.
ryRotation autour de Y ; seize pas font un tour complet.
rzRotation autour de Z ; seize pas font un tour complet.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 120. Dessine un modèle sans redimensionnement en appelant DrawModelScaled avec l’échelle 256.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Des modèles à l’échelle unitaire et à demi-échelle apparaissent au-dessus d’une scène issue d’un tableau d’objets aux mêmes échelles, illustrant projection et redimensionnement.


Commande de compilation
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-disasmImplémentation et source
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
Redimensionne un modèle, le tourne dans l’ordre Y/X/Z, translate et projette ses sommets, puis trace ses arêtes.
Syntaxe
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);Paramètres
modelModèle contenant les tableaux de sommets, d’arêtes et de faces, ainsi que leurs nombres ; ses tables doivent rester lisibles pendant l’appel.
xComposante X du point ou de l’origine de l’objet en coordonnées du monde.
yComposante Y du point ou de l’origine de l’objet en coordonnées du monde.
zComposante Z du point ou de l’origine de l’objet en coordonnées du monde.
rxRotation autour de X ; seize pas font un tour complet.
ryRotation autour de Y ; seize pas font un tour complet.
rzRotation autour de Z ; seize pas font un tour complet.
scale_q8Échelle dont l’unité vaut 256 ; les valeurs nulles ou négatives signifient aussi l’unité.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 120. Redimensionne au plus 24 sommets, les tourne Y/X/Z, les translate et les projette, puis parcourt les edge_count entrées, compteur sur un octet, avec filtrage facultatif par faces adjacentes. Le tampon de faces est limité à 16 ; les tables d’arêtes doivent contenir toutes les entrées déclarées. Une échelle non positive signifie 256. Les pointeurs de modèle, sommets ou arêtes nuls sont ignorés. Gardez produits et translations sur 16 bits signés ; les arêtes traversant une limite de profondeur sont rejetées.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Des modèles à l’échelle unitaire et à demi-échelle apparaissent au-dessus d’une scène issue d’un tableau d’objets aux mêmes échelles, illustrant projection et redimensionnement.


Commande de compilation
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-disasmImplémentation et source
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
Dessine au plus huit objets du plus proche au plus lointain, les faces proches masquant les arêtes suivantes.
Syntaxe
void DMG3D_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count);Paramètres
objectsTableau d’objets contenant positions, rotations, échelles et indicateurs de visibilité.
countNombre d’entrées fournies ; consultez la limite de traitement propre à l’opération.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 120. Trie au plus huit origines d’objets selon leur profondeur caméra, du plus proche au plus lointain. Dessine les modèles visibles et valides et marque les rectangles englobants des faces avant pour les objets suivants. La première place triée évite les tests de masque ; la dernière n’ajoute pas d’occultant. C’est un rejet grossier de lignes, pas un tampon de profondeur. Ignore null et les entrées vides ; données de l’appelant et cache de projection courant doivent rester valides pendant le parcours.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Des modèles à l’échelle unitaire et à demi-échelle apparaissent au-dessus d’une scène issue d’un tableau d’objets aux mêmes échelles, illustrant projection et redimensionnement.


Commande de compilation
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-disasmImplémentation et source
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
Soumet à la VRAM les écritures du fond en attente et le dessin préparé.
Syntaxe
void DMG3D_EndFrame();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 120. Attend le prochain VBlank et applique les écritures BG, puis consomme éventuellement les bandes auxiliaires avant de transférer les tuiles modifiées ou toute la zone principale. Le recouvrement des sources auxiliaire et principale rend cet ordre important. L’interrogation de STAT continue à travers les fenêtres d’accès ; la mise à jour peut dépasser un seul VBlank.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.


Commande de compilation
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-disasmImplémentation et source
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
Projette les triangles avant du modèle et efface les pixels préparés à l’intérieur.
Syntaxe
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);Paramètres
modelModèle contenant les tableaux de sommets, d’arêtes et de faces, ainsi que leurs nombres ; ses tables doivent rester lisibles pendant l’appel.
xComposante X du point ou de l’origine de l’objet en coordonnées du monde.
yComposante Y du point ou de l’origine de l’objet en coordonnées du monde.
zComposante Z du point ou de l’origine de l’objet en coordonnées du monde.
rxRotation autour de X ; seize pas font un tour complet.
ryRotation autour de Y ; seize pas font un tour complet.
rzRotation autour de Z ; seize pas font un tour complet.
scale_q8Échelle dont l’unité vaut 256 ; les valeurs nulles ou négatives signifient aussi l’unité.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 120. Projette au plus 24 sommets et efface l’intérieur des triangles avant dans la zone de préparation, pour un modèle doté d’indicateurs de lignes cachées et de données de faces. Une échelle non positive signifie 256, soit l’unité. Examine au plus 16 faces ; celles traversant une limite de profondeur sont ignorées. Remplace aussi les caches de projection partagés, sans mettre à jour la VRAM.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Les faces projetées effacent une région remplie, rendant visibles les zones conservées et effacées.


Commande de compilation
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-disasmImplémentation et source
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
Efface un segment horizontal, bornes incluses, sur une ligne préparée.
Syntaxe
void DMG3D_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1);Paramètres
yCoordonnée Y en pixels de la ligne à effacer.
x0Borne X inférieure, en pixels du viewport ; l’ordre et le découpage suivent les notes de cette opération.
x1Borne X supérieure, en pixels du viewport ; l’ordre et le découpage suivent les notes de cette opération.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 120. Ordonne les extrémités X et efface le segment préparé, bornes incluses. Les deux extrémités doivent être dans 0..127 ; un Y invalide est ignoré. La routine ne découpe pas X à votre place.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.


Commande de compilation
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-disasmImplémentation et source
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
Efface un triangle en coordonnées écran dans la zone de préparation, par segments horizontaux de lignes de balayage.
Syntaxe
void DMG3D_EraseTriangle2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by, w3ddmg_u8 cx, w3ddmg_u8 cy);Paramètres
axCoordonnée X du sommet A en pixels du viewport.
ayCoordonnée Y du sommet A en pixels du viewport.
bxCoordonnée X du sommet B en pixels du viewport.
byCoordonnée Y du sommet B en pixels du viewport.
cxCoordonnée X du sommet C en pixels du viewport.
cyCoordonnée Y du sommet C en pixels du viewport.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 120. Efface un triangle dans les pixels préparés à l’aide d’intersections entières avec les lignes de balayage. Fournissez des coordonnées du viewport. Les triangles dégénérés sont ignorés ; masque d’occlusion et VRAM restent inchangés.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Les faces projetées effacent une région remplie, rendant visibles les zones conservées et effacées.


Commande de compilation
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-disasmImplémentation et source
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
Initialise le LCD, les tuiles et la carte du fond pour un viewport filaire monochrome.
Syntaxe
void DMG3D_Init();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 120. Prend le contrôle du LCD, efface la VRAM des tuiles et la carte BG, puis installe un viewport de 16×15 à partir de la tuile (3,1). Règle le défilement à (8,0), BGP à 0xB4 et active le fond. Réinitialise caméra, files, modes de transfert, les deux tables de modifications et la zone de préparation. Réservez 0xD000..0xDFFF et gardez son mappage WRAM ; le stockage auxiliaire partage ces adresses. Appelez BeginFrame avant de dessiner pour établir l’état d’occlusion.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.


Commande de compilation
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-disasmImplémentation et source
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
Projette un point du monde par la caméra vers les coordonnées du viewport.
Syntaxe
w3ddmg_u8 DMG3D_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy);Paramètres
xComposante X du point ou de l’origine de l’objet en coordonnées du monde.
yComposante Y du point ou de l’origine de l’objet en coordonnées du monde.
zComposante Z du point ou de l’origine de l’objet en coordonnées du monde.
sxPointeur u8 valide et accessible en écriture recevant la coordonnée X projetée.
syPointeur u8 valide et accessible en écriture recevant la coordonnée Y projetée.
Valeur renvoyée
Renvoie 1 si la projection réussit, 0 si la profondeur est rejetée.
Conditions et limites
WIRE3D_DMG_HEIGHT = 120. Projette un point du monde avec la caméra courante. Une profondeur invalide renvoie zéro sans changer les sorties ; le succès écrit des coordonnées bornées à 128×120. Les deux pointeurs de sortie doivent être valides. Les différences de coordonnées doivent tenir dans s16.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.


Commande de compilation
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-disasmImplémentation et source
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
Met en file une écriture de numéro de tuile dans une case de la carte du fond.
Syntaxe
void DMG3D_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile);Paramètres
xCoordonnée X en tuiles dans la carte de fond de 32×32.
yCoordonnée Y en tuiles dans la carte de fond de 32×32.
tileNuméro de tuile sur huit bits pour la case du fond.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 120. Met en file une écriture de tuile dans la carte 32×32 en 0x9800 pour EndFrame. Les coordonnées invalides et les soumissions au-delà de 48 écritures en attente sont ignorées sans signalement. Cette file est distincte de celle de la bibliothèque vram générale.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.


Commande de compilation
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-disasmImplémentation et source
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
Fait tourner un point sur place selon les angles fournis.
Syntaxe
void DMG3D_RotatePoint(w3ddmg_i16* x, w3ddmg_i16* y, w3ddmg_i16* z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz);Paramètres
xPointeur s16 distinct et accessible en écriture pour la composante X.
yPointeur s16 distinct et accessible en écriture pour la composante Y.
zPointeur s16 distinct et accessible en écriture pour la composante Z.
rxRotation autour de X ; seize pas font un tour complet.
ryRotation autour de Y ; seize pas font un tour complet.
rzRotation autour de Z ; seize pas font un tour complet.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 120. Tourne sur place dans l’ordre Y/X/Z, avec 16 pas par tour. Un pointeur de composante null rend tout l’appel sans effet ; utilisez des pointeurs distincts. Chaque rotation d’axe borne ses entrées à ±220.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Des modèles à l’échelle unitaire et à demi-échelle apparaissent au-dessus d’une scène issue d’un tableau d’objets aux mêmes échelles, illustrant projection et redimensionnement.


Commande de compilation
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-disasmImplémentation et source
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
Choisit si EndFrame transfère aussi les bandes auxiliaires.
Syntaxe
void DMG3D_SetAuxTransfer(w3ddmg_u8 flag);Paramètres
flagZéro désactive la fonction de transfert ; toute autre valeur l’active.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 120. Mémorise l’autorisation de transfert auxiliaire d’EndFrame ; toute valeur non nulle l’active. Aucune donnée n’est copiée ou effacée ici. Les octets source auxiliaires partagent les adresses de la zone principale.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Une partie de la zone principale est consommée par le transfert auxiliaire, ce qui produit un bloc noir de 8×8 à l’écran en (80,24).


Commande de compilation
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-disasmImplémentation et source
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
Mémorise la position et l’orientation de la caméra pour les projections suivantes.
Syntaxe
void DMG3D_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 pitch, w3ddmg_u8 yaw, w3ddmg_u8 roll);Paramètres
xComposante X de la caméra en coordonnées du monde.
yComposante Y de la caméra en coordonnées du monde.
zComposante Z de la caméra en coordonnées du monde.
pitchRotation autour de X ; seize pas font un tour complet.
yawRotation autour de Y ; seize pas font un tour complet.
rollRotation autour de Z ; seize pas font un tour complet.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 120. Mémorise la position et les angles de caméra pour les dessins suivants ; un tour compte 16 pas angulaires. Ne reprojette pas les dessins existants et ne valide pas les plages d’entrée.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.


Commande de compilation
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-disasmImplémentation et source
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
Sélectionne le transfert des tuiles modifiées pour le viewport principal de 120 lignes.
Syntaxe
void DMG3D_SetDirtyTransfer(w3ddmg_u8 flag);Paramètres
flagZéro désactive la fonction de transfert ; toute autre valeur l’active.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 120. Mémorise l’autorisation de transfert des zones modifiées et efface les deux historiques de modifications ainsi que la zone principale, même si la valeur ne change pas. La VRAM est conservée ; l’activer sur une ancienne image peut laisser d’anciennes tuiles non marquées. Préparez donc un affichage de départ propre.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
L’ancien cadre en haut à gauche disparaît ; seul reste le nouveau cadre aux coordonnées écran (96,88)..(120,112).


Commande de compilation
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-disasmImplémentation et source
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
Écrit la correspondance des quatre nuances dans le registre de palette du fond monochrome BGP.
Syntaxe
void DMG3D_SetPalette(w3ddmg_u8 bgp);Paramètres
bgpValeur du registre BGP contenant quatre affectations de nuance sur deux bits.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 120. Écrit immédiatement l’encodage brut de la palette DMG BGP, sans synchronisation d’image.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.


Commande de compilation
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-disasmImplémentation et source
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
Transfère immédiatement six bandes auxiliaires et efface leurs octets source.
Syntaxe
void DMG3D_TransferAuxNow();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 120. Transfère et consomme immédiatement les bandes source auxiliaires, indépendamment de leur autorisation. N’attend pas le début du VBlank et ne met à jour ni historique de modifications ni file BG. La source recouvre la zone principale ; coordonnez les deux transferts.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Une ligne horizontale projetée et un bloc auxiliaire de 8×8 illustrent les transferts directs ; un octet source passe de 255 à 0 lorsqu’il est consommé.


Commande de compilation
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-disasmImplémentation et source
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
Transfère immédiatement toute la zone principale et efface les pixels source consommés.
Syntaxe
void DMG3D_TransferMainNow();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 120. Transfère et consomme immédiatement toute la zone principale en interrogeant STAT, sans attendre le prochain VBlank. Ignore les autorisations de transfert et conserve les historiques de modifications et la file de tuiles BG ; l’appelant coordonne le cycle de l’image.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Une ligne horizontale projetée et un bloc auxiliaire de 8×8 illustrent les transferts directs ; un octet source passe de 255 à 0 lorsqu’il est consommé.


Commande de compilation
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-disasmImplémentation et source
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 — Réserves d'objets fondées sur des tableaux fixes
entity est un pool d’objets sur tableau fixe destiné aux états des ennemis, projectiles, objets à ramasser, etc. Vous allouez un emplacement libre, y accédez par son identifiant, puis le réutilisez lorsque l’objet n’est plus nécessaire. Il n’y a aucune allocation sur le tas. Le jeu définit les unités de position et de vitesse, les déplacements, les collisions et la mise à jour des compteurs de temps.
Incluez entity.h et compilez entity.c exactement une fois. Appelez d’abord entity_init et vérifiez que entity_create ne renvoie pas 0xFF. ENTITY_MAX vaut 16 par défaut. Les identifiants permettent une capacité de 1 à 255 emplacements, mais la capacité réellement utilisable dépend de la RAM disponible. Utilisez la même définition de capacité dans toutes les unités de compilation.
Le pointeur renvoyé par entity_get désigne un emplacement réutilisable du pool. Après libération, le même identifiant peut désigner un autre objet : ni l’identifiant ni le pointeur ne constituent donc une identité permanente. entity_destroy se contente de désactiver l’emplacement. Il revient à l’appelant de masquer ou de libérer les sprites et de nettoyer les autres ressources. Le champ sprite sert au suivi interne ; il ne met pas automatiquement l’OAM à jour.
entity_update_all et entity_draw_all parcourent les emplacements actifs par identifiant croissant et appellent fn(id). Placez le travail de mise à jour ou de dessin dans la fonction de rappel. Un rappel nul ne fait rien. Créer ou libérer un emplacement situé plus loin dans l’ordre de parcours modifie le parcours en cours. Effectuer les mises à jour avant le dessin permet de séparer ces deux responsabilités.
entity_clear_all
Libère toutes les entités et réinitialise leurs champs, y compris le marqueur d’absence de sprite.
Syntaxe
void entity_clear_all();Valeur renvoyée
Aucune (void).
Conditions et limites
Le pool est un tableau fixe, sans allocation sur le tas. ENTITY_MAX vaut 16 par défaut et doit être compris entre 1 et 255, avec la même définition dans chaque unité de compilation. Les ID commencent à zéro ; 0xFF indique un échec.
Met à zéro active,type,x,y,vx,vy,state,timer et place sprite à 0xFF dans chaque emplacement. Ne masque ni ne libère les sprites matériels ; gérez séparément ces ressources.
Exemple d’utilisation
entity_clear_all();
after_clear = entity_count_active();
if (after_clear != 0 || entity_get(reused) != 0) { failures++; }Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le programme complet illustre le cycle de vie d’un emplacement réutilisable. Lisez les nombres avec leurs libellés : CREATED 002 après deux allocations ; AFTER FREE 001 après libération de la première ; REUSED ID 000 quand le plus petit ID libre est réutilisé ; AFTER CLEAR 000 après vidage du pool. Il vérifie aussi la recherche null après libération et la remise à zéro après réallocation. FAILED CHECKS 000 indique que les valeurs concordent.
Le parcours GB appelle chaque rappel pour les deux entités actives : UPDATE CALLS 002 et DRAW CALLS 002. Le rappel de mise à jour déplace les deux objets d’une tuile vers la droite. Celui de dessin place A en (3,12) et B en (7,12) pour les représenter. Ce sont des tuiles de police du fond dessinées par le rappel, pas des sprites alloués automatiquement.


Commande de compilation
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-disasmImplémentation et source
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
Compte les emplacements d’entités occupés sans les modifier.
Syntaxe
u8 entity_count_active();Valeur renvoyée
Nombre d’emplacements dont active est non nul, de 0 à ENTITY_MAX. C’est l’occupation, pas le plus grand ID ni le nombre de sprites à l’écran.
Conditions et limites
Le pool est un tableau fixe, sans allocation sur le tas. ENTITY_MAX vaut 16 par défaut et doit être compris entre 1 et 255, avec la même définition dans chaque unité de compilation. Les ID commencent à zéro ; 0xFF indique un échec.
Exemple d’utilisation
created = entity_count_active();
if (created != 2) { failures++; }Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le programme complet illustre le cycle de vie d’un emplacement réutilisable. Lisez les nombres avec leurs libellés : CREATED 002 après deux allocations ; AFTER FREE 001 après libération de la première ; REUSED ID 000 quand le plus petit ID libre est réutilisé ; AFTER CLEAR 000 après vidage du pool. Il vérifie aussi la recherche null après libération et la remise à zéro après réallocation. FAILED CHECKS 000 indique que les valeurs concordent.
Le parcours GB appelle chaque rappel pour les deux entités actives : UPDATE CALLS 002 et DRAW CALLS 002. Le rappel de mise à jour déplace les deux objets d’une tuile vers la droite. Celui de dessin place A en (3,12) et B en (7,12) pour les représenter. Ce sont des tuiles de police du fond dessinées par le rappel, pas des sprites alloués automatiquement.


Commande de compilation
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-disasmImplémentation et source
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
Alloue une entité du type et à la position indiqués ; renvoie son ID réutilisable ou 0xFF si le pool est plein.
Syntaxe
u8 entity_create(u8 type, s16 x, s16 y);Paramètres
typeÉtiquette de type définie par le jeu, de 0 à 255. Le pool la conserve sans sélectionner de comportement ni de routine de dessin.
x, yCoordonnées signées sur 16 bits (
-32768–32767). Le jeu choisit l’unité, par exemple pixels ou Q8.8 ; le pool ne convertit pas les unités, ne borne pas les positions et n’applique pas automatiquement les vitesses.
Valeur renvoyée
L’ID du premier emplacement libre (0–ENTITY_MAX-1), ou 0xFF si aucun n’est libre. L’allocation fixe active=1, conserve type et position, efface vitesse/état/temporisateur et place sprite=0xFF.
Conditions et limites
Le pool est un tableau fixe, sans allocation sur le tas. ENTITY_MAX vaut 16 par défaut et doit être compris entre 1 et 255, avec la même définition dans chaque unité de compilation. Les ID commencent à zéro ; 0xFF indique un échec.
Exemple d’utilisation
first = entity_create(1, 2, 12);
second = entity_create(2, 6, 12);
if (first == 0xFF || second == 0xFF) { failures++; }Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le programme complet illustre le cycle de vie d’un emplacement réutilisable. Lisez les nombres avec leurs libellés : CREATED 002 après deux allocations ; AFTER FREE 001 après libération de la première ; REUSED ID 000 quand le plus petit ID libre est réutilisé ; AFTER CLEAR 000 après vidage du pool. Il vérifie aussi la recherche null après libération et la remise à zéro après réallocation. FAILED CHECKS 000 indique que les valeurs concordent.
Le parcours GB appelle chaque rappel pour les deux entités actives : UPDATE CALLS 002 et DRAW CALLS 002. Le rappel de mise à jour déplace les deux objets d’une tuile vers la droite. Celui de dessin place A en (3,12) et B en (7,12) pour les représenter. Ce sont des tuiles de police du fond dessinées par le rappel, pas des sprites alloués automatiquement.


Commande de compilation
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-disasmImplémentation et source
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
Libère l’entité id ; ses données restent en place jusqu’à la prochaine allocation.
Syntaxe
void entity_destroy(u8 id);Paramètres
idIndice d’emplacement réutilisable, de 0 à
ENTITY_MAX-1. Au-delà, l’ID est invalide. Sa destruction n’a aucun effet et sa recherche renvoie null.
Valeur renvoyée
Aucune (void).
Conditions et limites
Le pool est un tableau fixe, sans allocation sur le tas. ENTITY_MAX vaut 16 par défaut et doit être compris entre 1 et 255, avec la même définition dans chaque unité de compilation. Les ID commencent à zéro ; 0xFF indique un échec.
La destruction efface seulement active : elle n’efface pas les autres champs et ne libère ni sprite ni ressource. Une allocation ultérieure peut réutiliser le même ID et la même adresse pour une autre entité. Le jeu doit gérer les ressources associées.
Exemple d’utilisation
entity_destroy(first);
after_free = entity_count_active();
if (entity_get(first) != 0 || after_free != 1) { failures++; }Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le programme complet illustre le cycle de vie d’un emplacement réutilisable. Lisez les nombres avec leurs libellés : CREATED 002 après deux allocations ; AFTER FREE 001 après libération de la première ; REUSED ID 000 quand le plus petit ID libre est réutilisé ; AFTER CLEAR 000 après vidage du pool. Il vérifie aussi la recherche null après libération et la remise à zéro après réallocation. FAILED CHECKS 000 indique que les valeurs concordent.
Le parcours GB appelle chaque rappel pour les deux entités actives : UPDATE CALLS 002 et DRAW CALLS 002. Le rappel de mise à jour déplace les deux objets d’une tuile vers la droite. Celui de dessin place A en (3,12) et B en (7,12) pour les représenter. Ce sont des tuiles de police du fond dessinées par le rappel, pas des sprites alloués automatiquement.


Commande de compilation
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-disasmImplémentation et source
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
Parcourt les entités actives et transmet chaque ID au rappel de dessin. Le parcours est celui de entity_update_all ; aucun sprite ni pixel n’est dessiné si le rappel ne soumet pas de données de dessin.
Syntaxe
void entity_draw_all(EntityFn fn);Paramètres
fnPointeur de fonction de signature
void fn(u8 id). Reçoit un ID ; utilisezentity_get(id)pour accéder aux champs. Null est accepté et n’entraîne aucun appel.
Valeur renvoyée
Aucune (void).
Conditions et limites
Le pool est un tableau fixe, sans allocation sur le tas. ENTITY_MAX vaut 16 par défaut et doit être compris entre 1 et 255, avec la même définition dans chaque unité de compilation. Les ID commencent à zéro ; 0xFF indique un échec.
L’activité est testée au moment d’atteindre l’emplacement. Un rappel peut désactiver un emplacement suivant pour le sauter, ou l’activer pour le visiter dans cette passe. Ce n’est pas un instantané de l’ensemble actif initial.
Exemple d’utilisation
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++; }Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le programme complet illustre le cycle de vie d’un emplacement réutilisable. Lisez les nombres avec leurs libellés : CREATED 002 après deux allocations ; AFTER FREE 001 après libération de la première ; REUSED ID 000 quand le plus petit ID libre est réutilisé ; AFTER CLEAR 000 après vidage du pool. Il vérifie aussi la recherche null après libération et la remise à zéro après réallocation. FAILED CHECKS 000 indique que les valeurs concordent.
Le parcours GB appelle chaque rappel pour les deux entités actives : UPDATE CALLS 002 et DRAW CALLS 002. Le rappel de mise à jour déplace les deux objets d’une tuile vers la droite. Celui de dessin place A en (3,12) et B en (7,12) pour les représenter. Ce sont des tuiles de police du fond dessinées par le rappel, pas des sprites alloués automatiquement.


Commande de compilation
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-disasmImplémentation et source
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
Renvoie un pointeur vers l’entité active, ou null pour un ID invalide ou libre. Cet espace peut être réutilisé.
Syntaxe
Entity* entity_get(u8 id);Paramètres
idIndice d’emplacement réutilisable, de 0 à
ENTITY_MAX-1. Au-delà, l’ID est invalide. Sa destruction n’a aucun effet et sa recherche renvoie null.
Valeur renvoyée
Pointeur modifiable vers l’emplacement actif, ou null pour un ID invalide ou libre. La mémoire appartient au pool ; ne la libérez pas et ne traitez pas le pointeur comme une identité permanente après destruction et réallocation.
Conditions et limites
Le pool est un tableau fixe, sans allocation sur le tas. ENTITY_MAX vaut 16 par défaut et doit être compris entre 1 et 255, avec la même définition dans chaque unité de compilation. Les ID commencent à zéro ; 0xFF indique un échec.
La destruction efface seulement active : elle n’efface pas les autres champs et ne libère ni sprite ni ressource. Une allocation ultérieure peut réutiliser le même ID et la même adresse pour une autre entité. Le jeu doit gérer les ressources associées.
Exemple d’utilisation
current_entity = entity_get(first);
if (current_entity != 0) { current_entity->vx = 5; }
else { failures++; }Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le programme complet illustre le cycle de vie d’un emplacement réutilisable. Lisez les nombres avec leurs libellés : CREATED 002 après deux allocations ; AFTER FREE 001 après libération de la première ; REUSED ID 000 quand le plus petit ID libre est réutilisé ; AFTER CLEAR 000 après vidage du pool. Il vérifie aussi la recherche null après libération et la remise à zéro après réallocation. FAILED CHECKS 000 indique que les valeurs concordent.
Le parcours GB appelle chaque rappel pour les deux entités actives : UPDATE CALLS 002 et DRAW CALLS 002. Le rappel de mise à jour déplace les deux objets d’une tuile vers la droite. Celui de dessin place A en (3,12) et B en (7,12) pour les représenter. Ce sont des tuiles de police du fond dessinées par le rappel, pas des sprites alloués automatiquement.


Commande de compilation
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-disasmImplémentation et source
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
Initialise tous les emplacements du pool d’entités.
Syntaxe
void entity_init();Valeur renvoyée
Aucune (void).
Conditions et limites
Le pool est un tableau fixe, sans allocation sur le tas. ENTITY_MAX vaut 16 par défaut et doit être compris entre 1 et 255, avec la même définition dans chaque unité de compilation. Les ID commencent à zéro ; 0xFF indique un échec.
Met à zéro active,type,x,y,vx,vy,state,timer et place sprite à 0xFF dans chaque emplacement. Ne masque ni ne libère les sprites matériels ; gérez séparément ces ressources.
Exemple d’utilisation
entity_init();
if (entity_count_active() != 0) { failures++; }Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le programme complet illustre le cycle de vie d’un emplacement réutilisable. Lisez les nombres avec leurs libellés : CREATED 002 après deux allocations ; AFTER FREE 001 après libération de la première ; REUSED ID 000 quand le plus petit ID libre est réutilisé ; AFTER CLEAR 000 après vidage du pool. Il vérifie aussi la recherche null après libération et la remise à zéro après réallocation. FAILED CHECKS 000 indique que les valeurs concordent.
Le parcours GB appelle chaque rappel pour les deux entités actives : UPDATE CALLS 002 et DRAW CALLS 002. Le rappel de mise à jour déplace les deux objets d’une tuile vers la droite. Celui de dessin place A en (3,12) et B en (7,12) pour les représenter. Ce sont des tuiles de police du fond dessinées par le rappel, pas des sprites alloués automatiquement.


Commande de compilation
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-disasmImplémentation et source
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
Parcourt les emplacements actifs par ID croissant et appelle fn(id) une fois pour chacun. Le rappel implémente déplacements, collisions ou temporisateurs ; le pool ne fournit pas cette logique. Un rappel null ne fait rien.
Syntaxe
void entity_update_all(EntityFn fn);Paramètres
fnPointeur de fonction de signature
void fn(u8 id). Reçoit un ID ; utilisezentity_get(id)pour accéder aux champs. Null est accepté et n’entraîne aucun appel.
Valeur renvoyée
Aucune (void).
Conditions et limites
Le pool est un tableau fixe, sans allocation sur le tas. ENTITY_MAX vaut 16 par défaut et doit être compris entre 1 et 255, avec la même définition dans chaque unité de compilation. Les ID commencent à zéro ; 0xFF indique un échec.
L’activité est testée au moment d’atteindre l’emplacement. Un rappel peut désactiver un emplacement suivant pour le sauter, ou l’activer pour le visiter dans cette passe. Ce n’est pas un instantané de l’ensemble actif initial.
Exemple d’utilisation
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++; }Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le programme complet illustre le cycle de vie d’un emplacement réutilisable. Lisez les nombres avec leurs libellés : CREATED 002 après deux allocations ; AFTER FREE 001 après libération de la première ; REUSED ID 000 quand le plus petit ID libre est réutilisé ; AFTER CLEAR 000 après vidage du pool. Il vérifie aussi la recherche null après libération et la remise à zéro après réallocation. FAILED CHECKS 000 indique que les valeurs concordent.
Le parcours GB appelle chaque rappel pour les deux entités actives : UPDATE CALLS 002 et DRAW CALLS 002. Le rappel de mise à jour déplace les deux objets d’une tuile vers la droite. Celui de dessin place A en (3,12) et B en (7,12) pour les représenter. Ce sont des tuiles de police du fond dessinées par le rappel, pas des sprites alloués automatiquement.


Commande de compilation
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-disasmImplémentation et source
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 — Calcul en virgule fixe Q8.8 et rectangles
L’arithmétique Q8.8 représente les coordonnées et vitesses fractionnaires avec des entiers ; elle s’accompagne de tests de collision entre rectangles et points. Vérifiez la précision et les limites de chaque opération.
fix_div
Divise des valeurs Q8.8 après avoir réduit la précision des opérandes.
Syntaxe
fix8 fix_div(fix8 a, fix8 b);Paramètres
aOpérande de gauche au format Q8.8.
bOpérande de droite au format Q8.8.
Valeur renvoyée
Renvoie un quotient Q8.8, ou zéro si b == 0.
Conditions et limites
L’expression calculée est ((a >> 4) * 256) / (b >> 4). Un diviseur non nul doit le rester après le décalage : n’utilisez pas de valeur brute positive de 1 à 15. Le numérateur mis à l’échelle doit lui aussi tenir sur 16 bits.
Exemple d’utilisation
result[3]=fix_div(768,512);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Diviser 3,0 par 2,0 donne 1,5 (valeur brute 384). Une vérification distincte contrôle le retour prévu lorsque le diviseur est exactement nul.


Commande de compilation
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=64kImplémentation et source
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
Convertit une coordonnée ou une vitesse entière en Q8.8 pour conserver les parties fractionnaires dans les calculs suivants.
Syntaxe
fix8 fix_from_int(s16 n);Paramètres
nEntier à convertir, de −128 à 127.
Valeur renvoyée
Renvoie la valeur brute n × 256.
Conditions et limites
fix8 est un format Q8.8 signé : la valeur brute 256 représente 1,0. Les valeurs intermédiaires et les résultats doivent tenir sur 16 bits.
Exemple d’utilisation
result[0]=fix_from_int(-3);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple convertit −3. L’affichage −00768 correspond au résultat brut Q8.8, soit −768.


Commande de compilation
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=64kImplémentation et source
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
Interpole entre deux valeurs Q8.8 à l’aide d’un poids sur huit bits.
Syntaxe
fix8 fix_lerp(fix8 a, fix8 b, u8 t_q8);Paramètres
aOpérande de gauche au format Q8.8.
bOpérande de droite au format Q8.8.
t_q8Poids d’interpolation, de 0 à 255.
Valeur renvoyée
Renvoie la valeur Q8.8 interpolée approximativement.
Conditions et limites
La différence et le poids sont chacun décalés de quatre bits vers la droite. Le poids n’a donc que 16 niveaux, et même 255 ne permet pas nécessairement d’atteindre la valeur finale. b - a et le résultat doivent tenir sur 16 bits.
Exemple d’utilisation
result[4]=fix_lerp(0,1024,128);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Entre 0 et 4,0, un poids de 128 donne 2,0 (valeur brute 512). Un poids de 255 donne 3,75 (valeur brute 960), ce qui montre que la valeur finale n’est pas atteinte.


Commande de compilation
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=64kImplémentation et source
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
Multiplie deux valeurs Q8.8 par une approximation peu coûteuse en calcul.
Syntaxe
fix8 fix_mul(fix8 a, fix8 b);Paramètres
aOpérande de gauche au format Q8.8.
bOpérande de droite au format Q8.8.
Valeur renvoyée
Renvoie le produit au format Q8.8.
Conditions et limites
Chaque opérande est décalé de quatre bits vers la droite avant la multiplication, ce qui supprime ses quatre bits de poids faible. La précision est donc inférieure à celle d’un produit complet de deux valeurs de 16 bits. fix8 est un format Q8.8 signé où la valeur brute 256 représente 1,0. Les valeurs intermédiaires et les résultats doivent tenir sur 16 bits.
Exemple d’utilisation
result[2]=fix_mul(384,512);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Multiplier 1,5 par 2,0 donne 3,0 (valeur brute 768). Le programme vérifie aussi un cas de quantification : le produit des valeurs brutes 271 et 271 donne 256.


Commande de compilation
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=64kImplémentation et source
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
Extrait une coordonnée entière d’une valeur Q8.8 en supprimant les bits fractionnaires. Les valeurs négatives sont arrondies vers moins l’infini.
Syntaxe
s16 fix_to_int(fix8 x);Paramètres
xValeur Q8.8 à convertir en entier.
Valeur renvoyée
Renvoie un entier signé.
Conditions et limites
fix8 est un format Q8.8 signé : la valeur brute 256 représente 1,0. Les valeurs intermédiaires et les résultats doivent tenir sur 16 bits.
Exemple d’utilisation
result[1]=fix_to_int(-384);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
La valeur brute −384 (−1,5) donne −2, affiché sous la forme −00002. Un test de limite vérifie aussi que la valeur brute −1 devient −1.


Commande de compilation
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=64kImplémentation et source
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
Calcule la valeur absolue d’un entier signé sur 16 bits.
Syntaxe
s16 kq_abs_s16(s16 v);Paramètres
vValeur signée sur 16 bits dont on cherche la valeur absolue.
Valeur renvoyée
Renvoie une valeur absolue non négative, sauf pour −32768, dont la valeur absolue n’est pas représentable.
Conditions et limites
La valeur positive 32768 ne tient pas dans un s16. Excluez −32768 si vous avez besoin d’un résultat non négatif.
Exemple d’utilisation
result[0]=kq_abs_s16(-123);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple transforme −123 en 123, comme pour mesurer l’amplitude d’un écart entre deux coordonnées.


Commande de compilation
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=64kImplémentation et source
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
Limite une coordonnée ou une vitesse à un intervalle dont les bornes sont incluses.
Syntaxe
s16 kq_clamp_s16(s16 v, s16 lo, s16 hi);Paramètres
vValeur signée à limiter.
loBorne inférieure incluse.
hiBorne supérieure incluse.
Valeur renvoyée
Renvoie lo en dessous de l’intervalle, hi au-dessus, ou v si la valeur est dans l’intervalle.
Conditions et limites
Fournissez un intervalle valide tel que lo <= hi.
Exemple d’utilisation
result[3]=kq_clamp_s16(25,-10,10);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Limiter 25 à l’intervalle −10…10 donne 10. Les tests couvrent aussi −11→−10 à la borne inférieure et 3→3 à l’intérieur de l’intervalle.


Commande de compilation
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=64kImplémentation et source
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
Sélectionne le plus grand de deux entiers signés sur 16 bits.
Syntaxe
s16 kq_max_s16(s16 a, s16 b);Paramètres
aPremière valeur signée à comparer.
bSeconde valeur signée à comparer.
Valeur renvoyée
Renvoie l’opérande sélectionné.
Conditions et limites
La comparaison tient compte du signe. Si les opérandes sont égaux, leur valeur commune est renvoyée. Aucun des deux n’est modifié.
Exemple d’utilisation
result[2]=kq_max_s16(-7,4);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Comparer −7 et 4 donne 4. Les résultats négatifs sont affichés avec un signe moins.


Commande de compilation
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=64kImplémentation et source
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
Sélectionne le plus petit de deux entiers signés sur 16 bits.
Syntaxe
s16 kq_min_s16(s16 a, s16 b);Paramètres
aPremière valeur signée à comparer.
bSeconde valeur signée à comparer.
Valeur renvoyée
Renvoie l’opérande sélectionné.
Conditions et limites
La comparaison tient compte du signe. Si les opérandes sont égaux, leur valeur commune est renvoyée. Aucun des deux n’est modifié.
Exemple d’utilisation
result[1]=kq_min_s16(-7,4);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Comparer −7 et 4 donne -7. Les résultats négatifs sont affichés avec un signe moins.


Commande de compilation
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=64kImplémentation et source
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
Teste si un point se trouve dans un rectangle, bords gauche et supérieur inclus.
Syntaxe
u8 kq_point_in_rect(s16 x, s16 y, KQRect r);Paramètres
xCoordonnée X du point, dans le repère du rectangle.
yCoordonnée Y du point.
rRectangle à tester, passé par valeur.
Valeur renvoyée
Renvoie 1 à l’intérieur et 0 à l’extérieur.
Conditions et limites
Utilisez des dimensions positives et veillez à ce que les sommes coordonnée + dimension soient représentables en s16. Les bords droit et inférieur sont exclus. Les rectangles d’aire nulle ne sont pas explicitement rejetés.
Exemple d’utilisation
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));
}}Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Chaque unité de coordonnée correspond à une tuile. Les rectangles A en (1,1) et B en (5,4) mesurent tous deux 8×6. Les cases propres à A affichent A, celles propres à B affichent B, et le chevauchement de 4×3 affiche 12 cases O. Le bord droit de A, x=9, est exclu. Sur CGB, A est rouge, B bleu et O vert.


Commande de compilation
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=64kImplémentation et source
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
Teste si deux rectangles alignés sur les axes se recouvrent sur une aire strictement positive.
Syntaxe
u8 kq_rect_intersect(KQRect a, KQRect b);Paramètres
aPremier rectangle, passé par valeur :
x, yindiquent son coin supérieur gauche ;w, hsont sa largeur et sa hauteur.bSecond rectangle, dans le même repère que A.
Valeur renvoyée
Renvoie 1 en cas de recouvrement, et 0 en cas de séparation ou de simple contact des bords.
Conditions et limites
Utilisez des dimensions positives et veillez à ce que les sommes coordonnée + dimension soient représentables en s16. Les bords droit et inférieur sont exclus. Les rectangles d’aire nulle ne sont pas explicitement rejetés.
Exemple d’utilisation
result[0]=kq_rect_intersect(a,b);result[2]=kq_rect_intersect(a,touch);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Chaque unité de coordonnée correspond à une tuile. Les rectangles A en (1,1) et B en (5,4) mesurent tous deux 8×6. Les cases propres à A affichent A, celles propres à B affichent B, et le chevauchement de 4×3 affiche 12 cases O. Le bord droit de A, x=9, est exclu. Sur CGB, A est rouge, B bleu et O vert.


Commande de compilation
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=64kImplémentation et source
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 — État des boutons, appuis, relâchements et répétition
Utilisez input_down pour un mouvement continu, input_pressed pour une action unique, input_released pour agir au relâchement et input_repeat pour répéter une sélection de menu. Initialisez une fois, mettez à jour une fois par cycle d’entrée, puis consultez autant que nécessaire. btn_down, btn_pressed, btn_released et btn_repeat sont les alias de ces quatre consultations.
Masques communs : BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Un bit à 1 indique un bouton maintenu. Ce format s’applique à input_* sur GB et FC ; les lectures brutes FC utilisent un autre ordre.
Les délais se comptent en mises à jour, pas en millisecondes. Un nouvel appui produit un événement immédiat. Avec INPUT_REPEAT_DELAY=18 et INPUT_REPEAT_RATE=5, le suivant arrive 19 mises à jour plus tard, puis tous les 6 appels. Chaque bouton a son compteur. Appliquez les mêmes macros lors de la compilation de input.c ; modifier seulement l’en-tête du code appelant ne reconfigure pas la bibliothèque.
btn_down
btn_down est un alias de input_down. Vérifie si au moins un des boutons sélectionnés est actuellement maintenu.
Indique si au moins un bouton sélectionné par mask est maintenu.
Syntaxe
u8 btn_down(u8 mask);Paramètres
maskUn masque
BTN_*, ou plusieurs combinés avec|. Un seul bouton correspondant suffit ;BTN_A | BTN_Bn’exige pas les deux. Le masque 0 renvoie toujours 0. Pour vérifier que tous sont maintenus, comparez(input_current() & mask) == mask.
Valeur renvoyée
Renvoie exactement 1 si un bouton sélectionné remplit la condition, sinon 0. Le résultat n’est pas un masque de boutons.
Conditions et limites
L’en-tête définit une macro objet qui se développe en nom d’implémentation. Arguments, résultats et accès à l’état sont identiques à ceux de la cible ; l’alias n’ajoute aucun état ni traitement distinct. Utilisez input.h/input.c pour les entrées ou system.h/system.c pour les services d’images, comme dans l’exemple complet et sa commande de compilation.
Masques communs : BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Un bit à 1 indique un bouton maintenu. Ce format s’applique à input_* sur GB et FC ; les lectures brutes FC utilisent un autre ordre.
Les fonctions de consultation lisent le dernier input_update() sans relire le contrôleur, consommer d’événement ni avancer les compteurs. Plusieurs consultations dans un même cycle donnent le même résultat. Deux appels à input_update() avec un bouton maintenu effacent son événement de nouvel appui au second appel.
Exemple d’utilisation
if (btn_down(BTN_A)!=0) held_ticks++;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme distingue le maintien d’un bouton, un nouvel appui, le relâchement et la répétition automatique. Maintenez A pendant 40 mises à jour, puis relâchez-le. FIRST DOWN, FIRST PRESS et FIRST REPEAT valent 1 ; FIRST CURRENT vaut 16. HELD TICKS vaut 40, PRESS COUNT vaut 1 et REPEAT COUNT vaut 5. Au relâchement, RELEASE vaut 1, LAST CURRENT vaut 0 et LAST PREVIOUS vaut 16. FAILED CHECKS doit valoir 0. Une autre durée modifie les compteurs ; le programme vérifie les intervalles de répétition selon la durée réellement observée.


Commande de compilation
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-cacheImplémentation et source
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 est un alias de input_pressed. Vérifie si au moins un des boutons sélectionnés vient d’être enfoncé lors de la dernière mise à jour des entrées.
Détecte un passage de relâché à appuyé pour un bouton du masque lors de la dernière mise à jour.
Syntaxe
u8 btn_pressed(u8 mask);Paramètres
maskUn masque
BTN_*, ou plusieurs combinés avec|. Un seul bouton correspondant suffit ;BTN_A | BTN_Bn’exige pas les deux. Le masque 0 renvoie toujours 0. Pour vérifier que tous sont maintenus, comparez(input_current() & mask) == mask.
Valeur renvoyée
Renvoie exactement 1 si un bouton sélectionné remplit la condition, sinon 0. Le résultat n’est pas un masque de boutons.
Conditions et limites
L’en-tête définit une macro objet qui se développe en nom d’implémentation. Arguments, résultats et accès à l’état sont identiques à ceux de la cible ; l’alias n’ajoute aucun état ni traitement distinct. Utilisez input.h/input.c pour les entrées ou system.h/system.c pour les services d’images, comme dans l’exemple complet et sa commande de compilation.
Masques communs : BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Un bit à 1 indique un bouton maintenu. Ce format s’applique à input_* sur GB et FC ; les lectures brutes FC utilisent un autre ordre.
Les fonctions de consultation lisent le dernier input_update() sans relire le contrôleur, consommer d’événement ni avancer les compteurs. Plusieurs consultations dans un même cycle donnent le même résultat. Deux appels à input_update() avec un bouton maintenu effacent son événement de nouvel appui au second appel.
Exemple d’utilisation
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++;
}Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme distingue le maintien d’un bouton, un nouvel appui, le relâchement et la répétition automatique. Maintenez A pendant 40 mises à jour, puis relâchez-le. FIRST DOWN, FIRST PRESS et FIRST REPEAT valent 1 ; FIRST CURRENT vaut 16. HELD TICKS vaut 40, PRESS COUNT vaut 1 et REPEAT COUNT vaut 5. Au relâchement, RELEASE vaut 1, LAST CURRENT vaut 0 et LAST PREVIOUS vaut 16. FAILED CHECKS doit valoir 0. Une autre durée modifie les compteurs ; le programme vérifie les intervalles de répétition selon la durée réellement observée.


Commande de compilation
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-cacheImplémentation et source
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 est un alias de input_released. Vérifie si au moins un des boutons sélectionnés a été relâché lors de la dernière mise à jour des entrées.
Détecte un relâchement pour un bouton du masque lors de la dernière mise à jour.
Syntaxe
u8 btn_released(u8 mask);Paramètres
maskUn masque
BTN_*, ou plusieurs combinés avec|. Un seul bouton correspondant suffit ;BTN_A | BTN_Bn’exige pas les deux. Le masque 0 renvoie toujours 0. Pour vérifier que tous sont maintenus, comparez(input_current() & mask) == mask.
Valeur renvoyée
Renvoie exactement 1 si un bouton sélectionné remplit la condition, sinon 0. Le résultat n’est pas un masque de boutons.
Conditions et limites
L’en-tête définit une macro objet qui se développe en nom d’implémentation. Arguments, résultats et accès à l’état sont identiques à ceux de la cible ; l’alias n’ajoute aucun état ni traitement distinct. Utilisez input.h/input.c pour les entrées ou system.h/system.c pour les services d’images, comme dans l’exemple complet et sa commande de compilation.
Masques communs : BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Un bit à 1 indique un bouton maintenu. Ce format s’applique à input_* sur GB et FC ; les lectures brutes FC utilisent un autre ordre.
Les fonctions de consultation lisent le dernier input_update() sans relire le contrôleur, consommer d’événement ni avancer les compteurs. Plusieurs consultations dans un même cycle donnent le même résultat. Deux appels à input_update() avec un bouton maintenu effacent son événement de nouvel appui au second appel.
Exemple d’utilisation
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;
}Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme distingue le maintien d’un bouton, un nouvel appui, le relâchement et la répétition automatique. Maintenez A pendant 40 mises à jour, puis relâchez-le. FIRST DOWN, FIRST PRESS et FIRST REPEAT valent 1 ; FIRST CURRENT vaut 16. HELD TICKS vaut 40, PRESS COUNT vaut 1 et REPEAT COUNT vaut 5. Au relâchement, RELEASE vaut 1, LAST CURRENT vaut 0 et LAST PREVIOUS vaut 16. FAILED CHECKS doit valoir 0. Une autre durée modifie les compteurs ; le programme vérifie les intervalles de répétition selon la durée réellement observée.


Commande de compilation
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-cacheImplémentation et source
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 est un alias de input_repeat. Détecte l’appui initial ou une impulsion de répétition programmée pendant le maintien d’un bouton.
Détecte un premier appui ou une impulsion de répétition pour un bouton du masque.
Syntaxe
u8 btn_repeat(u8 mask);Paramètres
maskUn masque
BTN_*, ou plusieurs combinés avec|. Un seul bouton correspondant suffit ;BTN_A | BTN_Bn’exige pas les deux. Le masque 0 renvoie toujours 0. Pour vérifier que tous sont maintenus, comparez(input_current() & mask) == mask.
Valeur renvoyée
Renvoie exactement 1 si un bouton sélectionné remplit la condition, sinon 0. Le résultat n’est pas un masque de boutons.
Conditions et limites
L’en-tête définit une macro objet qui se développe en nom d’implémentation. Arguments, résultats et accès à l’état sont identiques à ceux de la cible ; l’alias n’ajoute aucun état ni traitement distinct. Utilisez input.h/input.c pour les entrées ou system.h/system.c pour les services d’images, comme dans l’exemple complet et sa commande de compilation.
Masques communs : BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Un bit à 1 indique un bouton maintenu. Ce format s’applique à input_* sur GB et FC ; les lectures brutes FC utilisent un autre ordre.
Les fonctions de consultation lisent le dernier input_update() sans relire le contrôleur, consommer d’événement ni avancer les compteurs. Plusieurs consultations dans un même cycle donnent le même résultat. Deux appels à input_update() avec un bouton maintenu effacent son événement de nouvel appui au second appel.
Les délais se comptent en mises à jour, pas en millisecondes. Un nouvel appui produit un événement immédiat. Avec INPUT_REPEAT_DELAY=18 et INPUT_REPEAT_RATE=5, le suivant arrive 19 mises à jour plus tard, puis tous les 6 appels. Chaque bouton a son compteur. Appliquez les mêmes macros lors de la compilation de input.c ; modifier seulement l’en-tête du code appelant ne reconfigure pas la bibliothèque.
Exemple d’utilisation
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.
}Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme distingue le maintien d’un bouton, un nouvel appui, le relâchement et la répétition automatique. Maintenez A pendant 40 mises à jour, puis relâchez-le. FIRST DOWN, FIRST PRESS et FIRST REPEAT valent 1 ; FIRST CURRENT vaut 16. HELD TICKS vaut 40, PRESS COUNT vaut 1 et REPEAT COUNT vaut 5. Au relâchement, RELEASE vaut 1, LAST CURRENT vaut 0 et LAST PREVIOUS vaut 16. FAILED CHECKS doit valoir 0. Une autre durée modifie les compteurs ; le programme vérifie les intervalles de répétition selon la durée réellement observée.


Commande de compilation
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-cacheImplémentation et source
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
Renvoie le masque complet des boutons maintenus lors de la dernière mise à jour.
Syntaxe
u8 input_current();Valeur renvoyée
Un masque de 8 bits au format commun BTN_*. Plusieurs boutons peuvent être présents simultanément ; 0 signifie aucun.
Conditions et limites
Masques communs : BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Un bit à 1 indique un bouton maintenu. Ce format s’applique à input_* sur GB et FC ; les lectures brutes FC utilisent un autre ordre.
Les fonctions de consultation lisent le dernier input_update() sans relire le contrôleur, consommer d’événement ni avancer les compteurs. Plusieurs consultations dans un même cycle donnent le même résultat. Deux appels à input_update() avec un bouton maintenu effacent son événement de nouvel appui au second appel.
Exemple d’utilisation
first_current=input_current(); // Only A held: BTN_A, or decimal 16.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme distingue le maintien d’un bouton, un nouvel appui, le relâchement et la répétition automatique. Maintenez A pendant 40 mises à jour, puis relâchez-le. FIRST DOWN, FIRST PRESS et FIRST REPEAT valent 1 ; FIRST CURRENT vaut 16. HELD TICKS vaut 40, PRESS COUNT vaut 1 et REPEAT COUNT vaut 5. Au relâchement, RELEASE vaut 1, LAST CURRENT vaut 0 et LAST PREVIOUS vaut 16. FAILED CHECKS doit valoir 0. Une autre durée modifie les compteurs ; le programme vérifie les intervalles de répétition selon la durée réellement observée.


Commande de compilation
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-cacheImplémentation et source
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
Indique si au moins un bouton sélectionné par mask est maintenu.
Syntaxe
u8 input_down(u8 mask);Paramètres
maskUn masque
BTN_*, ou plusieurs combinés avec|. Un seul bouton correspondant suffit ;BTN_A | BTN_Bn’exige pas les deux. Le masque 0 renvoie toujours 0. Pour vérifier que tous sont maintenus, comparez(input_current() & mask) == mask.
Valeur renvoyée
Renvoie exactement 1 si un bouton sélectionné remplit la condition, sinon 0. Le résultat n’est pas un masque de boutons.
Conditions et limites
Masques communs : BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Un bit à 1 indique un bouton maintenu. Ce format s’applique à input_* sur GB et FC ; les lectures brutes FC utilisent un autre ordre.
Les fonctions de consultation lisent le dernier input_update() sans relire le contrôleur, consommer d’événement ni avancer les compteurs. Plusieurs consultations dans un même cycle donnent le même résultat. Deux appels à input_update() avec un bouton maintenu effacent son événement de nouvel appui au second appel.
Exemple d’utilisation
if (input_down(BTN_A)!=0) held_ticks++;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme distingue le maintien d’un bouton, un nouvel appui, le relâchement et la répétition automatique. Maintenez A pendant 40 mises à jour, puis relâchez-le. FIRST DOWN, FIRST PRESS et FIRST REPEAT valent 1 ; FIRST CURRENT vaut 16. HELD TICKS vaut 40, PRESS COUNT vaut 1 et REPEAT COUNT vaut 5. Au relâchement, RELEASE vaut 1, LAST CURRENT vaut 0 et LAST PREVIOUS vaut 16. FAILED CHECKS doit valoir 0. Une autre durée modifie les compteurs ; le programme vérifie les intervalles de répétition selon la durée réellement observée.


Commande de compilation
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-cacheImplémentation et source
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
Efface les masques courant, précédent, d’appui, de relâchement et de répétition, puis réinitialise les huit compteurs à INPUT_REPEAT_DELAY. Le contrôleur n’est pas lu. Un bouton maintenu lors de la première mise à jour suivante est considéré comme un nouvel appui.
Syntaxe
void input_init();Valeur renvoyée
Aucune (void).
Conditions et limites
Masques communs : BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Un bit à 1 indique un bouton maintenu. Ce format s’applique à input_* sur GB et FC ; les lectures brutes FC utilisent un autre ordre.
Les délais se comptent en mises à jour, pas en millisecondes. Un nouvel appui produit un événement immédiat. Avec INPUT_REPEAT_DELAY=18 et INPUT_REPEAT_RATE=5, le suivant arrive 19 mises à jour plus tard, puis tous les 6 appels. Chaque bouton a son compteur. Appliquez les mêmes macros lors de la compilation de input.c ; modifier seulement l’en-tête du code appelant ne reconfigure pas la bibliothèque.
Exemple d’utilisation
input_init();
if (input_current()!=0 || input_previous()!=0) failures++;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme distingue le maintien d’un bouton, un nouvel appui, le relâchement et la répétition automatique. Maintenez A pendant 40 mises à jour, puis relâchez-le. FIRST DOWN, FIRST PRESS et FIRST REPEAT valent 1 ; FIRST CURRENT vaut 16. HELD TICKS vaut 40, PRESS COUNT vaut 1 et REPEAT COUNT vaut 5. Au relâchement, RELEASE vaut 1, LAST CURRENT vaut 0 et LAST PREVIOUS vaut 16. FAILED CHECKS doit valoir 0. Une autre durée modifie les compteurs ; le programme vérifie les intervalles de répétition selon la durée réellement observée.


Commande de compilation
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-cacheImplémentation et source
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
Détecte un passage de relâché à appuyé pour un bouton du masque lors de la dernière mise à jour.
Syntaxe
u8 input_pressed(u8 mask);Paramètres
maskUn masque
BTN_*, ou plusieurs combinés avec|. Un seul bouton correspondant suffit ;BTN_A | BTN_Bn’exige pas les deux. Le masque 0 renvoie toujours 0. Pour vérifier que tous sont maintenus, comparez(input_current() & mask) == mask.
Valeur renvoyée
Renvoie exactement 1 si un bouton sélectionné remplit la condition, sinon 0. Le résultat n’est pas un masque de boutons.
Conditions et limites
Masques communs : BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Un bit à 1 indique un bouton maintenu. Ce format s’applique à input_* sur GB et FC ; les lectures brutes FC utilisent un autre ordre.
Les fonctions de consultation lisent le dernier input_update() sans relire le contrôleur, consommer d’événement ni avancer les compteurs. Plusieurs consultations dans un même cycle donnent le même résultat. Deux appels à input_update() avec un bouton maintenu effacent son événement de nouvel appui au second appel.
Exemple d’utilisation
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++;
}Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme distingue le maintien d’un bouton, un nouvel appui, le relâchement et la répétition automatique. Maintenez A pendant 40 mises à jour, puis relâchez-le. FIRST DOWN, FIRST PRESS et FIRST REPEAT valent 1 ; FIRST CURRENT vaut 16. HELD TICKS vaut 40, PRESS COUNT vaut 1 et REPEAT COUNT vaut 5. Au relâchement, RELEASE vaut 1, LAST CURRENT vaut 0 et LAST PREVIOUS vaut 16. FAILED CHECKS doit valoir 0. Une autre durée modifie les compteurs ; le programme vérifie les intervalles de répétition selon la durée réellement observée.


Commande de compilation
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-cacheImplémentation et source
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
Renvoie le masque des boutons maintenus avant la dernière mise à jour.
Syntaxe
u8 input_previous();Valeur renvoyée
Un masque de 8 bits au format commun BTN_*. Plusieurs boutons peuvent être présents simultanément ; 0 signifie aucun.
Conditions et limites
Masques communs : BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Un bit à 1 indique un bouton maintenu. Ce format s’applique à input_* sur GB et FC ; les lectures brutes FC utilisent un autre ordre.
Les fonctions de consultation lisent le dernier input_update() sans relire le contrôleur, consommer d’événement ni avancer les compteurs. Plusieurs consultations dans un même cycle donnent le même résultat. Deux appels à input_update() avec un bouton maintenu effacent son événement de nouvel appui au second appel.
Exemple d’utilisation
first_previous=input_previous(); // No buttons in the preceding sample: 0.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme distingue le maintien d’un bouton, un nouvel appui, le relâchement et la répétition automatique. Maintenez A pendant 40 mises à jour, puis relâchez-le. FIRST DOWN, FIRST PRESS et FIRST REPEAT valent 1 ; FIRST CURRENT vaut 16. HELD TICKS vaut 40, PRESS COUNT vaut 1 et REPEAT COUNT vaut 5. Au relâchement, RELEASE vaut 1, LAST CURRENT vaut 0 et LAST PREVIOUS vaut 16. FAILED CHECKS doit valoir 0. Une autre durée modifie les compteurs ; le programme vérifie les intervalles de répétition selon la durée réellement observée.


Commande de compilation
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-cacheImplémentation et source
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
Détecte un relâchement pour un bouton du masque lors de la dernière mise à jour.
Syntaxe
u8 input_released(u8 mask);Paramètres
maskUn masque
BTN_*, ou plusieurs combinés avec|. Un seul bouton correspondant suffit ;BTN_A | BTN_Bn’exige pas les deux. Le masque 0 renvoie toujours 0. Pour vérifier que tous sont maintenus, comparez(input_current() & mask) == mask.
Valeur renvoyée
Renvoie exactement 1 si un bouton sélectionné remplit la condition, sinon 0. Le résultat n’est pas un masque de boutons.
Conditions et limites
Masques communs : BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Un bit à 1 indique un bouton maintenu. Ce format s’applique à input_* sur GB et FC ; les lectures brutes FC utilisent un autre ordre.
Les fonctions de consultation lisent le dernier input_update() sans relire le contrôleur, consommer d’événement ni avancer les compteurs. Plusieurs consultations dans un même cycle donnent le même résultat. Deux appels à input_update() avec un bouton maintenu effacent son événement de nouvel appui au second appel.
Exemple d’utilisation
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;
}Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme distingue le maintien d’un bouton, un nouvel appui, le relâchement et la répétition automatique. Maintenez A pendant 40 mises à jour, puis relâchez-le. FIRST DOWN, FIRST PRESS et FIRST REPEAT valent 1 ; FIRST CURRENT vaut 16. HELD TICKS vaut 40, PRESS COUNT vaut 1 et REPEAT COUNT vaut 5. Au relâchement, RELEASE vaut 1, LAST CURRENT vaut 0 et LAST PREVIOUS vaut 16. FAILED CHECKS doit valoir 0. Une autre durée modifie les compteurs ; le programme vérifie les intervalles de répétition selon la durée réellement observée.


Commande de compilation
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-cacheImplémentation et source
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
Détecte un premier appui ou une impulsion de répétition pour un bouton du masque.
Syntaxe
u8 input_repeat(u8 mask);Paramètres
maskUn masque
BTN_*, ou plusieurs combinés avec|. Un seul bouton correspondant suffit ;BTN_A | BTN_Bn’exige pas les deux. Le masque 0 renvoie toujours 0. Pour vérifier que tous sont maintenus, comparez(input_current() & mask) == mask.
Valeur renvoyée
Renvoie exactement 1 si un bouton sélectionné remplit la condition, sinon 0. Le résultat n’est pas un masque de boutons.
Conditions et limites
Masques communs : BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Un bit à 1 indique un bouton maintenu. Ce format s’applique à input_* sur GB et FC ; les lectures brutes FC utilisent un autre ordre.
Les fonctions de consultation lisent le dernier input_update() sans relire le contrôleur, consommer d’événement ni avancer les compteurs. Plusieurs consultations dans un même cycle donnent le même résultat. Deux appels à input_update() avec un bouton maintenu effacent son événement de nouvel appui au second appel.
Les délais se comptent en mises à jour, pas en millisecondes. Un nouvel appui produit un événement immédiat. Avec INPUT_REPEAT_DELAY=18 et INPUT_REPEAT_RATE=5, le suivant arrive 19 mises à jour plus tard, puis tous les 6 appels. Chaque bouton a son compteur. Appliquez les mêmes macros lors de la compilation de input.c ; modifier seulement l’en-tête du code appelant ne reconfigure pas la bibliothèque.
Exemple d’utilisation
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.
}Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme distingue le maintien d’un bouton, un nouvel appui, le relâchement et la répétition automatique. Maintenez A pendant 40 mises à jour, puis relâchez-le. FIRST DOWN, FIRST PRESS et FIRST REPEAT valent 1 ; FIRST CURRENT vaut 16. HELD TICKS vaut 40, PRESS COUNT vaut 1 et REPEAT COUNT vaut 5. Au relâchement, RELEASE vaut 1, LAST CURRENT vaut 0 et LAST PREVIOUS vaut 16. FAILED CHECKS doit valoir 0. Une autre durée modifie les compteurs ; le programme vérifie les intervalles de répétition selon la durée réellement observée.


Commande de compilation
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-cacheImplémentation et source
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
Mémorise le masque courant comme état précédent, lit les boutons du Game Boy avec __readpadex, calcule les relâchements et avance un compteur indépendant par bouton. Appelez-la une fois par cycle d’entrée avant de consulter l’état mémorisé.
Syntaxe
void input_update();Valeur renvoyée
Aucune (void).
Conditions et limites
Masques communs : BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Un bit à 1 indique un bouton maintenu. Ce format s’applique à input_* sur GB et FC ; les lectures brutes FC utilisent un autre ordre.
Les délais se comptent en mises à jour, pas en millisecondes. Un nouvel appui produit un événement immédiat. Avec INPUT_REPEAT_DELAY=18 et INPUT_REPEAT_RATE=5, le suivant arrive 19 mises à jour plus tard, puis tous les 6 appels. Chaque bouton a son compteur. Appliquez les mêmes macros lors de la compilation de input.c ; modifier seulement l’en-tête du code appelant ne reconfigure pas la bibliothèque.
Exemple d’utilisation
input_update(); // One update per input tick, followed by any number of queries.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Ce programme distingue le maintien d’un bouton, un nouvel appui, le relâchement et la répétition automatique. Maintenez A pendant 40 mises à jour, puis relâchez-le. FIRST DOWN, FIRST PRESS et FIRST REPEAT valent 1 ; FIRST CURRENT vaut 16. HELD TICKS vaut 40, PRESS COUNT vaut 1 et REPEAT COUNT vaut 5. Au relâchement, RELEASE vaut 1, LAST CURRENT vaut 0 et LAST PREVIOUS vaut 16. FAILED CHECKS doit valoir 0. Une autre durée modifie les compteurs ; le programme vérifie les intervalles de répétition selon la durée réellement observée.


Commande de compilation
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-cacheImplémentation et source
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 — Communication série et paquets logiques
La bibliothèque propose trois niveaux : échanges d’octets, paquets jusqu’à 24 octets et files par correspondant. Commencez par BYTE MASTER/SLAVE, puis PACKET, puis LINK4 pour comprendre la source d’horloge et la disponibilité des données reçues. Incluez exactement une fois dans le programme l’unité des registres matériels, link.c et link_packet.c ; gb_link_example.h fournit cet ordre.
Link4 gère l’emplacement logique hôte 0 et les correspondants 1 à 3. SelectPeer n’envoie aucune commande modifiant le câblage physique. La topologie link4 de KOKURA suit le correspondant sélectionné via les métadonnées du compilateur. Utilisez LinkDmg07 pour le protocole de l’adaptateur physique DMG-07.
Continuez à interroger les deux extrémités. Le délai expire après 90 appels sans progression, pas après un nombre d’images matérielles. Envoyer 0xFF uniquement pour fournir l’horloge d’un ACK ne repousse pas cette échéance ; au plus trois tentatives sont permises. Les retransmissions peuvent livrer des doublons : ajoutez des identifiants applicatifs si une commande doit s’exécuter exactement une fois.
Link4_BeginTransferTo
Sélectionne une destination, puis démarre un échange d’octet.
Syntaxe
u8 __stackcall Link4_BeginTransferTo(u8 peer_slot, u8 out);Paramètres
peer_slotEmplacement distant configuré : de 1 à slot_count−1 depuis l’hôte, ou 0 depuis un correspondant.
outValeur sortante sur huit bits.
Valeur renvoyée
Renvoie la première erreur de sélection ou de démarrage, ou 0 en cas de succès.
Conditions et limites
Link4 gère l’emplacement logique hôte 0 et les correspondants 1 à 3. SelectPeer n’envoie aucune commande modifiant le câblage physique. La topologie link4 de KOKURA suit le correspondant sélectionné via les métadonnées du compilateur. Utilisez LinkDmg07 pour le protocole de l’adaptateur physique DMG-07.
Codes d’erreur : 0=aucune, 1=occupé, 2=expiration du délai, 3=débordement en réception, 4=configuration/protocole invalide, 5=expiration ACK avec une réponse évoquant une déconnexion. Les appels de démarrage/configuration réussissent avec 0 ; ceux de réception/extraction avec 1. Un appel réussi n’efface pas une erreur mémorisée.
Link4 copie chaque octet reçu dans le tampon général et dans un tampon propre au correspondant. Lire l’un ne vide pas l’autre. L’interrogation des paquets consomme le tampon général ; éliminez aussi régulièrement les octets bruts inutilisés des tampons par correspondant pour éviter un débordement.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[6+slot]=Link4_BeginTransferTo(slot,16+slot);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Reliez les quatre ROM avec la topologie link4 de KOKURA. L’hôte reçoit 161/162/163 des correspondants 1/2/3 et affiche LAST PEER=3. Il envoie ensuite les commandes 65/66/67 avec les données 7/42/255 ; vérifiez aussi ces valeurs sur l’écran de chaque correspondant.


Commande de compilation
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.pngImplémentation et source
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
Lit le correspondant attribué au dernier octet reçu complètement.
Syntaxe
u8 Link4_GetLastRxPeer();Valeur renvoyée
L’hôte renvoie le correspondant sélectionné et un correspondant renvoie 0 ; avant toute réception, renvoie 255.
Conditions et limites
Link4 gère l’emplacement logique hôte 0 et les correspondants 1 à 3. SelectPeer n’envoie aucune commande modifiant le câblage physique. La topologie link4 de KOKURA suit le correspondant sélectionné via les métadonnées du compilateur. Utilisez LinkDmg07 pour le protocole de l’adaptateur physique DMG-07.
Ces fonctions lisent la configuration et l’historique. Elles ne détectent pas les connexions physiques, n’interrogent pas tous les correspondants et n’attendent pas la fin des transferts.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[19]=Link4_GetLastRxPeer();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Reliez les quatre ROM avec la topologie link4 de KOKURA. L’hôte reçoit 161/162/163 des correspondants 1/2/3 et affiche LAST PEER=3. Il envoie ensuite les commandes 65/66/67 avec les données 7/42/255 ; vérifiez aussi ces valeurs sur l’écran de chaque correspondant.


Commande de compilation
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.pngImplémentation et source
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
Lit la destination mémorisée au début du dernier transfert d’octet.
Syntaxe
u8 Link4_GetLastTxPeer();Valeur renvoyée
Renvoie la destination mémorisée, ou 255 avant tout démarrage.
Conditions et limites
Link4 gère l’emplacement logique hôte 0 et les correspondants 1 à 3. SelectPeer n’envoie aucune commande modifiant le câblage physique. La topologie link4 de KOKURA suit le correspondant sélectionné via les métadonnées du compilateur. Utilisez LinkDmg07 pour le protocole de l’adaptateur physique DMG-07.
Ces fonctions lisent la configuration et l’historique. Elles ne détectent pas les connexions physiques, n’interrogent pas tous les correspondants et n’attendent pas la fin des transferts.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[20]=Link4_GetLastTxPeer();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Reliez les quatre ROM avec la topologie link4 de KOKURA. L’hôte reçoit 161/162/163 des correspondants 1/2/3 et affiche LAST PEER=3. Il envoie ensuite les commandes 65/66/67 avec les données 7/42/255 ; vérifiez aussi ces valeurs sur l’écran de chaque correspondant.


Commande de compilation
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.pngImplémentation et source
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
Lit l’emplacement configuré de cette machine.
Syntaxe
u8 Link4_GetLocalSlot();Valeur renvoyée
L’hôte vaut 0, les correspondants 1 à 3. L’état non configuré renvoie aussi 0.
Conditions et limites
Link4 gère l’emplacement logique hôte 0 et les correspondants 1 à 3. SelectPeer n’envoie aucune commande modifiant le câblage physique. La topologie link4 de KOKURA suit le correspondant sélectionné via les métadonnées du compilateur. Utilisez LinkDmg07 pour le protocole de l’adaptateur physique DMG-07.
Ces fonctions lisent la configuration et l’historique. Elles ne détectent pas les connexions physiques, n’interrogent pas tous les correspondants et n’attendent pas la fin des transferts.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[2]=Link4_GetLocalSlot();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Reliez les quatre ROM avec la topologie link4 de KOKURA. L’hôte reçoit 161/162/163 des correspondants 1/2/3 et affiche LAST PEER=3. Il envoie ensuite les commandes 65/66/67 avec les données 7/42/255 ; vérifiez aussi ces valeurs sur l’écran de chaque correspondant.


Commande de compilation
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.pngImplémentation et source
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
Lit le rôle logique configuré.
Syntaxe
u8 Link4_GetMode();Valeur renvoyée
0=non configuré, 1=hôte, 2=correspondant.
Conditions et limites
Link4 gère l’emplacement logique hôte 0 et les correspondants 1 à 3. SelectPeer n’envoie aucune commande modifiant le câblage physique. La topologie link4 de KOKURA suit le correspondant sélectionné via les métadonnées du compilateur. Utilisez LinkDmg07 pour le protocole de l’adaptateur physique DMG-07.
Ces fonctions lisent la configuration et l’historique. Elles ne détectent pas les connexions physiques, n’interrogent pas tous les correspondants et n’attendent pas la fin des transferts.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[1]=Link4_GetMode();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Reliez les quatre ROM avec la topologie link4 de KOKURA. L’hôte reçoit 161/162/163 des correspondants 1/2/3 et affiche LAST PEER=3. Il envoie ensuite les commandes 65/66/67 avec les données 7/42/255 ; vérifiez aussi ces valeurs sur l’écran de chaque correspondant.


Commande de compilation
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.pngImplémentation et source
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
Lit la destination logique actuellement sélectionnée.
Syntaxe
u8 Link4_GetSelectedPeer();Valeur renvoyée
L’hôte renvoie le correspondant sélectionné ; un correspondant renvoie 0 ; non configuré renvoie 255.
Conditions et limites
Link4 gère l’emplacement logique hôte 0 et les correspondants 1 à 3. SelectPeer n’envoie aucune commande modifiant le câblage physique. La topologie link4 de KOKURA suit le correspondant sélectionné via les métadonnées du compilateur. Utilisez LinkDmg07 pour le protocole de l’adaptateur physique DMG-07.
Ces fonctions lisent la configuration et l’historique. Elles ne détectent pas les connexions physiques, n’interrogent pas tous les correspondants et n’attendent pas la fin des transferts.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[4]=Link4_GetSelectedPeer();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Reliez les quatre ROM avec la topologie link4 de KOKURA. L’hôte reçoit 161/162/163 des correspondants 1/2/3 et affiche LAST PEER=3. Il envoie ensuite les commandes 65/66/67 avec les données 7/42/255 ; vérifiez aussi ces valeurs sur l’écran de chaque correspondant.


Commande de compilation
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.pngImplémentation et source
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
Lit le nombre total d’emplacements configuré.
Syntaxe
u8 Link4_GetSlotCount();Valeur renvoyée
Une configuration valide renvoie 2 à 4 ; non configuré renvoie 0.
Conditions et limites
Link4 gère l’emplacement logique hôte 0 et les correspondants 1 à 3. SelectPeer n’envoie aucune commande modifiant le câblage physique. La topologie link4 de KOKURA suit le correspondant sélectionné via les métadonnées du compilateur. Utilisez LinkDmg07 pour le protocole de l’adaptateur physique DMG-07.
Ces fonctions lisent la configuration et l’historique. Elles ne détectent pas les connexions physiques, n’interrogent pas tous les correspondants et n’attendent pas la fin des transferts.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[3]=Link4_GetSlotCount();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Reliez les quatre ROM avec la topologie link4 de KOKURA. L’hôte reçoit 161/162/163 des correspondants 1/2/3 et affiche LAST PEER=3. Il envoie ensuite les commandes 65/66/67 avec les données 7/42/255 ; vérifiez aussi ces valeurs sur l’écran de chaque correspondant.


Commande de compilation
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.pngImplémentation et source
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
Vérifie les données non lues du tampon de réception d’un correspondant.
Syntaxe
u8 __stackcall Link4_HasByteFrom(u8 peer_slot);Paramètres
peer_slotEmplacement distant configuré : de 1 à slot_count−1 depuis l’hôte, ou 0 depuis un correspondant.
Valeur renvoyée
Renvoie 1 si des données sont en file, 0 si vide ou si le correspondant est invalide.
Conditions et limites
Le tampon circulaire de réception de huit entrées contient sept octets utiles. S’il est plein, le nouvel octet est abandonné et l’erreur 3 est mémorisée. Un octet reçu de valeur zéro est une donnée valide.
Link4 copie chaque octet reçu dans le tampon général et dans un tampon propre au correspondant. Lire l’un ne vide pas l’autre. L’interrogation des paquets consomme le tampon général ; éliminez aussi régulièrement les octets bruts inutilisés des tampons par correspondant pour éviter un débordement.
Cette requête n’interroge pas le matériel ; un correspondant invalide ne modifie pas l’erreur mémorisée.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[9+slot]=Link4_HasByteFrom(slot);value=0;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Reliez les quatre ROM avec la topologie link4 de KOKURA. L’hôte reçoit 161/162/163 des correspondants 1/2/3 et affiche LAST PEER=3. Il envoie ensuite les commandes 65/66/67 avec les données 7/42/255 ; vérifiez aussi ces valeurs sur l’écran de chaque correspondant.


Commande de compilation
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.pngImplémentation et source
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
Consulte la boîte des paquets terminés d’un emplacement distant.
Syntaxe
u8 __stackcall Link4_HasPacketFrom(u8 peer_slot);Paramètres
peer_slotEmplacement distant configuré : de 1 à slot_count−1 depuis l’hôte, ou 0 depuis un correspondant.
Valeur renvoyée
Renvoie 1 pour un paquet non lu, 0 si vide ou si le correspondant est invalide.
Conditions et limites
Link4 gère l’emplacement logique hôte 0 et les correspondants 1 à 3. SelectPeer n’envoie aucune commande modifiant le câblage physique. La topologie link4 de KOKURA suit le correspondant sélectionné via les métadonnées du compilateur. Utilisez LinkDmg07 pour le protocole de l’adaptateur physique DMG-07.
Un paquet contient 0xA5, la commande, la longueur, 0 à 24 octets utiles et une somme de contrôle XOR. La réponse est 0x79 (ACK, accepté) ou 0x1F (NAK, refusé). Le contrôle combine par XOR la commande, la longueur et les données utiles. Chaque machine possède une boîte de réception de paquets partagée ; Link4 en ajoute une par correspondant.
Cette requête n’interroge pas le matériel ; un correspondant invalide ne modifie pas l’erreur mémorisée.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[9]=Link4_HasPacketFrom(0);result[10]=Link4_ReadPacketFrom(0,&cmd,&len,data);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Pour le correspondant 1 parmi quatre emplacements, les valeurs attendues sont HOST BYTE=17, COMMAND=65, LENGTH=3 et PAYLOAD 2=42. CONSUMED=0 est l’indicateur de la boîte de l’hôte après consommation.


Commande de compilation
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.pngImplémentation et source
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
Initialise un hôte logique de deux à quatre emplacements et sélectionne le correspondant 1.
Syntaxe
u8 __stackcall Link4_InitHost(u8 slot_count);Paramètres
slot_countNombre d’emplacements, hôte compris, de 2 à 4.
Valeur renvoyée
Renvoie 0 pour une configuration valide, 4 pour un nombre d’emplacements invalide.
Conditions et limites
L’initialisation supprime les files d’octets, les paquets, la sélection du correspondant et les erreurs, puis désactive le transfert et la source IRQ série. Un échange en cours n’est pas conservé.
Link4 gère l’emplacement logique hôte 0 et les correspondants 1 à 3. SelectPeer n’envoie aucune commande modifiant le câblage physique. La topologie link4 de KOKURA suit le correspondant sélectionné via les métadonnées du compilateur. Utilisez LinkDmg07 pour le protocole de l’adaptateur physique DMG-07.
Les sections critiques internes suivent leur profondeur d’imbrication logicielle. Sortir de la section la plus externe active les interruptions CPU ; ne supposez donc pas qu’un état IME précédemment désactivé sera conservé.
L’initialisation précède la validation. Même un appel échoué supprime l’ancienne topologie et les données non lues.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[0]=Link4_InitHost(4);result[1]=Link4_GetMode();result[2]=Link4_GetLocalSlot();result[3]=Link4_GetSlotCount();result[4]=Link4_GetSelectedPeer();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Reliez les quatre ROM avec la topologie link4 de KOKURA. L’hôte reçoit 161/162/163 des correspondants 1/2/3 et affiche LAST PEER=3. Il envoie ensuite les commandes 65/66/67 avec les données 7/42/255 ; vérifiez aussi ces valeurs sur l’écran de chaque correspondant.


Commande de compilation
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.pngImplémentation et source
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
Initialise un correspondant à horloge externe et sélectionne l’emplacement hôte 0.
Syntaxe
u8 __stackcall Link4_InitPeer(u8 local_slot, u8 slot_count);Paramètres
local_slotEmplacement local, de 1 à slot_count−1.
slot_countNombre total d’emplacements, hôte compris, de 2 à 4.
Valeur renvoyée
Renvoie 0 pour une configuration valide, 4 pour un nombre d’emplacements ou un emplacement local invalide.
Conditions et limites
L’initialisation supprime les files d’octets, les paquets, la sélection du correspondant et les erreurs, puis désactive le transfert et la source IRQ série. Un échange en cours n’est pas conservé.
Link4 gère l’emplacement logique hôte 0 et les correspondants 1 à 3. SelectPeer n’envoie aucune commande modifiant le câblage physique. La topologie link4 de KOKURA suit le correspondant sélectionné via les métadonnées du compilateur. Utilisez LinkDmg07 pour le protocole de l’adaptateur physique DMG-07.
Les sections critiques internes suivent leur profondeur d’imbrication logicielle. Sortir de la section la plus externe active les interruptions CPU ; ne supposez donc pas qu’un état IME précédemment désactivé sera conservé.
L’initialisation précède la validation. Même un appel échoué supprime l’ancienne topologie et les données non lues.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[0]=Link4_InitPeer(1,4);result[1]=Link4_GetMode();result[2]=Link4_GetLocalSlot();result[3]=Link4_GetSlotCount();result[4]=Link4_GetSelectedPeer();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Pour le correspondant 1 parmi quatre emplacements, les valeurs attendues sont HOST BYTE=17, COMMAND=65, LENGTH=3 et PAYLOAD 2=42. CONSUMED=0 est l’indicateur de la boîte de l’hôte après consommation.


Commande de compilation
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.pngImplémentation et source
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
Fait avancer une fois le moteur de paquets partagé pour le correspondant sélectionné.
Syntaxe
void Link4_PollPacket();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Link4 gère l’emplacement logique hôte 0 et les correspondants 1 à 3. SelectPeer n’envoie aucune commande modifiant le câblage physique. La topologie link4 de KOKURA suit le correspondant sélectionné via les métadonnées du compilateur. Utilisez LinkDmg07 pour le protocole de l’adaptateur physique DMG-07.
Un paquet contient 0xA5, la commande, la longueur, 0 à 24 octets utiles et une somme de contrôle XOR. La réponse est 0x79 (ACK, accepté) ou 0x1F (NAK, refusé). Le contrôle combine par XOR la commande, la longueur et les données utiles. Chaque machine possède une boîte de réception de paquets partagée ; Link4 en ajoute une par correspondant.
Continuez à interroger les deux extrémités. Le délai expire après 90 appels sans progression, pas après un nombre d’images matérielles. Envoyer 0xFF uniquement pour fournir l’horloge d’un ACK ne repousse pas cette échéance ; au plus trois tentatives sont permises. Les retransmissions peuvent livrer des doublons : ajoutez des identifiants applicatifs si une commande doit s’exécuter exactement une fois.
Link4 copie chaque octet reçu dans le tampon général et dans un tampon propre au correspondant. Lire l’un ne vide pas l’autre. L’interrogation des paquets consomme le tampon général ; éliminez aussi régulièrement les octets bruts inutilisés des tampons par correspondant pour éviter un débordement.
Ne parcourt pas tous les emplacements en rotation. Ne changez de correspondant qu’après la fin de l’échange, lorsque la sélection est autorisée.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
for(i=0;i<50;i++){Link4_PollPacket();while(Link4_TryReadByteFrom(slot,0)){}m_wait();}Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Reliez les quatre ROM avec la topologie link4 de KOKURA. L’hôte reçoit 161/162/163 des correspondants 1/2/3 et affiche LAST PEER=3. Il envoie ensuite les commandes 65/66/67 avec les données 7/42/255 ; vérifiez aussi ces valeurs sur l’écran de chaque correspondant.


Commande de compilation
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.pngImplémentation et source
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
Copie un paquet du correspondant indiqué et le retire de sa boîte.
Syntaxe
u8 __stackcall Link4_ReadPacketFrom(u8 peer_slot, u8 *cmd, u8 *len, u8 *dst);Paramètres
peer_slotEmplacement distant configuré : de 1 à slot_count−1 depuis l’hôte, ou 0 depuis un correspondant.
cmdOctet de commande inscriptible ; null omet cette sortie.
lenOctet de longueur inscriptible, de 0 à 24 ; null omet cette sortie.
dstTampon de données utiles inscriptible d’au moins 24 octets ; null abandonne les données utiles.
Valeur renvoyée
Renvoie 1 si consommé, 0 si vide ou si le correspondant est invalide.
Conditions et limites
Il n’y a pas de paramètre de capacité de destination. Fournissez 24 octets inscriptibles si vous utilisez dst. cmd, len et dst peuvent être nuls indépendamment. Sérialisez l’inspection et la consommation de la boîte de réception par rapport aux autres codes et aux interruptions.
Vide la boîte partagée uniquement si elle désigne le paquet de ce même correspondant. Les paquets non lus des autres correspondants restent disponibles.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[9]=Link4_HasPacketFrom(0);result[10]=Link4_ReadPacketFrom(0,&cmd,&len,data);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Pour le correspondant 1 parmi quatre emplacements, les valeurs attendues sont HOST BYTE=17, COMMAND=65, LENGTH=3 et PAYLOAD 2=42. CONSUMED=0 est l’indicateur de la boîte de l’hôte après consommation.


Commande de compilation
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.pngImplémentation et source
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
Interroge la fin du transfert et ne change la destination logique qu’à l’état inactif.
Syntaxe
u8 __stackcall Link4_SelectPeer(u8 peer_slot);Paramètres
peer_slotEmplacement distant configuré : de 1 à slot_count−1 depuis l’hôte, ou 0 depuis un correspondant.
Valeur renvoyée
Renvoie 0 après sélection, 1 si l’état octet/paquet/ACK est occupé, ou 4 si non configuré ou si le correspondant est invalide.
Conditions et limites
Link4 gère l’emplacement logique hôte 0 et les correspondants 1 à 3. SelectPeer n’envoie aucune commande modifiant le câblage physique. La topologie link4 de KOKURA suit le correspondant sélectionné via les métadonnées du compilateur. Utilisez LinkDmg07 pour le protocole de l’adaptateur physique DMG-07.
Codes d’erreur : 0=aucune, 1=occupé, 2=expiration du délai, 3=débordement en réception, 4=configuration/protocole invalide, 5=expiration ACK avec une réponse évoquant une déconnexion. Les appels de démarrage/configuration réussissent avec 0 ; ceux de réception/extraction avec 1. Un appel réussi n’efface pas une erreur mémorisée.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[25]=Link4_SelectPeer(1);result[26]=Link_LastError();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Reliez les quatre ROM avec la topologie link4 de KOKURA. L’hôte reçoit 161/162/163 des correspondants 1/2/3 et affiche LAST PEER=3. Il envoie ensuite les commandes 65/66/67 avec les données 7/42/255 ; vérifiez aussi ces valeurs sur l’écran de chaque correspondant.


Commande de compilation
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.pngImplémentation et source
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
Sélectionne un correspondant logique, copie le paquet et programme son envoi.
Syntaxe
u8 __stackcall Link4_SendPacketTo(u8 peer_slot, const u8 *data, u8 len, u8 cmd);Paramètres
peer_slotEmplacement distant configuré : de 1 à slot_count−1 depuis l’hôte, ou 0 depuis un correspondant.
dataSource lisible sur len octets ; peut être nulle uniquement si len vaut zéro.
lenLongueur des données utiles en octets, de 0 à 24.
cmdCommande sur huit bits définie par l’application.
Valeur renvoyée
Renvoie la première erreur de sélection ou de mise en file ; 0 signifie accepté.
Conditions et limites
Link4 gère l’emplacement logique hôte 0 et les correspondants 1 à 3. SelectPeer n’envoie aucune commande modifiant le câblage physique. La topologie link4 de KOKURA suit le correspondant sélectionné via les métadonnées du compilateur. Utilisez LinkDmg07 pour le protocole de l’adaptateur physique DMG-07.
Codes d’erreur : 0=aucune, 1=occupé, 2=expiration du délai, 3=débordement en réception, 4=configuration/protocole invalide, 5=expiration ACK avec une réponse évoquant une déconnexion. Les appels de démarrage/configuration réussissent avec 0 ; ceux de réception/extraction avec 1. Un appel réussi n’efface pas une erreur mémorisée.
Un paquet contient 0xA5, la commande, la longueur, 0 à 24 octets utiles et une somme de contrôle XOR. La réponse est 0x79 (ACK, accepté) ou 0x1F (NAK, refusé). Le contrôle combine par XOR la commande, la longueur et les données utiles. Chaque machine possède une boîte de réception de paquets partagée ; Link4 en ajoute une par correspondant.
Continuez à interroger les deux extrémités. Le délai expire après 90 appels sans progression, pas après un nombre d’images matérielles. Envoyer 0xFF uniquement pour fournir l’horloge d’un ACK ne repousse pas cette échéance ; au plus trois tentatives sont permises. Les retransmissions peuvent livrer des doublons : ajoutez des identifiants applicatifs si une commande doit s’exécuter exactement une fois.
Link4 copie chaque octet reçu dans le tampon général et dans un tampon propre au correspondant. Lire l’un ne vide pas l’autre. L’interrogation des paquets consomme le tampon général ; éliminez aussi régulièrement les octets bruts inutilisés des tampons par correspondant pour éviter un débordement.
La sélection précède la validation des données utiles ; même si elles sont refusées, la nouvelle destination peut rester sélectionnée.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[21+slot]=Link4_SendPacketTo(slot,data,3,64+slot);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Reliez les quatre ROM avec la topologie link4 de KOKURA. L’hôte reçoit 161/162/163 des correspondants 1/2/3 et affiche LAST PEER=3. Il envoie ensuite les commandes 65/66/67 avec les données 7/42/255 ; vérifiez aussi ces valeurs sur l’écran de chaque correspondant.


Commande de compilation
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.pngImplémentation et source
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
Parcourt les emplacements distants par ordre croissant et extrait le premier octet disponible.
Syntaxe
u8 __stackcall Link4_TryReadByteAny(u8 *peer_slot, u8 *out);Paramètres
peer_slotOctet inscriptible pour l’emplacement d’origine ; null omet cette sortie.
outDestination d’un octet inscriptible ; null abandonne l’octet.
Valeur renvoyée
Renvoie 1 à la réception, sinon 0.
Conditions et limites
Le tampon circulaire de réception de huit entrées contient sept octets utiles. S’il est plein, le nouvel octet est abandonné et l’erreur 3 est mémorisée. Un octet reçu de valeur zéro est une donnée valide.
Link4 copie chaque octet reçu dans le tampon général et dans un tampon propre au correspondant. Lire l’un ne vide pas l’autre. L’interrogation des paquets consomme le tampon général ; éliminez aussi régulièrement les octets bruts inutilisés des tampons par correspondant pour éviter un débordement.
Les sections critiques internes suivent leur profondeur d’imbrication logicielle. Sortir de la section la plus externe active les interruptions CPU ; ne supposez donc pas qu’un état IME précédemment désactivé sera conservé.
Ignore l’emplacement local. Les emplacements de numéro inférieur continuellement alimentés sont prioritaires ; utilisez les lectures par correspondant si un partage équitable en rotation est nécessaire.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
else {other=255;Link4_TryReadByteAny(&other,&value);result[12+slot]=other;}Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Reliez les quatre ROM avec la topologie link4 de KOKURA. L’hôte reçoit 161/162/163 des correspondants 1/2/3 et affiche LAST PEER=3. Il envoie ensuite les commandes 65/66/67 avec les données 7/42/255 ; vérifiez aussi ces valeurs sur l’écran de chaque correspondant.


Commande de compilation
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.pngImplémentation et source
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
Extrait un octet du tampon de réception du correspondant indiqué.
Syntaxe
u8 __stackcall Link4_TryReadByteFrom(u8 peer_slot, u8 *out);Paramètres
peer_slotEmplacement distant configuré : de 1 à slot_count−1 depuis l’hôte, ou 0 depuis un correspondant.
outDestination d’un octet inscriptible ; null abandonne l’octet.
Valeur renvoyée
Renvoie 1 après extraction ; si vide ou si le correspondant est invalide, renvoie 0 et conserve out.
Conditions et limites
Le tampon circulaire de réception de huit entrées contient sept octets utiles. S’il est plein, le nouvel octet est abandonné et l’erreur 3 est mémorisée. Un octet reçu de valeur zéro est une donnée valide.
Link4 copie chaque octet reçu dans le tampon général et dans un tampon propre au correspondant. Lire l’un ne vide pas l’autre. L’interrogation des paquets consomme le tampon général ; éliminez aussi régulièrement les octets bruts inutilisés des tampons par correspondant pour éviter un débordement.
Les sections critiques internes suivent leur profondeur d’imbrication logicielle. Sortir de la section la plus externe active les interruptions CPU ; ne supposez donc pas qu’un état IME précédemment désactivé sera conservé.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
if(slot==1)result[13]=Link4_TryReadByteFrom(slot,&value);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Reliez les quatre ROM avec la topologie link4 de KOKURA. L’hôte reçoit 161/162/163 des correspondants 1/2/3 et affiche LAST PEER=3. Il envoie ensuite les commandes 65/66/67 avec les données 7/42/255 ; vérifiez aussi ces valeurs sur l’écran de chaque correspondant.


Commande de compilation
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.pngImplémentation et source
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
Charge SB et démarre ou arme un échange d’octet en duplex intégral.
Syntaxe
u8 __stackcall Link_BeginTransfer(u8 out);Paramètres
outValeur sortante sur huit bits ; chaque échange envoie un octet, même si seule la réception vous intéresse.
Valeur renvoyée
Renvoie 0 si le transfert est démarré ou armé, et 1 s’il est déjà occupé.
Conditions et limites
Chaque machine possède un état de liaison partagé. Les échanges d’octets sont en duplex intégral : un côté fournit l’horloge interne, l’autre utilise l’horloge externe. La vitesse normale exige 512 cycles par bit ; la vitesse rapide CGB, 16.
Codes d’erreur : 0=aucune, 1=occupé, 2=expiration du délai, 3=débordement en réception, 4=configuration/protocole invalide, 5=expiration ACK avec une réponse évoquant une déconnexion. Les appels de démarrage/configuration réussissent avec 0 ; ceux de réception/extraction avec 1. Un appel réussi n’efface pas une erreur mémorisée.
Une extrémité à horloge externe attend les impulsions de l’autre côté. Un refus pour occupation ne remplace pas l’octet déjà en cours de transfert.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
lesson_delay(12);result[0]=Link_BeginTransfer(42);value=0;result[1]=Link_WaitByte(8,&value);result[2]=value;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Reliez-vous à BYTE SLAVE. Envoyez 42 et recevez 99, puis échangez zéro dans les deux sens. RECEIVED=1, PEER BYTE=99, ZERO READY=1 et ZERO BYTE=0 distinguent une donnée zéro valide d’une absence de données. Deux instances CGB utilisent l’horloge rapide pour le second échange.


Commande de compilation
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.pngImplémentation et source
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
Arrête le transfert d’octet actif ou en attente d’horloge externe.
Syntaxe
void Link_Cancel();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Les sections critiques internes suivent leur profondeur d’imbrication logicielle. Sortir de la section la plus externe active les interruptions CPU ; ne supposez donc pas qu’un état IME précédemment désactivé sera conservé.
Écrit SC=0 et efface les états d’occupation et de demande série. Les octets reçus, l’état des paquets et les erreurs sont conservés. Réinitialisez également si vous recommencez le protocole depuis le début.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
Link_Cancel();result[12]=Link_IsBusy();result[13]=(SC&128)!=0;Link_ClearError();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Vérifie l’initialisation, le refus lorsque la liaison est occupée, l’expiration avec horloge externe et la capacité du tampon. Valeurs attendues : BUSY ERROR=1, TIMEOUT=2, OPEN RX=255, OVERFLOW=3 et QUEUE BYTES=7. Après avoir observé IRQ REQUEST=1, la leçon appelle explicitement le corps du gestionnaire en maintenant la source IRQ série masquée.


Commande de compilation
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.pngImplémentation et source
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
Efface uniquement l’erreur mémorisée.
Syntaxe
void Link_ClearError();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Codes d’erreur : 0=aucune, 1=occupé, 2=expiration du délai, 3=débordement en réception, 4=configuration/protocole invalide, 5=expiration ACK avec une réponse évoquant une déconnexion. Les appels de démarrage/configuration réussissent avec 0 ; ceux de réception/extraction avec 1. Un appel réussi n’efface pas une erreur mémorisée.
Transferts, files et état des paquets restent inchangés. Utilisez Link_Cancel pour arrêter le transfert d’octet, ou réinitialisez pour supprimer tout l’état.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
Link_ClearError();result[8]=Link_LastError();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Vérifie l’initialisation, le refus lorsque la liaison est occupée, l’expiration avec horloge externe et la capacité du tampon. Valeurs attendues : BUSY ERROR=1, TIMEOUT=2, OPEN RX=255, OVERFLOW=3 et QUEUE BYTES=7. Après avoir observé IRQ REQUEST=1, la leçon appelle explicitement le corps du gestionnaire en maintenant la source IRQ série masquée.


Commande de compilation
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.pngImplémentation et source
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
Vérifie si le tampon circulaire général de réception contient des données non lues.
Syntaxe
u8 Link_HasByte();Valeur renvoyée
Renvoie 1 si des données sont en file, sinon 0.
Conditions et limites
Le tampon circulaire de réception de huit entrées contient sept octets utiles. S’il est plein, le nouvel octet est abandonné et l’erreur 3 est mémorisée. Un octet reçu de valeur zéro est une donnée valide.
N’interroge pas le matériel. Collectez d’abord le transfert terminé avec Link_Poll ou le gestionnaire série.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[1]=Link_HasByte();value=77;result[2]=Link_TryReadByte(&value);result[3]=value;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
BYTE MASTER fournit l’horloge. Valeurs attendues : PEER BYTE=42, ZERO READY=1 et ZERO BYTE=0. EMPTY READ vaut aussi zéro ensuite ; il faut donc l’état de disponibilité ou le résultat de TryRead pour reconnaître une file vide.


Commande de compilation
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.pngImplémentation et source
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
Consulte la boîte partagée des paquets entièrement reçus.
Syntaxe
u8 Link_HasPacket();Valeur renvoyée
Renvoie 1 pour un paquet non lu, sinon 0.
Conditions et limites
Un paquet contient 0xA5, la commande, la longueur, 0 à 24 octets utiles et une somme de contrôle XOR. La réponse est 0x79 (ACK, accepté) ou 0x1F (NAK, refusé). Le contrôle combine par XOR la commande, la longueur et les données utiles. Chaque machine possède une boîte de réception de paquets partagée ; Link4 en ajoute une par correspondant.
Lit un indicateur sans faire avancer le protocole. N’indique pas si l’émetteur a reçu son ACK.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[0]=Link_HasPacket();cmd=0;len=0;result[1]=Link_ReadPacket(&cmd,&len,data);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Connectez-vous à PACKET MASTER et vérifiez COMMAND=49, LENGTH=3 et les données 7/42/255. CONSUMED=0 après ReadPacket signifie que la boîte de réception est désormais vide.


Commande de compilation
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.pngImplémentation et source
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
Réinitialise l’état de liaison partagé à sa configuration par défaut avec horloge externe.
Syntaxe
void Link_InitCommon();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Chaque machine possède un état de liaison partagé. Les échanges d’octets sont en duplex intégral : un côté fournit l’horloge interne, l’autre utilise l’horloge externe. La vitesse normale exige 512 cycles par bit ; la vitesse rapide CGB, 16.
L’initialisation supprime les files d’octets, les paquets, la sélection du correspondant et les erreurs, puis désactive le transfert et la source IRQ série. Un échange en cours n’est pas conservé.
Les sections critiques internes suivent leur profondeur d’imbrication logicielle. Sortir de la section la plus externe active les interruptions CPU ; ne supposez donc pas qu’un état IME précédemment désactivé sera conservé.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
Link_InitCommon();result[0]=Link_IsBusy();result[1]=Link_HasByte();result[2]=Link_LastError();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Vérifie l’initialisation, le refus lorsque la liaison est occupée, l’expiration avec horloge externe et la capacité du tampon. Valeurs attendues : BUSY ERROR=1, TIMEOUT=2, OPEN RX=255, OVERFLOW=3 et QUEUE BYTES=7. Après avoir observé IRQ REQUEST=1, la leçon appelle explicitement le corps du gestionnaire en maintenant la source IRQ série masquée.


Commande de compilation
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.pngImplémentation et source
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
Réinitialise l’état et fait de cette machine la source d’horloge.
Syntaxe
void Link_InitMaster();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Chaque machine possède un état de liaison partagé. Les échanges d’octets sont en duplex intégral : un côté fournit l’horloge interne, l’autre utilise l’horloge externe. La vitesse normale exige 512 cycles par bit ; la vitesse rapide CGB, 16.
L’initialisation supprime les files d’octets, les paquets, la sélection du correspondant et les erreurs, puis désactive le transfert et la source IRQ série. Un échange en cours n’est pas conservé.
Les sections critiques internes suivent leur profondeur d’imbrication logicielle. Sortir de la section la plus externe active les interruptions CPU ; ne supposez donc pas qu’un état IME précédemment désactivé sera conservé.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
Link_InitMaster();Link_SetUseInterrupt(0);Link_SetFastClock(0);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Reliez-vous à BYTE SLAVE. Envoyez 42 et recevez 99, puis échangez zéro dans les deux sens. RECEIVED=1, PEER BYTE=99, ZERO READY=1 et ZERO BYTE=0 distinguent une donnée zéro valide d’une absence de données. Deux instances CGB utilisent l’horloge rapide pour le second échange.


Commande de compilation
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.pngImplémentation et source
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
Réinitialise l’état et sélectionne la communication avec horloge externe.
Syntaxe
void Link_InitSlave();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Chaque machine possède un état de liaison partagé. Les échanges d’octets sont en duplex intégral : un côté fournit l’horloge interne, l’autre utilise l’horloge externe. La vitesse normale exige 512 cycles par bit ; la vitesse rapide CGB, 16.
L’initialisation supprime les files d’octets, les paquets, la sélection du correspondant et les erreurs, puis désactive le transfert et la source IRQ série. Un échange en cours n’est pas conservé.
Les sections critiques internes suivent leur profondeur d’imbrication logicielle. Sortir de la section la plus externe active les interruptions CPU ; ne supposez donc pas qu’un état IME précédemment désactivé sera conservé.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
Link_InitSlave();result[0]=Link_BeginTransfer(99);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
BYTE MASTER fournit l’horloge. Valeurs attendues : PEER BYTE=42, ZERO READY=1 et ZERO BYTE=0. EMPTY READ vaut aussi zéro ensuite ; il faut donc l’état de disponibilité ou le résultat de TryRead pour reconnaître une file vide.


Commande de compilation
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.pngImplémentation et source
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
Interroge une fois la fin du transfert, puis indique si un échange reste actif.
Syntaxe
u8 Link_IsBusy();Valeur renvoyée
Renvoie 1 si occupé, sinon 0.
Conditions et limites
Le tampon circulaire de réception de huit entrées contient sept octets utiles. S’il est plein, le nouvel octet est abandonné et l’erreur 3 est mémorisée. Un octet reçu de valeur zéro est une donnée valide.
Ce n’est pas une requête passive : l’octet SB terminé est mis en file, ce qui peut modifier la disponibilité des données et l’état d’erreur.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[3]=Link_IsBusy();result[4]=Link_HasByte();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Reliez-vous à BYTE SLAVE. Envoyez 42 et recevez 99, puis échangez zéro dans les deux sens. RECEIVED=1, PEER BYTE=99, ZERO READY=1 et ZERO BYTE=0 distinguent une donnée zéro valide d’une absence de données. Deux instances CGB utilisent l’horloge rapide pour le second échange.


Commande de compilation
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.pngImplémentation et source
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
Lit la dernière erreur de liaison mémorisée sans l’effacer.
Syntaxe
u8 Link_LastError();Valeur renvoyée
Renvoie le code d’erreur actuel, de 0 à 5.
Conditions et limites
Codes d’erreur : 0=aucune, 1=occupé, 2=expiration du délai, 3=débordement en réception, 4=configuration/protocole invalide, 5=expiration ACK avec une réponse évoquant une déconnexion. Les appels de démarrage/configuration réussissent avec 0 ; ceux de réception/extraction avec 1. Un appel réussi n’efface pas une erreur mémorisée.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[2]=Link_LastError();Link_ClearError();result[3]=Link_LastError();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Envoyez la commande 49 avec les données 7/42/255, puis modifiez le tableau source. QUEUED=0 accepte l’envoi ; SECOND SEND=1 refuse un second démarrage. L’erreur d’occupation reste mémorisée jusqu’à ClearError. PAYLOAD 2=42 chez le destinataire prouve que les données en file sont une copie détenue par la bibliothèque.


Commande de compilation
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.pngImplémentation et source
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
Collecte un octet terminé depuis un gestionnaire ayant identifié une demande série.
Syntaxe
void Link_OnSerialIRQ();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Le tampon circulaire de réception de huit entrées contient sept octets utiles. S’il est plein, le nouvel octet est abandonné et l’erreur 3 est mémorisée. Un octet reçu de valeur zéro est une donnée valide.
Les sections critiques internes suivent leur profondeur d’imbrication logicielle. Sortir de la section la plus externe active les interruptions CPU ; ne supposez donc pas qu’un état IME précédemment désactivé sera conservé.
La fonction ne vérifie pas la fin du transfert dans SC. Ne l’appelez pas depuis une interruption de temporisateur sans rapport pendant un transfert série. Cet exemple appelle explicitement le corps après une véritable demande IF.serial, avec la source IRQ série CPU masquée ; il teste le corps, pas l’installation du vecteur.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
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;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Vérifie l’initialisation, le refus lorsque la liaison est occupée, l’expiration avec horloge externe et la capacité du tampon. Valeurs attendues : BUSY ERROR=1, TIMEOUT=2, OPEN RX=255, OVERFLOW=3 et QUEUE BYTES=7. Après avoir observé IRQ REQUEST=1, la leçon appelle explicitement le corps du gestionnaire en maintenant la source IRQ série masquée.


Commande de compilation
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.pngImplémentation et source
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
Collecte un transfert en cours uniquement après l’effacement du bit de démarrage de SC, puis met l’octet reçu en file.
Syntaxe
void Link_Poll();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Le tampon circulaire de réception de huit entrées contient sept octets utiles. S’il est plein, le nouvel octet est abandonné et l’erreur 3 est mémorisée. Un octet reçu de valeur zéro est une donnée valide.
L’appel ne bloque pas. Il ne fait rien si l’état logiciel est inactif et n’implémente aucun délai d’expiration.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
for(i=0;i<24;i++){Link_Poll();if(Link_HasByte())break;m_wait();}Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
BYTE MASTER fournit l’horloge. Valeurs attendues : PEER BYTE=42, ZERO READY=1 et ZERO BYTE=0. EMPTY READ vaut aussi zéro ensuite ; il faut donc l’état de disponibilité ou le résultat de TryRead pour reconnaître une file vide.


Commande de compilation
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.pngImplémentation et source
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
Analyse les octets reçus, démarre l’octet sortant ou l’ACK suivant et fait avancer l’état des délais et des tentatives.
Syntaxe
void Link_PollPacket();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Un paquet contient 0xA5, la commande, la longueur, 0 à 24 octets utiles et une somme de contrôle XOR. La réponse est 0x79 (ACK, accepté) ou 0x1F (NAK, refusé). Le contrôle combine par XOR la commande, la longueur et les données utiles. Chaque machine possède une boîte de réception de paquets partagée ; Link4 en ajoute une par correspondant.
Continuez à interroger les deux extrémités. Le délai expire après 90 appels sans progression, pas après un nombre d’images matérielles. Envoyer 0xFF uniquement pour fournir l’horloge d’un ACK ne repousse pas cette échéance ; au plus trois tentatives sont permises. Les retransmissions peuvent livrer des doublons : ajoutez des identifiants applicatifs si une commande doit s’exécuter exactement une fois.
Les lectures brutes de type ReadByte consomment le même tampon général et peuvent prélever une partie d’un paquet. Ne mélangez pas lectures brutes et réception de paquets.
Link4 copie chaque octet reçu dans le tampon général et dans un tampon propre au correspondant. Lire l’un ne vide pas l’autre. L’interrogation des paquets consomme le tampon général ; éliminez aussi régulièrement les octets bruts inutilisés des tampons par correspondant pour éviter un débordement.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
Link_InitSlave();for(i=0;i<120;i++){Link_PollPacket();m_wait();}Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Connectez-vous à PACKET MASTER et vérifiez COMMAND=49, LENGTH=3 et les données 7/42/255. CONSUMED=0 après ReadPacket signifie que la boîte de réception est désormais vide.


Commande de compilation
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.pngExemple d’utilisation
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();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Envoyez sans correspondant connecté. Les transferts d’octets se terminent avec l’horloge interne, mais aucun ACK n’arrive ; après les tentatives, NO ACK ERROR=5. Cancel laisse CANCEL BUSY=0.


Commande de compilation
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.pngImplémentation et source
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
Renvoie un octet extrait du tampon général de réception.
Syntaxe
u8 Link_ReadByte();Valeur renvoyée
Renvoie l’octet reçu ; une file vide renvoie aussi zéro.
Conditions et limites
Le tampon circulaire de réception de huit entrées contient sept octets utiles. S’il est plein, le nouvel octet est abandonné et l’erreur 3 est mémorisée. Un octet reçu de valeur zéro est une donnée valide.
Les sections critiques internes suivent leur profondeur d’imbrication logicielle. Sortir de la section la plus externe active les interruptions CPU ; ne supposez donc pas qu’un état IME précédemment désactivé sera conservé.
La valeur renvoyée seule ne distingue pas un zéro reçu d’une file vide. Utilisez l’indicateur de succès de TryReadByte ou HasByte avant de lire.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[6]=Link_HasByte();result[7]=Link_ReadByte();result[8]=Link_ReadByte();result[9]=Link_LastError();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
BYTE MASTER fournit l’horloge. Valeurs attendues : PEER BYTE=42, ZERO READY=1 et ZERO BYTE=0. EMPTY READ vaut aussi zéro ensuite ; il faut donc l’état de disponibilité ou le résultat de TryRead pour reconnaître une file vide.


Commande de compilation
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.pngImplémentation et source
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
Copie un paquet terminé et le retire de la boîte partagée.
Syntaxe
u8 __stackcall Link_ReadPacket(u8 *cmd, u8 *len, u8 *dst);Paramètres
cmdOctet de commande inscriptible ; null omet cette sortie.
lenOctet de longueur inscriptible, de 0 à 24 ; null omet cette sortie.
dstTampon de données utiles inscriptible d’au moins 24 octets ; null abandonne les données utiles.
Valeur renvoyée
Renvoie 1 si le paquet est consommé, 0 si la boîte est vide ; une lecture à vide ne modifie pas les sorties.
Conditions et limites
Il n’y a pas de paramètre de capacité de destination. Fournissez 24 octets inscriptibles si vous utilisez dst. cmd, len et dst peuvent être nuls indépendamment. Sérialisez l’inspection et la consommation de la boîte de réception par rapport aux autres codes et aux interruptions.
En mode Link4, vide aussi la boîte du correspondant associée à ce paquet partagé. Les boîtes des autres correspondants restent disponibles.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[0]=Link_HasPacket();cmd=0;len=0;result[1]=Link_ReadPacket(&cmd,&len,data);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Connectez-vous à PACKET MASTER et vérifiez COMMAND=49, LENGTH=3 et les données 7/42/255. CONSUMED=0 après ReadPacket signifie que la boîte de réception est désormais vide.


Commande de compilation
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.pngImplémentation et source
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
Copie les données utiles dans un stockage détenu par la bibliothèque et programme l’envoi du paquet.
Syntaxe
u8 __stackcall Link_SendPacket(const u8 *data, u8 len, u8 cmd);Paramètres
dataSource lisible sur len octets ; peut être nulle uniquement si len vaut zéro.
lenLongueur des données utiles en octets, de 0 à 24.
cmdCommande sur huit bits définie par l’application.
Valeur renvoyée
Renvoie 0 si accepté, 1 si l’état de paquet est occupé, ou 4 si la longueur ou le pointeur est invalide.
Conditions et limites
Codes d’erreur : 0=aucune, 1=occupé, 2=expiration du délai, 3=débordement en réception, 4=configuration/protocole invalide, 5=expiration ACK avec une réponse évoquant une déconnexion. Les appels de démarrage/configuration réussissent avec 0 ; ceux de réception/extraction avec 1. Un appel réussi n’efface pas une erreur mémorisée.
Un paquet contient 0xA5, la commande, la longueur, 0 à 24 octets utiles et une somme de contrôle XOR. La réponse est 0x79 (ACK, accepté) ou 0x1F (NAK, refusé). Le contrôle combine par XOR la commande, la longueur et les données utiles. Chaque machine possède une boîte de réception de paquets partagée ; Link4 en ajoute une par correspondant.
Continuez à interroger les deux extrémités. Le délai expire après 90 appels sans progression, pas après un nombre d’images matérielles. Envoyer 0xFF uniquement pour fournir l’horloge d’un ACK ne repousse pas cette échéance ; au plus trois tentatives sont permises. Les retransmissions peuvent livrer des doublons : ajoutez des identifiants applicatifs si une commande doit s’exécuter exactement une fois.
Zéro signifie mis en file, pas reçu ni acquitté par le correspondant. Le tableau source peut être réutilisé après acceptation.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[0]=Link_SendPacket(data,3,0x31);data[1]=0;result[1]=Link_SendPacket(data,3,0x32);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Envoyez la commande 49 avec les données 7/42/255, puis modifiez le tableau source. QUEUED=0 accepte l’envoi ; SECOND SEND=1 refuse un second démarrage. L’erreur d’occupation reste mémorisée jusqu’à ClearError. PAYLOAD 2=42 chez le destinataire prouve que les données en file sont une copie détenue par la bibliothèque.


Commande de compilation
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.pngImplémentation et source
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
Choisit si les futurs transferts à horloge interne utilisent le bit d’horloge rapide CGB.
Syntaxe
void __stackcall Link_SetFastClock(u8 on);Paramètres
onZéro demande la vitesse normale ; une valeur non nulle demande la vitesse rapide.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Chaque machine possède un état de liaison partagé. Les échanges d’octets sont en duplex intégral : un côté fournit l’horloge interne, l’autre utilise l’horloge externe. La vitesse normale exige 512 cycles par bit ; la vitesse rapide CGB, 16.
Ne modifie pas un transfert en cours. Les transferts à horloge externe ignorent ce réglage. La prise en charge matérielle n’est pas vérifiée ; exécutez les deux extrémités de l’exemple dans des modes matériels compatibles.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
lesson_delay(12);Link_SetFastClock(__cgb_is_cgb());result[5]=Link_BeginTransfer(0);value=77;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Reliez-vous à BYTE SLAVE. Envoyez 42 et recevez 99, puis échangez zéro dans les deux sens. RECEIVED=1, PEER BYTE=99, ZERO READY=1 et ZERO BYTE=0 distinguent une donnée zéro valide d’une absence de données. Deux instances CGB utilisent l’horloge rapide pour le second échange.


Commande de compilation
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.pngImplémentation et source
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
Active le bit d’autorisation d’interruption série et efface une demande série en attente.
Syntaxe
void __stackcall Link_SetUseInterrupt(u8 on);Paramètres
onZéro désactive ; toute valeur non nulle active.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Les sections critiques internes suivent leur profondeur d’imbrication logicielle. Sortir de la section la plus externe active les interruptions CPU ; ne supposez donc pas qu’un état IME précédemment désactivé sera conservé.
Installez séparément un gestionnaire au vecteur 0058h ; cette bibliothèque n’en enregistre pas. L’exemple masque à nouveau la source avant le transfert et ne teste pas le code d’entrée d’interruption CPU.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
Link_SetUseInterrupt(1);result[3]=(IE_REG&8)!=0;Link_SetUseInterrupt(0);result[4]=(IE_REG&8)!=0;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Vérifie l’initialisation, le refus lorsque la liaison est occupée, l’expiration avec horloge externe et la capacité du tampon. Valeurs attendues : BUSY ERROR=1, TIMEOUT=2, OPEN RX=255, OVERFLOW=3 et QUEUE BYTES=7. Après avoir observé IRQ REQUEST=1, la leçon appelle explicitement le corps du gestionnaire en maintenant la source IRQ série masquée.


Commande de compilation
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.pngImplémentation et source
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
Extrait un octet du tampon général de réception sans attendre.
Syntaxe
u8 __stackcall Link_TryReadByte(u8 *out);Paramètres
outDestination d’un octet inscriptible ; null abandonne l’octet.
Valeur renvoyée
Renvoie 1 si un octet est extrait, 0 si le tampon est vide ; une lecture à vide laisse out inchangé.
Conditions et limites
Le tampon circulaire de réception de huit entrées contient sept octets utiles. S’il est plein, le nouvel octet est abandonné et l’erreur 3 est mémorisée. Un octet reçu de valeur zéro est une donnée valide.
Les sections critiques internes suivent leur profondeur d’imbrication logicielle. Sortir de la section la plus externe active les interruptions CPU ; ne supposez donc pas qu’un état IME précédemment désactivé sera conservé.
Link4 copie chaque octet reçu dans le tampon général et dans un tampon propre au correspondant. Lire l’un ne vide pas l’autre. L’interrogation des paquets consomme le tampon général ; éliminez aussi régulièrement les octets bruts inutilisés des tampons par correspondant pour éviter un débordement.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[1]=Link_HasByte();value=77;result[2]=Link_TryReadByte(&value);result[3]=value;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
BYTE MASTER fournit l’horloge. Valeurs attendues : PEER BYTE=42, ZERO READY=1 et ZERO BYTE=0. EMPTY READ vaut aussi zéro ensuite ; il faut donc l’état de disponibilité ou le résultat de TryRead pour reconnaître une file vide.


Commande de compilation
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.pngImplémentation et source
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
Interroge immédiatement, puis attend un octet avec une limite fondée sur les VBlank.
Syntaxe
u8 __stackcall Link_WaitByte(u16 timeout_frames, u8 *out);Paramètres
timeout_framesNombre maximal d’attentes VBlank. Zéro effectue tout de même l’interrogation et la lecture initiales.
outOctet inscriptible obligatoire. null renvoie immédiatement zéro sans modifier l’erreur mémorisée.
Valeur renvoyée
Renvoie 1 à la réception, 0 en cas d’expiration ou de sortie nulle.
Conditions et limites
Le tampon circulaire de réception de huit entrées contient sept octets utiles. S’il est plein, le nouvel octet est abandonné et l’erreur 3 est mémorisée. Un octet reçu de valeur zéro est une donnée valide.
Utilisez cette fonction avec le LCD actif. L’expiration mémorise l’erreur 2 et laisse out inchangé. Le transfert lui-même n’est pas annulé ; appelez Cancel si vous l’abandonnez.
Les écrans proviennent de KOKURA. Les exemples à plusieurs extrémités vérifient les valeurs d’instances d’émulateur reliées ; les captures proviennent de leurs états finaux sauvegardés. Ces vérifications ne prouvent pas le comportement d’un câble physique ou d’un adaptateur à quatre joueurs.
Exécutez ces commandes PowerShell depuis le dossier parent contenant kitaqgb, kokura et kitaq-docs. Compilez toutes les ROM participantes avant de lancer la session reliée. Pour Link4, conservez les métadonnées de symboles générées à côté des ROM. Pour les exécutions DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
value=77;result[9]=Link_WaitByte(2,&value);result[10]=value;result[11]=Link_LastError();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Vérifie l’initialisation, le refus lorsque la liaison est occupée, l’expiration avec horloge externe et la capacité du tampon. Valeurs attendues : BUSY ERROR=1, TIMEOUT=2, OPEN RX=255, OVERFLOW=3 et QUEUE BYTES=7. Après avoir observé IRQ REQUEST=1, la leçon appelle explicitement le corps du gestionnaire en maintenant la source IRQ série masquée.


Commande de compilation
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.pngImplémentation et source
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 — Communication DMG-07 avec horloge externe
Le DMG-07 diffuse l’octet de chaque console aux quatre joueurs. Cette bibliothèque gère découverte, démarrage par le joueur 1, diffusions retardées et contrôle de redémarrage aligné. Découvrez l’échange à quatre avec EXCHANGE, les expirations avec NO ADAPTER, les données non lues avec OVERFLOW et la reprise avec RESTART.
Les joueurs de la bibliothèque sont numérotés 1..4 ; zéro signifie non découvert. Les bits 0..3 du masque de connexion correspondent aux joueurs 1..4. Les slots KOKURA --link-session vont de 0 à 3, convention distincte de l’API ROM.
Ce pilote possède le port série. N’exécutez pas Link ordinaire ou Link4 simultanément ; incluez link_hwregs_gb.c et link_dmg07.c une fois chacun. L’adaptateur fournit les horloges externes ; le pilote ne sélectionne pas le mode série rapide CGB.
Appelez Poll de façon répétée pendant toute la trame et TickFrame exactement une fois par trame. Un Poll par VBlank ne peut pas réarmer le port entre les octets de l’adaptateur. Le d_poll de l’en-tête partagé détecte l’entrée dans LY >= 144 pour appeler TickFrame une fois. Sérialisez les deux opérations au lieu de faire rivaliser ISR et boucle principale.
Avec SIZE=1, chaque console soumet un octet ; la diffusion de quatre octets suit l’ordre des joueurs 1..4. La première diffusion est jetée. Les suivantes contiennent les contributions du paquet précédent. Quatre octets 0xFF sont réservés à l’indication de redémarrage.
LinkDmg07_ClearError
Remet le dernier code d’erreur à zéro.
Syntaxe
void LinkDmg07_ClearError();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
SilenceFrames et les compteurs de diagnostic saturent à 255. Init les réinitialise tous ; les redémarrages ordinaires du protocole préservent les diagnostics. ClearError n’efface que le code d’erreur.
Préserve données reçues, phase, connexion et verrou d’expiration. Cet appel seul ne reconnecte pas et ne relance pas la réception.
Les écrans proviennent du modèle DMG-07 de KOKURA. Chaque console s’exécute indépendamment et les valeurs envoyées/reçues sont comparées. Le comportement électrique et le timing de l’adaptateur et du câble physiques ne sont pas vérifiés. Les écrans CGB affichent les nombres en bleu.
Placez kitaqgb, kokura et kitaq-docs sous un même répertoire parent et ouvrez PowerShell à cet endroit. Les exemples à quatre consoles lancent la même ROM dans quatre sessions. Pour DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
LinkDmg07_ClearError();result[21]=LinkDmg07_LastError();result[22]=LinkDmg07_GetErrorCount();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Laissez le premier paquet valide non lu jusqu’au suivant. Attendez SENT SEQ=3, PACKET SEQ=2 et ERROR=6 ; la lecture renvoie les dernières valeurs 33/34/35/36. ClearError met CLEAR ERROR à zéro, mais ErrorCount reste à un.


Commande de compilation
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.pngImplémentation et source
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
Consomme et efface une notification de découverte terminée.
Syntaxe
u8 LinkDmg07_ConsumePingStatus();Valeur renvoyée
Renvoie 1 si consommé, sinon 0.
Conditions et limites
Efface seulement la notification, préservant slot, masque et LastStatus. Les appels suivants renvoient zéro jusqu’à une nouvelle notification.
Les écrans proviennent du modèle DMG-07 de KOKURA. Chaque console s’exécute indépendamment et les valeurs envoyées/reçues sont comparées. Le comportement électrique et le timing de l’adaptateur et du câble physiques ne sont pas vérifiés. Les écrans CGB affichent les nombres en bleu.
Placez kitaqgb, kokura et kitaq-docs sous un même répertoire parent et ouvrez PowerShell à cet endroit. Les exemples à quatre consoles lancent la même ROM dans quatre sessions. Pour DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[3]=LinkDmg07_ConsumePingStatus();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exécutez la même ROM sur quatre consoles, chacune envoyant 32 plus son numéro. Toutes reçoivent PLAYER 1..4 = 33/34/35/36. La première diffusion valide enregistre SENT SEQ=2 et PACKET SEQ=1, montrant le retard d’un paquet. L’écran fige cette observation ; un jeu continue ensuite à interroger le port.


Commande de compilation
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.pngImplémentation et source
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
Lit l’ensemble de joueurs sur quatre bits du dernier état accepté.
Syntaxe
u8 LinkDmg07_GetConnectedMask();Valeur renvoyée
Les bits 0..3 indiquent les joueurs connectés. Zéro signifie non découvert ; quatre joueurs connectés donnent 15.
Conditions et limites
Les joueurs de la bibliothèque sont numérotés 1..4 ; zéro signifie non découvert. Les bits 0..3 du masque de connexion correspondent aux joueurs 1..4. Les slots KOKURA --link-session vont de 0 à 3, convention distincte de l’API ROM.
Renvoie l’état de découverte mémorisé, sans sonder le câblage physique. Pendant le transfert, reflète la dernière notification acceptée.
Les écrans proviennent du modèle DMG-07 de KOKURA. Chaque console s’exécute indépendamment et les valeurs envoyées/reçues sont comparées. Le comportement électrique et le timing de l’adaptateur et du câble physiques ne sont pas vérifiés. Les écrans CGB affichent les nombres en bleu.
Placez kitaqgb, kokura et kitaq-docs sous un même répertoire parent et ouvrez PowerShell à cet endroit. Les exemples à quatre consoles lancent la même ROM dans quatre sessions. Pour DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[1]=LinkDmg07_GetConnectedMask();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exécutez la même ROM sur quatre consoles, chacune envoyant 32 plus son numéro. Toutes reçoivent PLAYER 1..4 = 33/34/35/36. La première diffusion valide enregistre SENT SEQ=2 et PACKET SEQ=1, montrant le retard d’un paquet. L’écran fige cette observation ; un jeu continue ensuite à interroger le port.


Commande de compilation
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.pngImplémentation et source
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
Lit les pertes enregistrées : silence après détection d’un adaptateur ou disparition de joueurs de l’état de découverte.
Syntaxe
u8 LinkDmg07_GetDisconnectCount();Valeur renvoyée
Renvoie 0..255 événements, pas le nombre de joueurs perdus.
Conditions et limites
SilenceFrames et les compteurs de diagnostic saturent à 255. Init les réinitialise tous ; les redémarrages ordinaires du protocole préservent les diagnostics. ClearError n’efface que le code d’erreur.
Une expiration avant toute détection d’adaptateur ne l’incrémente pas. Plusieurs joueurs retirés par un seul changement d’état comptent comme un événement.
Les écrans proviennent du modèle DMG-07 de KOKURA. Chaque console s’exécute indépendamment et les valeurs envoyées/reçues sont comparées. Le comportement électrique et le timing de l’adaptateur et du câble physiques ne sont pas vérifiés. Les écrans CGB affichent les nombres en bleu.
Placez kitaqgb, kokura et kitaq-docs sous un même répertoire parent et ouvrez PowerShell à cet endroit. Les exemples à quatre consoles lancent la même ROM dans quatre sessions. Pour DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[8]=LinkDmg07_GetDisconnectCount();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exécutez sans adaptateur. Attendez PLAYER=0, START ERROR=2, SILENT FRAME=12, TIMEOUTS=1 et ERROR=4. DISCONNECTS reste zéro, aucun adaptateur n’ayant été vu. Une lecture vide préserve EMPTY BUFFER=77 ; ClearError donne CLEARED=0.


Commande de compilation
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.pngImplémentation et source
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
Lit le nombre d’erreurs de protocole reçues et d’écrasements de paquets non lus.
Syntaxe
u8 LinkDmg07_GetErrorCount();Valeur renvoyée
Renvoie 0..255. N’inclut pas les erreurs de validation/état de requête ni les expirations.
Conditions et limites
SilenceFrames et les compteurs de diagnostic saturent à 255. Init les réinitialise tous ; les redémarrages ordinaires du protocole préservent les diagnostics. ClearError n’efface que le code d’erreur.
La boîte de réception ne conserve que le dernier paquet. Un nouveau paquet terminé écrase les données non lues, mémorise l’erreur 6 et incrémente ErrorCount. L’adaptateur n’attend pas que l’application lise la boîte.
Les écrans proviennent du modèle DMG-07 de KOKURA. Chaque console s’exécute indépendamment et les valeurs envoyées/reçues sont comparées. Le comportement électrique et le timing de l’adaptateur et du câble physiques ne sont pas vérifiés. Les écrans CGB affichent les nombres en bleu.
Placez kitaqgb, kokura et kitaq-docs sous un même répertoire parent et ouvrez PowerShell à cet endroit. Les exemples à quatre consoles lancent la même ROM dans quatre sessions. Pour DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[19]=LinkDmg07_GetErrorCount();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Laissez le premier paquet valide non lu jusqu’au suivant. Attendez SENT SEQ=3, PACKET SEQ=2 et ERROR=6 ; la lecture renvoie les dernières valeurs 33/34/35/36. ClearError met CLEAR ERROR à zéro, mais ErrorCount reste à un.


Commande de compilation
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.pngImplémentation et source
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
Lit le dernier octet d’état brut validé de l’adaptateur.
Syntaxe
u8 LinkDmg07_GetLastStatus();Valeur renvoyée
Le quartet de poids fort est le masque de connexion ; les trois bits faibles contiennent le numéro local. Initialement zéro.
Conditions et limites
Les joueurs de la bibliothèque sont numérotés 1..4 ; zéro signifie non découvert. Les bits 0..3 du masque de connexion correspondent aux joueurs 1..4. Les slots KOKURA --link-session vont de 0 à 3, convention distincte de l’API ROM.
Rejette un état avec bit 3 actif, numéro nul ou supérieur à quatre, ou numéro local changé après découverte. Le rejet mémorise l’erreur 5 sans enregistrer cette valeur comme LastStatus.
Les écrans proviennent du modèle DMG-07 de KOKURA. Chaque console s’exécute indépendamment et les valeurs envoyées/reçues sont comparées. Le comportement électrique et le timing de l’adaptateur et du câble physiques ne sont pas vérifiés. Les écrans CGB affichent les nombres en bleu.
Placez kitaqgb, kokura et kitaq-docs sous un même répertoire parent et ouvrez PowerShell à cet endroit. Les exemples à quatre consoles lancent la même ROM dans quatre sessions. Pour DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[2]=LinkDmg07_GetLastStatus();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exécutez la même ROM sur quatre consoles, chacune envoyant 32 plus son numéro. Toutes reçoivent PLAYER 1..4 = 33/34/35/36. La première diffusion valide enregistre SENT SEQ=2 et PACKET SEQ=1, montrant le retard d’un paquet. L’écran fige cette observation ; un jeu continue ensuite à interroger le port.


Commande de compilation
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.pngImplémentation et source
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
Lit le numéro de joueur de cette console, appris dans l’état de l’adaptateur.
Syntaxe
u8 LinkDmg07_GetLocalSlot();Valeur renvoyée
Renvoie 1..4 après découverte ; zéro avant ou juste après une réinitialisation de découverte.
Conditions et limites
Les joueurs de la bibliothèque sont numérotés 1..4 ; zéro signifie non découvert. Les bits 0..3 du masque de connexion correspondent aux joueurs 1..4. Les slots KOKURA --link-session vont de 0 à 3, convention distincte de l’API ROM.
Les écrans proviennent du modèle DMG-07 de KOKURA. Chaque console s’exécute indépendamment et les valeurs envoyées/reçues sont comparées. Le comportement électrique et le timing de l’adaptateur et du câble physiques ne sont pas vérifiés. Les écrans CGB affichent les nombres en bleu.
Placez kitaqgb, kokura et kitaq-docs sous un même répertoire parent et ouvrez PowerShell à cet endroit. Les exemples à quatre consoles lancent la même ROM dans quatre sessions. Pour DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
slot=LinkDmg07_GetLocalSlot();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exécutez la même ROM sur quatre consoles, chacune envoyant 32 plus son numéro. Toutes reçoivent PLAYER 1..4 = 33/34/35/36. La première diffusion valide enregistre SENT SEQ=2 et PACKET SEQ=1, montrant le retard d’un paquet. L’écran fige cette observation ; un jeu continue ensuite à interroger le port.


Commande de compilation
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.pngImplémentation et source
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
Lit la séquence attribuée au dernier paquet publié.
Syntaxe
u8 LinkDmg07_GetPacketSequence();Valeur renvoyée
Renvoie la séquence du paquet sur huit bits sans changer la disponibilité.
Conditions et limites
Les numéros de séquence passent de 255 à zéro. À la publication du paquet, PacketSequence vaut SentSequence moins un. Les départs de transmission suivants avancent SentSequence ; deux lectures ultérieures ne diffèrent donc pas nécessairement d’un.
La boîte de réception ne conserve que le dernier paquet. Un nouveau paquet terminé écrase les données non lues, mémorise l’erreur 6 et incrémente ErrorCount. L’adaptateur n’attend pas que l’application lise la boîte.
Les écrans proviennent du modèle DMG-07 de KOKURA. Chaque console s’exécute indépendamment et les valeurs envoyées/reçues sont comparées. Le comportement électrique et le timing de l’adaptateur et du câble physiques ne sont pas vérifiés. Les écrans CGB affichent les nombres en bleu.
Placez kitaqgb, kokura et kitaq-docs sous un même répertoire parent et ouvrez PowerShell à cet endroit. Les exemples à quatre consoles lancent la même ROM dans quatre sessions. Pour DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[7]=LinkDmg07_GetPacketSequence();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exécutez la même ROM sur quatre consoles, chacune envoyant 32 plus son numéro. Toutes reçoivent PLAYER 1..4 = 33/34/35/36. La première diffusion valide enregistre SENT SEQ=2 et PACKET SEQ=1, montrant le retard d’un paquet. L’écran fige cette observation ; un jeu continue ensuite à interroger le port.


Commande de compilation
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.pngImplémentation et source
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
Lit l’octet d’un joueur dans le paquet mémorisé.
Syntaxe
u8 __stackcall LinkDmg07_GetPacketSlot(u8 player_slot);Paramètres
player_slotNuméro de joueur physique, 1..4.
Valeur renvoyée
Renvoie l’octet mémorisé du joueur 1..4, ou zéro pour un numéro invalide.
Conditions et limites
Les joueurs de la bibliothèque sont numérotés 1..4 ; zéro signifie non découvert. Les bits 0..3 du masque de connexion correspondent aux joueurs 1..4. Les slots KOKURA --link-session vont de 0 à 3, convention distincte de l’API ROM.
Ne vérifie ni ne consomme la disponibilité. Renvoie zéro juste après initialisation et peut renvoyer des octets conservés après consommation ou remise à zéro de découverte. Ne l’utilisez pas comme test de nouvelles données.
Les écrans proviennent du modèle DMG-07 de KOKURA. Chaque console s’exécute indépendamment et les valeurs envoyées/reçues sont comparées. Le comportement électrique et le timing de l’adaptateur et du câble physiques ne sont pas vérifiés. Les écrans CGB affichent les nombres en bleu.
Placez kitaqgb, kokura et kitaq-docs sous un même répertoire parent et ouvrez PowerShell à cet endroit. Les exemples à quatre consoles lancent la même ROM dans quatre sessions. Pour DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[16]=LinkDmg07_GetPacketSlot(4);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exécutez la même ROM sur quatre consoles, chacune envoyant 32 plus son numéro. Toutes reçoivent PLAYER 1..4 = 33/34/35/36. La première diffusion valide enregistre SENT SEQ=2 et PACKET SEQ=1, montrant le retard d’un paquet. L’écran fige cette observation ; un jeu continue ensuite à interroger le port.


Commande de compilation
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.pngImplémentation et source
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
Lit la phase courante : découverte, demande de démarrage, confirmation ou transfert.
Syntaxe
u8 LinkDmg07_GetPhase();Valeur renvoyée
0=PING, 1=REQUEST_AA, 2=WAIT_CC, 3=TRANSFER.
Conditions et limites
N’interroge pas le port et n’attend pas. L’acceptation d’une demande de démarrage ne suffit pas pour TRANSFER : quatre octets 0xCC consécutifs sont requis.
Les écrans proviennent du modèle DMG-07 de KOKURA. Chaque console s’exécute indépendamment et les valeurs envoyées/reçues sont comparées. Le comportement électrique et le timing de l’adaptateur et du câble physiques ne sont pas vérifiés. Les écrans CGB affichent les nombres en bleu.
Placez kitaqgb, kokura et kitaq-docs sous un même répertoire parent et ouvrez PowerShell à cet endroit. Les exemples à quatre consoles lancent la même ROM dans quatre sessions. Pour DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[8]=LinkDmg07_GetPhase();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exécutez la même ROM sur quatre consoles, chacune envoyant 32 plus son numéro. Toutes reçoivent PLAYER 1..4 = 33/34/35/36. La première diffusion valide enregistre SENT SEQ=2 et PACKET SEQ=1, montrant le retard d’un paquet. L’écran fige cette observation ; un jeu continue ensuite à interroger le port.


Commande de compilation
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.pngImplémentation et source
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
Lit si le contrôle de redémarrage est absent, en attente ou en cours d’envoi.
Syntaxe
u8 LinkDmg07_GetRestartState();Valeur renvoyée
0=aucun, 1=attente de frontière, 2=envoi du contrôle.
Conditions et limites
Distinct de la phase de communication. Zéro seul n’implique pas une connexion établie ou utilisable.
Les écrans proviennent du modèle DMG-07 de KOKURA. Chaque console s’exécute indépendamment et les valeurs envoyées/reçues sont comparées. Le comportement électrique et le timing de l’adaptateur et du câble physiques ne sont pas vérifiés. Les écrans CGB affichent les nombres en bleu.
Placez kitaqgb, kokura et kitaq-docs sous un même répertoire parent et ouvrez PowerShell à cet endroit. Les exemples à quatre consoles lancent la même ROM dans quatre sessions. Pour DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[4]=LinkDmg07_GetRestartState();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le joueur 2 demande le redémarrage et enregistre PENDING=1, SENT FF=1. Les quatre consoles montrent DATA VALID=1, RESET PHASE=0, SLOT AFTER=0 et RESET PRIME=0. Le pilote préserve l’échange actif jusqu’à ce que l’indication de l’adaptateur le ramène à la découverte.


Commande de compilation
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.pngImplémentation et source
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
Lit le nombre d’octets applicatifs effectivement transmis sous horloge.
Syntaxe
u8 LinkDmg07_GetSentSequence();Valeur renvoyée
Renvoie la séquence d’envoi sur huit bits. Compte la première contribution, mais exclut le contrôle de redémarrage.
Conditions et limites
Les numéros de séquence passent de 255 à zéro. À la publication du paquet, PacketSequence vaut SentSequence moins un. Les départs de transmission suivants avancent SentSequence ; deux lectures ultérieures ne diffèrent donc pas nécessairement d’un.
Avec SIZE=1, chaque console soumet un octet ; la diffusion de quatre octets suit l’ordre des joueurs 1..4. La première diffusion est jetée. Les suivantes contiennent les contributions du paquet précédent. Quatre octets 0xFF sont réservés à l’indication de redémarrage.
Les écrans proviennent du modèle DMG-07 de KOKURA. Chaque console s’exécute indépendamment et les valeurs envoyées/reçues sont comparées. Le comportement électrique et le timing de l’adaptateur et du câble physiques ne sont pas vérifiés. Les écrans CGB affichent les nombres en bleu.
Placez kitaqgb, kokura et kitaq-docs sous un même répertoire parent et ouvrez PowerShell à cet endroit. Les exemples à quatre consoles lancent la même ROM dans quatre sessions. Pour DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[6]=LinkDmg07_GetSentSequence();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exécutez la même ROM sur quatre consoles, chacune envoyant 32 plus son numéro. Toutes reçoivent PLAYER 1..4 = 33/34/35/36. La première diffusion valide enregistre SENT SEQ=2 et PACKET SEQ=1, montrant le retard d’un paquet. L’écran fige cette observation ; un jeu continue ensuite à interroger le port.


Commande de compilation
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.pngImplémentation et source
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
Lit les trames comptées depuis la dernière fin de transfert série traitée.
Syntaxe
u8 LinkDmg07_GetSilenceFrames();Valeur renvoyée
0..255 ; une fin traitée le remet à zéro et chaque TickFrame l’incrémente.
Conditions et limites
Appelez Poll de façon répétée pendant toute la trame et TickFrame exactement une fois par trame. Un Poll par VBlank ne peut pas réarmer le port entre les octets de l’adaptateur. Le d_poll de l’en-tête partagé détecte l’entrée dans LY >= 144 pour appeler TickFrame une fois. Sérialisez les deux opérations au lieu de faire rivaliser ISR et boucle principale.
SilenceFrames et les compteurs de diagnostic saturent à 255. Init les réinitialise tous ; les redémarrages ordinaires du protocole préservent les diagnostics. ClearError n’efface que le code d’erreur.
Les écrans proviennent du modèle DMG-07 de KOKURA. Chaque console s’exécute indépendamment et les valeurs envoyées/reçues sont comparées. Le comportement électrique et le timing de l’adaptateur et du câble physiques ne sont pas vérifiés. Les écrans CGB affichent les nombres en bleu.
Placez kitaqgb, kokura et kitaq-docs sous un même répertoire parent et ouvrez PowerShell à cet endroit. Les exemples à quatre consoles lancent la même ROM dans quatre sessions. Pour DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[6]=LinkDmg07_GetSilenceFrames();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exécutez sans adaptateur. Attendez PLAYER=0, START ERROR=2, SILENT FRAME=12, TIMEOUTS=1 et ERROR=4. DISCONNECTS reste zéro, aucun adaptateur n’ayant été vu. Une lecture vide préserve EMPTY BUFFER=77 ; ClearError donne CLEARED=0.


Commande de compilation
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.pngImplémentation et source
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
Lit le nombre d’expirations de silence ou de négociation.
Syntaxe
u8 LinkDmg07_GetTimeoutCount();Valeur renvoyée
Renvoie un cumul de 0 à 255.
Conditions et limites
SilenceFrames et les compteurs de diagnostic saturent à 255. Init les réinitialise tous ; les redémarrages ordinaires du protocole préservent les diagnostics. ClearError n’efface que le code d’erreur.
Ne recompte pas le même silence à chaque trame avant la reprise. ClearError conserve ce verrou de suppression et le cumul.
Les écrans proviennent du modèle DMG-07 de KOKURA. Chaque console s’exécute indépendamment et les valeurs envoyées/reçues sont comparées. Le comportement électrique et le timing de l’adaptateur et du câble physiques ne sont pas vérifiés. Les écrans CGB affichent les nombres en bleu.
Placez kitaqgb, kokura et kitaq-docs sous un même répertoire parent et ouvrez PowerShell à cet endroit. Les exemples à quatre consoles lancent la même ROM dans quatre sessions. Pour DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[7]=LinkDmg07_GetTimeoutCount();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exécutez sans adaptateur. Attendez PLAYER=0, START ERROR=2, SILENT FRAME=12, TIMEOUTS=1 et ERROR=4. DISCONNECTS reste zéro, aucun adaptateur n’ayant été vu. Une lecture vide préserve EMPTY BUFFER=77 ; ClearError donne CLEARED=0.


Commande de compilation
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.pngImplémentation et source
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
Vérifie si un paquet de données terminé de quatre octets n’a pas été lu.
Syntaxe
u8 LinkDmg07_HasPacket();Valeur renvoyée
Renvoie 1 pour des données non lues, sinon 0.
Conditions et limites
Avec SIZE=1, chaque console soumet un octet ; la diffusion de quatre octets suit l’ordre des joueurs 1..4. La première diffusion est jetée. Les suivantes contiennent les contributions du paquet précédent. Quatre octets 0xFF sont réservés à l’indication de redémarrage.
La boîte de réception ne conserve que le dernier paquet. Un nouveau paquet terminé écrase les données non lues, mémorise l’erreur 6 et incrémente ErrorCount. L’adaptateur n’attend pas que l’application lise la boîte.
Les écrans proviennent du modèle DMG-07 de KOKURA. Chaque console s’exécute indépendamment et les valeurs envoyées/reçues sont comparées. Le comportement électrique et le timing de l’adaptateur et du câble physiques ne sont pas vérifiés. Les écrans CGB affichent les nombres en bleu.
Placez kitaqgb, kokura et kitaq-docs sous un même répertoire parent et ouvrez PowerShell à cet endroit. Les exemples à quatre consoles lancent la même ROM dans quatre sessions. Pour DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[15]=LinkDmg07_HasPacket();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exécutez la même ROM sur quatre consoles, chacune envoyant 32 plus son numéro. Toutes reçoivent PLAYER 1..4 = 33/34/35/36. La première diffusion valide enregistre SENT SEQ=2 et PACKET SEQ=1, montrant le retard d’un paquet. L’écran fige cette observation ; un jeu continue ensuite à interroger le port.


Commande de compilation
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.pngImplémentation et source
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
Vérifie si un échange de découverte de quatre octets terminé attend un acquittement.
Syntaxe
u8 LinkDmg07_HasPingStatus();Valeur renvoyée
Renvoie 1 pour une notification non consommée, sinon 0.
Conditions et limites
Ne lit qu’un drapeau. Un échange de découverte peut avancer malgré un état rejeté ; ce drapeau seul ne prouve donc ni des données entièrement valides ni un démarrage terminé. Vérifiez aussi slot, masque et LastError.
Les écrans proviennent du modèle DMG-07 de KOKURA. Chaque console s’exécute indépendamment et les valeurs envoyées/reçues sont comparées. Le comportement électrique et le timing de l’adaptateur et du câble physiques ne sont pas vérifiés. Les écrans CGB affichent les nombres en bleu.
Placez kitaqgb, kokura et kitaq-docs sous un même répertoire parent et ouvrez PowerShell à cet endroit. Les exemples à quatre consoles lancent la même ROM dans quatre sessions. Pour DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[4]=LinkDmg07_HasPingStatus();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exécutez la même ROM sur quatre consoles, chacune envoyant 32 plus son numéro. Toutes reçoivent PLAYER 1..4 = 33/34/35/36. La première diffusion valide enregistre SENT SEQ=2 et PACKET SEQ=1, montrant le retard d’un paquet. L’écran fige cette observation ; un jeu continue ensuite à interroger le port.


Commande de compilation
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.pngImplémentation et source
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
Réinitialise découverte, stockage de réception et diagnostics, puis arme la réception sur les horloges de l’adaptateur.
Syntaxe
void __stackcall LinkDmg07_Init(u8 rate);Paramètres
rateRéponse RATE sur huit bits à l’adaptateur ; zéro choisit la valeur par défaut 0x10.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Ce pilote possède le port série. N’exécutez pas Link ordinaire ou Link4 simultanément ; incluez link_hwregs_gb.c et link_dmg07.c une fois chacun. L’adaptateur fournit les horloges externes ; le pilote ne sélectionne pas le mode série rapide CGB.
Les joueurs de la bibliothèque sont numérotés 1..4 ; zéro signifie non découvert. Les bits 0..3 du masque de connexion correspondent aux joueurs 1..4. Les slots KOKURA --link-session vont de 0 à 3, convention distincte de l’API ROM.
Met SC à 0x80 et SB à 0x88 ; efface seulement les bits série dans IE et IF. Ne modifie ni les autres bits d’activation ni l’état IME du CPU.
Les écrans proviennent du modèle DMG-07 de KOKURA. Chaque console s’exécute indépendamment et les valeurs envoyées/reçues sont comparées. Le comportement électrique et le timing de l’adaptateur et du câble physiques ne sont pas vérifiés. Les écrans CGB affichent les nombres en bleu.
Placez kitaqgb, kokura et kitaq-docs sous un même répertoire parent et ouvrez PowerShell à cet endroit. Les exemples à quatre consoles lancent la même ROM dans quatre sessions. Pour DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
LinkDmg07_Init(0);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exécutez la même ROM sur quatre consoles, chacune envoyant 32 plus son numéro. Toutes reçoivent PLAYER 1..4 = 33/34/35/36. La première diffusion valide enregistre SENT SEQ=2 et PACKET SEQ=1, montrant le retard d’un paquet. L’écran fige cette observation ; un jeu continue ensuite à interroger le port.


Commande de compilation
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.pngImplémentation et source
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
Vérifie si la première diffusion indéfinie a été jetée.
Syntaxe
u8 LinkDmg07_IsPipelinePrimed();Valeur renvoyée
Renvoie 1 après la première diffusion ; initialisation, remise à zéro de découverte et confirmation de démarrage l’effacent.
Conditions et limites
Avec SIZE=1, chaque console soumet un octet ; la diffusion de quatre octets suit l’ordre des joueurs 1..4. La première diffusion est jetée. Les suivantes contiennent les contributions du paquet précédent. Quatre octets 0xFF sont réservés à l’indication de redémarrage.
Un pipeline amorcé ne contient pas nécessairement un paquet terminé. Utilisez HasPacket pour savoir si une lecture est disponible.
Les écrans proviennent du modèle DMG-07 de KOKURA. Chaque console s’exécute indépendamment et les valeurs envoyées/reçues sont comparées. Le comportement électrique et le timing de l’adaptateur et du câble physiques ne sont pas vérifiés. Les écrans CGB affichent les nombres en bleu.
Placez kitaqgb, kokura et kitaq-docs sous un même répertoire parent et ouvrez PowerShell à cet endroit. Les exemples à quatre consoles lancent la même ROM dans quatre sessions. Pour DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[9]=LinkDmg07_IsPipelinePrimed();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exécutez la même ROM sur quatre consoles, chacune envoyant 32 plus son numéro. Toutes reçoivent PLAYER 1..4 = 33/34/35/36. La première diffusion valide enregistre SENT SEQ=2 et PACKET SEQ=1, montrant le retard d’un paquet. L’écran fige cette observation ; un jeu continue ensuite à interroger le port.


Commande de compilation
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.pngImplémentation et source
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
Lit le dernier code d’erreur mémorisé.
Syntaxe
u8 LinkDmg07_LastError();Valeur renvoyée
Renvoie un code d’erreur de 0 à 6.
Conditions et limites
Codes d’erreur : 0=aucune, 1=mauvaise phase, 2=pas joueur 1, 3=non prêt, 4=expiration, 5=erreur de protocole, 6=paquet non lu écrasé. Les requêtes réussissent avec zéro ; réception/pop avec un. Une requête réussie n’efface pas une erreur antérieure.
La lecture ne l’efface pas. Ne conserve que le dernier code, pas l’historique des erreurs.
Les écrans proviennent du modèle DMG-07 de KOKURA. Chaque console s’exécute indépendamment et les valeurs envoyées/reçues sont comparées. Le comportement électrique et le timing de l’adaptateur et du câble physiques ne sont pas vérifiés. Les écrans CGB affichent les nombres en bleu.
Placez kitaqgb, kokura et kitaq-docs sous un même répertoire parent et ouvrez PowerShell à cet endroit. Les exemples à quatre consoles lancent la même ROM dans quatre sessions. Pour DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[9]=LinkDmg07_LastError();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exécutez sans adaptateur. Attendez PLAYER=0, START ERROR=2, SILENT FRAME=12, TIMEOUTS=1 et ERROR=4. DISCONNECTS reste zéro, aucun adaptateur n’ayant été vu. Une lecture vide préserve EMPTY BUFFER=77 ; ClearError donne CLEARED=0.


Commande de compilation
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.pngImplémentation et source
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
Traite un octet série terminé dans la phase courante et arme immédiatement la réponse suivante.
Syntaxe
void LinkDmg07_Poll();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Ce pilote possède le port série. N’exécutez pas Link ordinaire ou Link4 simultanément ; incluez link_hwregs_gb.c et link_dmg07.c une fois chacun. L’adaptateur fournit les horloges externes ; le pilote ne sélectionne pas le mode série rapide CGB.
Appelez Poll de façon répétée pendant toute la trame et TickFrame exactement une fois par trame. Un Poll par VBlank ne peut pas réarmer le port entre les octets de l’adaptateur. Le d_poll de l’en-tête partagé détecte l’entrée dans LY >= 144 pour appeler TickFrame une fois. Sérialisez les deux opérations au lieu de faire rivaliser ISR et boucle principale.
Ne fait rien tant que le bit de démarrage de SC est actif. Traiter une fin remet à zéro SilenceFrames et le verrou d’expiration. Initialisez avant d’interroger.
Les écrans proviennent du modèle DMG-07 de KOKURA. Chaque console s’exécute indépendamment et les valeurs envoyées/reçues sont comparées. Le comportement électrique et le timing de l’adaptateur et du câble physiques ne sont pas vérifiés. Les écrans CGB affichent les nombres en bleu.
Placez kitaqgb, kokura et kitaq-docs sous un même répertoire parent et ouvrez PowerShell à cet endroit. Les exemples à quatre consoles lancent la même ROM dans quatre sessions. Pour DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
void d_poll(){LinkDmg07_Poll();if(D_LY>=144){if(d_vblank==0){d_vblank=1;LinkDmg07_TickFrame();}}else d_vblank=0;}Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exécutez la même ROM sur quatre consoles, chacune envoyant 32 plus son numéro. Toutes reçoivent PLAYER 1..4 = 33/34/35/36. La première diffusion valide enregistre SENT SEQ=2 et PACKET SEQ=1, montrant le retard d’un paquet. L’écran fige cette observation ; un jeu continue ensuite à interroger le port.


Commande de compilation
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.pngImplémentation et source
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
Copie le dernier paquet terminé et efface son drapeau non lu.
Syntaxe
u8 __stackcall LinkDmg07_ReadPacket(u8 *dst);Paramètres
dstQuatre octets accessibles en écriture ; null jette le paquet.
Valeur renvoyée
Renvoie 1 si consommé, 0 si vide. Une lecture vide laisse dst inchangé.
Conditions et limites
Avec SIZE=1, chaque console soumet un octet ; la diffusion de quatre octets suit l’ordre des joueurs 1..4. La première diffusion est jetée. Les suivantes contiennent les contributions du paquet précédent. Quatre octets 0xFF sont réservés à l’indication de redémarrage.
La boîte de réception ne conserve que le dernier paquet. Un nouveau paquet terminé écrase les données non lues, mémorise l’erreur 6 et incrémente ErrorCount. L’adaptateur n’attend pas que l’application lise la boîte.
Les octets mémorisés restent accessibles par GetPacketSlot après consommation. Un ReadPacket vide ne les recopie pas.
Les écrans proviennent du modèle DMG-07 de KOKURA. Chaque console s’exécute indépendamment et les valeurs envoyées/reçues sont comparées. Le comportement électrique et le timing de l’adaptateur et du câble physiques ne sont pas vérifiés. Les écrans CGB affichent les nombres en bleu.
Placez kitaqgb, kokura et kitaq-docs sous un même répertoire parent et ouvrez PowerShell à cet endroit. Les exemples à quatre consoles lancent la même ROM dans quatre sessions. Pour DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[10]=LinkDmg07_ReadPacket(packet);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exécutez la même ROM sur quatre consoles, chacune envoyant 32 plus son numéro. Toutes reçoivent PLAYER 1..4 = 33/34/35/36. La première diffusion valide enregistre SENT SEQ=2 et PACKET SEQ=1, montrant le retard d’un paquet. L’écran fige cette observation ; un jeu continue ensuite à interroger le port.


Commande de compilation
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.pngImplémentation et source
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
Programme le trafic de contrôle de redémarrage à une frontière de paquet de transfert.
Syntaxe
u8 LinkDmg07_RequestRestart();Valeur renvoyée
Renvoie 0 en TRANSFER, sinon 1. Les demandes répétées pendant attente/envoi renvoient aussi 0.
Conditions et limites
Avec SIZE=1, chaque console soumet un octet ; la diffusion de quatre octets suit l’ordre des joueurs 1..4. La première diffusion est jetée. Les suivantes contiennent les contributions du paquet précédent. Quatre octets 0xFF sont réservés à l’indication de redémarrage.
Codes d’erreur : 0=aucune, 1=mauvaise phase, 2=pas joueur 1, 3=non prêt, 4=expiration, 5=erreur de protocole, 6=paquet non lu écrasé. Les requêtes réussissent avec zéro ; réception/pop avec un. Une requête réussie n’efface pas une erreur antérieure.
Tout joueur peut le demander. Préserve la position d’octet, envoie un trafic 0xFF aligné et revient à la découverte après l’indication tout-0xFF de l’adaptateur. La demande seule n’efface ni le slot local ni le pipeline de réception.
Les écrans proviennent du modèle DMG-07 de KOKURA. Chaque console s’exécute indépendamment et les valeurs envoyées/reçues sont comparées. Le comportement électrique et le timing de l’adaptateur et du câble physiques ne sont pas vérifiés. Les écrans CGB affichent les nombres en bleu.
Placez kitaqgb, kokura et kitaq-docs sous un même répertoire parent et ouvrez PowerShell à cet endroit. Les exemples à quatre consoles lancent la même ROM dans quatre sessions. Pour DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[3]=LinkDmg07_RequestRestart();result[4]=LinkDmg07_GetRestartState();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le joueur 2 demande le redémarrage et enregistre PENDING=1, SENT FF=1. Les quatre consoles montrent DATA VALID=1, RESET PHASE=0, SLOT AFTER=0 et RESET PRIME=0. Le pilote préserve l’échange actif jusqu’à ce que l’indication de l’adaptateur le ramène à la découverte.


Commande de compilation
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.pngImplémentation et source
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
Programme la demande de démarrage du joueur physique 1 à la prochaine frontière de paquet de découverte.
Syntaxe
u8 LinkDmg07_RequestTransmission();Valeur renvoyée
Renvoie 0 si programmé, 1 pour une mauvaise phase, 2 si ce n’est pas le joueur 1, 3 si le bit de connexion local manque.
Conditions et limites
Les joueurs de la bibliothèque sont numérotés 1..4 ; zéro signifie non découvert. Les bits 0..3 du masque de connexion correspondent aux joueurs 1..4. Les slots KOKURA --link-session vont de 0 à 3, convention distincte de l’API ROM.
Codes d’erreur : 0=aucune, 1=mauvaise phase, 2=pas joueur 1, 3=non prêt, 4=expiration, 5=erreur de protocole, 6=paquet non lu écrasé. Les requêtes réussissent avec zéro ; réception/pop avec un. Une requête réussie n’efface pas une erreur antérieure.
Ne peut être programmé qu’en PING. N’attend pas lui-même les quatre joueurs ; l’exemple vérifie le masque 15 dans l’application. La programmation est asynchrone : le trafic 0xAA aligné précède la confirmation 0xCC.
Les écrans proviennent du modèle DMG-07 de KOKURA. Chaque console s’exécute indépendamment et les valeurs envoyées/reçues sont comparées. Le comportement électrique et le timing de l’adaptateur et du câble physiques ne sont pas vérifiés. Les écrans CGB affichent les nombres en bleu.
Placez kitaqgb, kokura et kitaq-docs sous un même répertoire parent et ouvrez PowerShell à cet endroit. Les exemples à quatre consoles lancent la même ROM dans quatre sessions. Pour DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
result[5]=LinkDmg07_RequestTransmission();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exécutez la même ROM sur quatre consoles, chacune envoyant 32 plus son numéro. Toutes reçoivent PLAYER 1..4 = 33/34/35/36. La première diffusion valide enregistre SENT SEQ=2 et PACKET SEQ=1, montrant le retard d’un paquet. L’écran fige cette observation ; un jeu continue ensuite à interroger le port.


Commande de compilation
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.pngImplémentation et source
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
Définit l’octet applicatif d’un prochain paquet sortant.
Syntaxe
void __stackcall LinkDmg07_SetLocalByte(u8 value);Paramètres
valueValeur applicative sur huit bits à soumettre.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Avec SIZE=1, chaque console soumet un octet ; la diffusion de quatre octets suit l’ordre des joueurs 1..4. La première diffusion est jetée. Les suivantes contiennent les contributions du paquet précédent. Quatre octets 0xFF sont réservés à l’indication de redémarrage.
Échantillonné lorsque l’octet zéro du paquet est armé. Ne change pas un octet SB déjà armé. Définissez la première contribution avant de demander le démarrage.
Les écrans proviennent du modèle DMG-07 de KOKURA. Chaque console s’exécute indépendamment et les valeurs envoyées/reçues sont comparées. Le comportement électrique et le timing de l’adaptateur et du câble physiques ne sont pas vérifiés. Les écrans CGB affichent les nombres en bleu.
Placez kitaqgb, kokura et kitaq-docs sous un même répertoire parent et ouvrez PowerShell à cet endroit. Les exemples à quatre consoles lancent la même ROM dans quatre sessions. Pour DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
LinkDmg07_SetLocalByte(32+slot);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exécutez la même ROM sur quatre consoles, chacune envoyant 32 plus son numéro. Toutes reçoivent PLAYER 1..4 = 33/34/35/36. La première diffusion valide enregistre SENT SEQ=2 et PACKET SEQ=1, montrant le retard d’un paquet. L’écran fige cette observation ; un jeu continue ensuite à interroger le port.


Commande de compilation
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.pngImplémentation et source
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
Avance d’une trame les surveillances de silence et de démarrage/redémarrage, puis demande une reprise à l’échéance.
Syntaxe
void LinkDmg07_TickFrame();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Appelez Poll de façon répétée pendant toute la trame et TickFrame exactement une fois par trame. Un Poll par VBlank ne peut pas réarmer le port entre les octets de l’adaptateur. Le d_poll de l’en-tête partagé détecte l’entrée dans LY >= 144 pour appeler TickFrame une fois. Sérialisez les deux opérations au lieu de faire rivaliser ISR et boucle principale.
SilenceFrames et les compteurs de diagnostic saturent à 255. Init les réinitialise tous ; les redémarrages ordinaires du protocole préservent les diagnostics. ClearError n’efface que le code d’erreur.
Le délai par défaut est de 12 appels ; définissez LINK_DMG07_TIMEOUT_FRAMES entre 1 et 255 avant inclusion pour le changer. Un épisode de silence n’est compté qu’une fois, jusqu’à ce qu’un octet efface son verrou. La reprise du transfert préserve l’alignement des octets ; celle de découverte/démarrage retourne à la découverte.
Les écrans proviennent du modèle DMG-07 de KOKURA. Chaque console s’exécute indépendamment et les valeurs envoyées/reçues sont comparées. Le comportement électrique et le timing de l’adaptateur et du câble physiques ne sont pas vérifiés. Les écrans CGB affichent les nombres en bleu.
Placez kitaqgb, kokura et kitaq-docs sous un même répertoire parent et ouvrez PowerShell à cet endroit. Les exemples à quatre consoles lancent la même ROM dans quatre sessions. Pour DMG, remplacez partout --cgb=cgb par --cgb=dmg et --hardware cgb par --hardware dmg.
Exemple d’utilisation
void d_poll(){LinkDmg07_Poll();if(D_LY>=144){if(d_vblank==0){d_vblank=1;LinkDmg07_TickFrame();}}else d_vblank=0;}Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Exécutez sans adaptateur. Attendez PLAYER=0, START ERROR=2, SILENT FRAME=12, TIMEOUTS=1 et ERROR=4. DISCONNECTS reste zéro, aucun adaptateur n’ayant été vu. Une lecture vide préserve EMPTY BUFFER=77 ; ClearError donne CLEARED=0.


Commande de compilation
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.pngImplémentation et source
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 — Mouvement et collisions en 2D
Fournit l’intégration des boîtes, les contacts AABB et un solveur optionnel de réponse aux surfaces. Les corps utilisent des centres et des demi-dimensions ; active=0 exclut un emplacement, et inv_mass_q8<=0 rend le corps statique. KQRect utilise au contraire un coin supérieur gauche et une largeur/hauteur. Les contacts entre boîtes n’utilisent pas le champ restitution du corps ; les réponses aux surfaces utilisent les coefficients de KQSurface2D.
Utilisez des unités entières cohérentes pour les positions, rayons, demi-dimensions, vitesses et la gravité. Un pas correspond à un tick de simulation. Les exemples utilisent une unité par pixel. Ces routines ne convertissent pas automatiquement les positions en Q8.8 et n’effectuent aucun rendu.
Le monde emprunte son tableau : l’appelant alloue et possède la mémoire des corps et doit la garder valide. Initialiser le monde n’initialise pas les éléments du tableau.
kq2d_body_apply_friction
Multiplie les deux composantes de vitesse par un coefficient signé sur un octet divisé par 256, sans vérifier la position ni l’activité.
Syntaxe
void kq2d_body_apply_friction(KQBody2D* body, u8 friction_q8);Paramètres
bodyPointeur vers le corps à modifier. Les champs non utilisés par cette opération sont conservés.
friction_q8Facteur multiplicatif de vitesse utilisé par cette fonction. Il est converti en s8 : les valeurs 128..255 deviennent donc des coefficients négatifs.
Valeur renvoyée
Aucune valeur de retour. Cette rubrique décrit les champs modifiés et le moment où les changements prennent effet.
Conditions et limites
Les valeurs 0..127 donnent des facteurs de 0 à 127/256. Les valeurs 128..255 deviennent négatives après conversion en s8 et inversent la vitesse. Pour un amortissement non négatif sur toute la plage 0..255, utilisez kq2d_scale_q8 sur chaque composante. Les produits sont tronqués vers zéro. NULL est ignoré.
Exemple d’utilisation
kq2d_body_apply_friction(&temp,64);
result[11]=temp.vx; result[12]=temp.vy;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
À gauche, l’état initial ; à droite, après un tick. Une boîte rouge de 16x16, centrée en (24,24) avec une vitesse de (4,16), atteint (28,36) et sa vitesse Y s’annule sur le sol bleu. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48). Sur DMG, tous les repères sont noirs. Les contrôles RAM couvrent aussi l’initialisation, les fonctions de réglage, l’intégration, les tests de rectangles et de points et la mise à l’échelle signée.


Commande de compilation
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-disasmImplémentation et source
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
Ajoute la gravité à un corps dynamique actif et borne chaque axe à +/-max_speed, sans modifier la position.
Syntaxe
void kq2d_body_apply_gravity(KQBody2D* body, s16 gravity_x, s16 gravity_y, s16 max_speed);Paramètres
bodyPointeur vers le corps à modifier. Les champs non utilisés par cette opération sont conservés.
gravity_xAccélération ajoutée à la vitesse X par cet appel.
gravity_yAccélération ajoutée à la vitesse Y par cet appel.
max_speedLimite de vitesse. La rubrique précise si elle s’applique à chaque axe ou au vecteur résultant.
Valeur renvoyée
Aucune valeur de retour. Cette rubrique décrit les champs modifiés et le moment où les changements prennent effet.
Conditions et limites
Utilisez des unités entières cohérentes pour les positions, rayons, demi-dimensions, vitesses et la gravité. Un pas correspond à un tick de simulation. Les exemples utilisent une unité par pixel. Ces routines ne convertissent pas automatiquement les positions en Q8.8 et n’effectuent aucun rendu.
Veillez à ce que sommes, différences, sommes de demi-dimensions et produits de correction des contacts restent dans la plage d’un entier signé de 16 bits. La limitation de vitesse intervient après l’addition et ne peut donc pas empêcher un dépassement pendant celle-ci.
Les routines d’intégration et de collision des boîtes partagent une zone de travail. Ne les rappelez pas depuis une interruption lorsqu’elles sont déjà en cours d’exécution.
Ignore NULL, les corps inactifs et ceux dont la masse inverse est nulle ou négative. Fournissez une limite de vitesse positive ou nulle.
Exemple d’utilisation
kq2d_body_apply_gravity(&temp,5,-10,32);
result[9]=temp.vx; result[10]=temp.vy;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
À gauche, l’état initial ; à droite, après un tick. Une boîte rouge de 16x16, centrée en (24,24) avec une vitesse de (4,16), atteint (28,36) et sa vitesse Y s’annule sur le sol bleu. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48). Sur DMG, tous les repères sont noirs. Les contrôles RAM couvrent aussi l’initialisation, les fonctions de réglage, l’intégration, les tests de rectangles et de points et la mise à l’échelle signée.


Commande de compilation
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-disasmImplémentation et source
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
Initialise une boîte définie par son centre avec les demi-dimensions fournies, une vitesse nulle, une masse inverse de 256 et un état actif.
Syntaxe
void kq2d_body_init(KQBody2D* body, s16 x, s16 y, s16 half_x, s16 half_y);Paramètres
bodyPointeur vers le corps à modifier. Les champs non utilisés par cette opération sont conservés.
xCoordonnée X du centre ou du point, en pixels dans l’exemple.
yCoordonnée Y du centre ou du point ; le sens positif va vers le bas dans l’exemple.
half_xDemi-dimension selon X ; la largeur totale de la boîte vaut deux fois cette valeur.
half_yDemi-dimension selon Y ; la hauteur totale de la boîte vaut deux fois cette valeur.
Valeur renvoyée
Aucune valeur de retour. Cette rubrique décrit les champs modifiés et le moment où les changements prennent effet.
Conditions et limites
Utilisez des unités entières cohérentes pour les positions, rayons, demi-dimensions, vitesses et la gravité. Un pas correspond à un tick de simulation. Les exemples utilisent une unité par pixel. Ces routines ne convertissent pas automatiquement les positions en Q8.8 et n’effectuent aucun rendu.
Met restitution_q8 à zéro. Un corps NULL est ignoré. Fournissez des demi-dimensions positives.
Exemple d’utilisation
kq2d_body_init(&temp,10,20,8,8);
result[3]=temp.inv_mass_q8; result[4]=temp.active;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
À gauche, l’état initial ; à droite, après un tick. Une boîte rouge de 16x16, centrée en (24,24) avec une vitesse de (4,16), atteint (28,36) et sa vitesse Y s’annule sur le sol bleu. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48). Sur DMG, tous les repères sont noirs. Les contrôles RAM couvrent aussi l’initialisation, les fonctions de réglage, l’intégration, les tests de rectangles et de points et la mise à l’échelle signée.


Commande de compilation
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-disasmImplémentation et source
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
Consultez les changements et vérifications du 2026-10-03 pour les différences locales de cette API.
Estime prudemment la longueur du vecteur et met les deux axes à l’échelle ensemble pour limiter la vitesse résultante.
Syntaxe
void kq2d_body_limit_speed(KQBody2D* body, s16 max_speed);Paramètres
bodyPointeur vers le corps à modifier. Les champs non utilisés par cette opération sont conservés.
max_speedLimite de vitesse. La rubrique précise si elle s’applique à chaque axe ou au vecteur résultant.
Valeur renvoyée
Aucune valeur de retour. Cette rubrique décrit les champs modifiés et le moment où les changements prennent effet.
Conditions et limites
Gardez les valeurs absolues des composantes de vitesse et un max_speed positif à 16383 au plus. Une limite nulle ou négative annule la vitesse. NULL est ignoré, mais ni l’activité ni la masse n’empêchentntntntntntntntnt la modification. La quantification entière peut donner un résultat inférieur à la limite, et un très petit facteur peut produire zéro.
Exemple d’utilisation
kq2d_body_limit_speed(&body,250);
result[2]=body.vx; result[3]=body.vy;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le corps rouge reste en place. Son vecteur vitesse vert passe de (8,16) à gauche à (2,-8) à droite, montrant le rebond et le frottement tangent sur la surface bleue. Les origines des panneaux sont en (8,48)/(88,48) à l’écran ; le centre du corps est en (24,40) dans chaque panneau. La vitesse d’approche vaut 16 et l’exemple de temps de franchissement renvoie 192/256. L’exemple de limitation de vitesse réduit (300,400) à (147,196). Tous les repères sont noirs sur DMG.


Commande de compilation
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-disasmImplémentation et source
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
Consultez les changements et vérifications du 2026-10-03 pour les différences locales de cette API.
Utilise la vitesse relative à une surface mobile pour appliquer un rebond normal, une vitesse minimale de rebond et un frottement tangent.
Syntaxe
s16 kq2d_body_resolve_surface(KQBody2D* body, const KQSurface2D* surface);Paramètres
bodyPointeur vers le corps à modifier. Les champs non utilisés par cette opération sont conservés.
surfacePointeur vers une KQSurface2D contenant sa normale, sa vitesse et ses paramètres de rebond et de frottement.
Valeur renvoyée
Renvoie la vitesse normale d’approche positive, ou 0 si une entrée est NULL ou si le mouvement s’éloigne de la surface.
Conditions et limites
Utilisez une normale unitaire Q8 de longueur 256. Gardez les composantes relatives dans +/-8191, threshold/kick positifs ou nuls et les coefficients dans 0..255. La restitution ne s’applique que strictement au-dessus du seuil ; kick fixe une vitesse minimale de rebond. Des entrées NULL ou un mouvement d’éloignement laissent la vitesse inchangée. La détection de contact et la correction de pénétration sont séparées ; l’activité et la masse ne sont pas vérifiées.
Exemple d’utilisation
result[6]=kq2d_body_resolve_surface(&body,&surface);
result[7]=body.vx; result[8]=body.vy; result[9]=body.y;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le corps rouge reste en place. Son vecteur vitesse vert passe de (8,16) à gauche à (2,-8) à droite, montrant le rebond et le frottement tangent sur la surface bleue. Les origines des panneaux sont en (8,48)/(88,48) à l’écran ; le centre du corps est en (24,40) dans chaque panneau. La vitesse d’approche vaut 16 et l’exemple de temps de franchissement renvoie 192/256. L’exemple de limitation de vitesse réduit (300,400) à (147,196). Tous les repères sont noirs sur DMG.


Commande de compilation
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-disasmImplémentation et source
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
Remplace uniquement le centre du corps, en conservant sa vitesse, ses dimensions et son état d’activité.
Syntaxe
void kq2d_body_set_pos(KQBody2D* body, s16 x, s16 y);Paramètres
bodyPointeur vers le corps à modifier. Les champs non utilisés par cette opération sont conservés.
xCoordonnée X du centre ou du point, en pixels dans l’exemple.
yCoordonnée Y du centre ou du point ; le sens positif va vers le bas dans l’exemple.
Valeur renvoyée
Aucune valeur de retour. Cette rubrique décrit les champs modifiés et le moment où les changements prennent effet.
Conditions et limites
Utilisez des unités entières cohérentes pour les positions, rayons, demi-dimensions, vitesses et la gravité. Un pas correspond à un tick de simulation. Les exemples utilisent une unité par pixel. Ces routines ne convertissent pas automatiquement les positions en Q8.8 et n’effectuent aucun rendu.
NULL est ignoré. Si le pointeur est valide, les corps inactifs et statiques sont également modifiés.
Exemple d’utilisation
kq2d_body_set_pos(&temp,-12,20);
result[5]=temp.x; result[6]=temp.y;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
À gauche, l’état initial ; à droite, après un tick. Une boîte rouge de 16x16, centrée en (24,24) avec une vitesse de (4,16), atteint (28,36) et sa vitesse Y s’annule sur le sol bleu. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48). Sur DMG, tous les repères sont noirs. Les contrôles RAM couvrent aussi l’initialisation, les fonctions de réglage, l’intégration, les tests de rectangles et de points et la mise à l’échelle signée.


Commande de compilation
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-disasmImplémentation et source
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
Fixe directement la vitesse, sans la borner ni modifier la position.
Syntaxe
void kq2d_body_set_velocity(KQBody2D* body, s16 vx, s16 vy);Paramètres
bodyPointeur vers le corps à modifier. Les champs non utilisés par cette opération sont conservés.
vxDéplacement selon X par tick de simulation, dans les mêmes unités que la position.
vyDéplacement selon Y par tick de simulation, dans les mêmes unités que la position.
Valeur renvoyée
Aucune valeur de retour. Cette rubrique décrit les champs modifiés et le moment où les changements prennent effet.
Conditions et limites
Utilisez des unités entières cohérentes pour les positions, rayons, demi-dimensions, vitesses et la gravité. Un pas correspond à un tick de simulation. Les exemples utilisent une unité par pixel. Ces routines ne convertissent pas automatiquement les positions en Q8.8 et n’effectuent aucun rendu.
NULL est ignoré. Si le pointeur est valide, les corps inactifs et statiques sont également modifiés.
Exemple d’utilisation
kq2d_body_set_velocity(&temp,40,-30);
result[7]=temp.vx; result[8]=temp.vy;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
À gauche, l’état initial ; à droite, après un tick. Une boîte rouge de 16x16, centrée en (24,24) avec une vitesse de (4,16), atteint (28,36) et sa vitesse Y s’annule sur le sol bleu. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48). Sur DMG, tous les repères sont noirs. Les contrôles RAM couvrent aussi l’initialisation, les fonctions de réglage, l’intégration, les tests de rectangles et de points et la mise à l’échelle signée.


Commande de compilation
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-disasmImplémentation et source
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
Applique la gravité du monde et les limites de vitesse par axe à un corps dynamique, puis ajoute sa vitesse à sa position.
Syntaxe
void kq2d_integrate_body(KQWorld2D* world, KQBody2D* body);Paramètres
worldPointeur vers le monde contenant le tableau de corps et les paramètres de simulation.
bodyPointeur vers le corps à modifier. Les champs non utilisés par cette opération sont conservés.
Valeur renvoyée
Aucune valeur de retour. Cette rubrique décrit les champs modifiés et le moment où les changements prennent effet.
Conditions et limites
Utilisez des unités entières cohérentes pour les positions, rayons, demi-dimensions, vitesses et la gravité. Un pas correspond à un tick de simulation. Les exemples utilisent une unité par pixel. Ces routines ne convertissent pas automatiquement les positions en Q8.8 et n’effectuent aucun rendu.
Veillez à ce que sommes, différences, sommes de demi-dimensions et produits de correction des contacts restent dans la plage d’un entier signé de 16 bits. La limitation de vitesse intervient après l’addition et ne peut donc pas empêcher un dépassement pendant celle-ci.
Les routines d’intégration et de collision des boîtes partagent une zone de travail. Ne les rappelez pas depuis une interruption lorsqu’elles sont déjà en cours d’exécution.
Ignore NULL, les corps inactifs et ceux dont la masse inverse est nulle ou négative. Fournissez une limite de vitesse positive ou nulle.
Cet appel ne résout pas les contacts avec d’autres corps. Un monde NULL est également ignoré.
Exemple d’utilisation
kq2d_integrate_body(&world,&temp);
result[18]=temp.x; result[19]=temp.y;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
À gauche, l’état initial ; à droite, après un tick. Une boîte rouge de 16x16, centrée en (24,24) avec une vitesse de (4,16), atteint (28,36) et sa vitesse Y s’annule sur le sol bleu. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48). Sur DMG, tous les repères sont noirs. Les contrôles RAM couvrent aussi l’initialisation, les fonctions de réglage, l’intégration, les tests de rectangles et de points et la mise à l’échelle signée.


Commande de compilation
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-disasmImplémentation et source
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
Teste le chevauchement strict de deux boîtes définies par leur centre sur les axes X et Y.
Syntaxe
u8 kq2d_overlap_aabb(const KQBody2D* a, const KQBody2D* b);Paramètres
aPointeur valide vers un corps. La requête ignore l’activité, la masse et les indicateurs.
bPointeur valide vers un corps. La requête ignore l’activité, la masse et les indicateurs.
Valeur renvoyée
Renvoie 1 si les intérieurs se chevauchent, et 0 si les formes se touchent seulement ou sont séparées.
Conditions et limites
Utilisez des unités entières cohérentes pour les positions, rayons, demi-dimensions, vitesses et la gravité. Un pas correspond à un tick de simulation. Les exemples utilisent une unité par pixel. Ces routines ne convertissent pas automatiquement les positions en Q8.8 et n’effectuent aucun rendu.
Veillez à ce que sommes, différences, sommes de demi-dimensions et produits de correction des contacts restent dans la plage d’un entier signé de 16 bits. La limitation de vitesse intervient après l’addition et ne peut donc pas empêcher un dépassement pendant celle-ci.
Exemple d’utilisation
result[20]=kq2d_overlap_aabb(&bodies[0],&bodies[1]);
bodies[1].x=40; result[21]=kq2d_overlap_aabb(&bodies[0],&bodies[1]);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
À gauche, l’état initial ; à droite, après un tick. Une boîte rouge de 16x16, centrée en (24,24) avec une vitesse de (4,16), atteint (28,36) et sa vitesse Y s’annule sur le sol bleu. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48). Sur DMG, tous les repères sont noirs. Les contrôles RAM couvrent aussi l’initialisation, les fonctions de réglage, l’intégration, les tests de rectangles et de points et la mise à l’échelle signée.


Commande de compilation
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-disasmImplémentation et source
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
Teste si un point appartient au rectangle, bords gauche et supérieur inclus, bords droit et inférieur exclus.
Syntaxe
u8 kq2d_point_in_rect(s16 x, s16 y, KQRect r);Paramètres
xCoordonnée X du centre ou du point, en pixels dans l’exemple.
yCoordonnée Y du centre ou du point ; le sens positif va vers le bas dans l’exemple.
rValeur KQRect contenant la position x/y du coin supérieur gauche et la largeur/hauteur w/h.
Valeur renvoyée
Renvoie 1 à l’intérieur et 0 à l’extérieur.
Conditions et limites
Veillez à ce que sommes, différences, sommes de demi-dimensions et produits de correction des contacts restent dans la plage d’un entier signé de 16 bits. La limitation de vitesse intervient après l’addition et ne peut donc pas empêcher un dépassement pendant celle-ci.
Exemple d’utilisation
result[16]=kq2d_point_in_rect(0,0,r1);
result[17]=kq2d_point_in_rect(16,0,r1);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
À gauche, l’état initial ; à droite, après un tick. Une boîte rouge de 16x16, centrée en (24,24) avec une vitesse de (4,16), atteint (28,36) et sa vitesse Y s’annule sur le sol bleu. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48). Sur DMG, tous les repères sont noirs. Les contrôles RAM couvrent aussi l’initialisation, les fonctions de réglage, l’intégration, les tests de rectangles et de points et la mise à l’échelle signée.


Commande de compilation
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-disasmImplémentation et source
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
Teste le chevauchement intérieur de deux rectangles représentés par leur coin supérieur gauche et leurs dimensions.
Syntaxe
u8 kq2d_rect_intersect(KQRect a, KQRect b);Paramètres
aValeur KQRect avec les coordonnées du coin supérieur gauche et une largeur et une hauteur positives.
bValeur KQRect avec les coordonnées du coin supérieur gauche et une largeur et une hauteur positives.
Valeur renvoyée
Renvoie 1 si les intérieurs se chevauchent, et 0 si les formes se touchent seulement ou sont séparées.
Conditions et limites
Veillez à ce que sommes, différences, sommes de demi-dimensions et produits de correction des contacts restent dans la plage d’un entier signé de 16 bits. La limitation de vitesse intervient après l’addition et ne peut donc pas empêcher un dépassement pendant celle-ci.
Les dimensions nulles ou négatives ne sont pas explicitement rejetées. Ne copiez pas directement le centre et les demi-dimensions d’un corps dans un KQRect.
Exemple d’utilisation
result[14]=kq2d_rect_intersect(r1,r2);
r2.x=16; result[15]=kq2d_rect_intersect(r1,r2);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
À gauche, l’état initial ; à droite, après un tick. Une boîte rouge de 16x16, centrée en (24,24) avec une vitesse de (4,16), atteint (28,36) et sa vitesse Y s’annule sur le sol bleu. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48). Sur DMG, tous les repères sont noirs. Les contrôles RAM couvrent aussi l’initialisation, les fonctions de réglage, l’intégration, les tests de rectangles et de points et la mise à l’échelle signée.


Commande de compilation
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-disasmImplémentation et source
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
Consultez les changements et vérifications du 2026-10-03 pour les différences locales de cette API.
Multiplie par un coefficient signé divisé par 256, avec troncature vers zéro pour les deux signes.
Syntaxe
s16 kq2d_scale_q8(s16 value, s16 coefficient);Paramètres
valueValeur signée de 16 bits à mettre à l’échelle.
coefficientCoefficient signé de -256 à 256 ; 256 représente 1,0.
Valeur renvoyée
Renvoie le résultat signé de 16 bits, tronqué vers zéro.
Conditions et limites
Utilisez uniquement des coefficients de -256 à 256 ; +/-256 correspond à +/-1. Pour value=-32768 et coefficient=-256, le résultat mathématique est 32768, qui ne tient pas dans un s16.
Exemple d’utilisation
result[0]=kq2d_scale_q8(-257,128);
result[1]=kq2d_scale_q8(300,-256);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le corps rouge reste en place. Son vecteur vitesse vert passe de (8,16) à gauche à (2,-8) à droite, montrant le rebond et le frottement tangent sur la surface bleue. Les origines des panneaux sont en (8,48)/(88,48) à l’écran ; le centre du corps est en (24,40) dans chaque panneau. La vitesse d’approche vaut 16 et l’exemple de temps de franchissement renvoie 192/256. L’exemple de limitation de vitesse réduit (300,400) à (147,196). Tous les repères sont noirs sur DMG.


Commande de compilation
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-disasmImplémentation et source
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
Intègre les corps dynamiques actifs, puis résout les contacts entre les entrées actives du tableau.
Syntaxe
void kq2d_step(KQWorld2D* world);Paramètres
worldPointeur vers le monde contenant le tableau de corps et les paramètres de simulation.
Valeur renvoyée
Aucune valeur de retour. Cette rubrique décrit les champs modifiés et le moment où les changements prennent effet.
Conditions et limites
Utilisez des unités entières cohérentes pour les positions, rayons, demi-dimensions, vitesses et la gravité. Un pas correspond à un tick de simulation. Les exemples utilisent une unité par pixel. Ces routines ne convertissent pas automatiquement les positions en Q8.8 et n’effectuent aucun rendu.
Le monde emprunte son tableau : l’appelant alloue et possède la mémoire des corps et doit la garder valide. Initialiser le monde n’initialise pas les éléments du tableau.
Veillez à ce que sommes, différences, sommes de demi-dimensions et produits de correction des contacts restent dans la plage d’un entier signé de 16 bits. La limitation de vitesse intervient après l’addition et ne peut donc pas empêcher un dépassement pendant celle-ci.
Les contacts sont résolus selon l’axe de pénétration minimale, avec priorité à Y en cas d’égalité. La correction de position utilise les masses inverses, mais deux corps dynamiques reçoivent la moyenne simple de leurs vitesses sur cet axe ; une collision avec un corps statique annule cette composante. Le solveur n’utilise pas restitution_q8. La détection est discrète et peut manquer des traversées rapides.
Les routines d’intégration et de collision des boîtes partagent une zone de travail. Ne les rappelez pas depuis une interruption lorsqu’elles sont déjà en cours d’exécution.
Un monde ou un tableau NULL est ignoré. Même si solver_iterations vaut zéro, une passe de résolution des contacts est effectuée.
Exemple d’utilisation
kq2d_step(&world);
result[22]=bodies[0].x; result[23]=bodies[0].y;
result[24]=bodies[0].vx; result[25]=bodies[0].vy;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
À gauche, l’état initial ; à droite, après un tick. Une boîte rouge de 16x16, centrée en (24,24) avec une vitesse de (4,16), atteint (28,36) et sa vitesse Y s’annule sur le sol bleu. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48). Sur DMG, tous les repères sont noirs. Les contrôles RAM couvrent aussi l’initialisation, les fonctions de réglage, l’intégration, les tests de rectangles et de points et la mise à l’échelle signée.


Commande de compilation
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-disasmImplémentation et source
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
Estime l’instant de franchissement à l’intérieur du tick à partir des écarts signés initial et final, en supposant un mouvement linéaire.
Syntaxe
u16 kq2d_surface_toi_q8(s16 start_gap, s16 end_gap);Paramètres
start_gapÉcart signé au début du tick ; une valeur positive indique l’extérieur de la surface.
end_gapÉcart signé à la fin du tick ; une valeur négative indique que la surface a été franchie.
Valeur renvoyée
Renvoie un temps Q8 de 0 à 256 ; 192 représente 75 % du tick.
Conditions et limites
Gardez les écarts dans +/-8191. Un écart initial nul ou négatif renvoie 0 ; un écart final nul ou positif renvoie 256. Le chevauchement initial et l’instant zéro partagent la même valeur de retour, tout comme l’absence de franchissement et un contact exactement à la fin. Aucune position n’est modifiée.
Exemple d’utilisation
result[4]=kq2d_surface_toi_q8(6,-2);
result[5]=kq2d_surface_toi_q8(6,0);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le corps rouge reste en place. Son vecteur vitesse vert passe de (8,16) à gauche à (2,-8) à droite, montrant le rebond et le frottement tangent sur la surface bleue. Les origines des panneaux sont en (8,48)/(88,48) à l’écran ; le centre du corps est en (24,40) dans chaque panneau. La vitesse d’approche vaut 16 et l’exemple de temps de franchissement renvoie 192/256. L’exemple de limitation de vitesse réduit (300,400) à (147,196). Tous les repères sont noirs sur DMG.


Commande de compilation
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-disasmImplémentation et source
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
Associe un tableau à un monde 2D et règle la gravité à (0,32), le nombre d’itérations de contact à quatre et la limite de vitesse par axe à 512.
Syntaxe
void kq2d_world_init(KQWorld2D* world, KQBody2D* bodies, u8 body_count);Paramètres
worldPointeur vers le monde contenant le tableau de corps et les paramètres de simulation.
bodiesDébut d’un tableau de corps appartenant à l’appelant et contenant body_count éléments.
body_countNombre d’emplacements du tableau, de 0 à 255, entrées inactives comprises.
Valeur renvoyée
Aucune valeur de retour. Cette rubrique décrit les champs modifiés et le moment où les changements prennent effet.
Conditions et limites
Utilisez des unités entières cohérentes pour les positions, rayons, demi-dimensions, vitesses et la gravité. Un pas correspond à un tick de simulation. Les exemples utilisent une unité par pixel. Ces routines ne convertissent pas automatiquement les positions en Q8.8 et n’effectuent aucun rendu.
Le monde emprunte son tableau : l’appelant alloue et possède la mémoire des corps et doit la garder valide. Initialiser le monde n’initialise pas les éléments du tableau.
Exemple d’utilisation
kq2d_world_init(&world,bodies,2);
result[0]=world.gravity_y; result[1]=world.solver_iterations; result[2]=world.max_speed;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
À gauche, l’état initial ; à droite, après un tick. Une boîte rouge de 16x16, centrée en (24,24) avec une vitesse de (4,16), atteint (28,36) et sa vitesse Y s’annule sur le sol bleu. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48). Sur DMG, tous les repères sont noirs. Les contrôles RAM couvrent aussi l’initialisation, les fonctions de réglage, l’intégration, les tests de rectangles et de points et la mise à l’échelle signée.


Commande de compilation
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-disasmImplémentation et source
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 — Physique des cercles
Gère le rayon des cercles, la masse inverse, la restitution, le frottement tangent, l’amortissement du monde et ses limites. L’appelant initialise tous les champs des corps. friction_q8 et wall_friction_q8 indiquent la part de mouvement tangent supprimée, tandis que linear_damping_q8 indique la part de vitesse conservée. Les coefficients sur un octet sont divisés par 256 : 255 n’est donc pas exactement 1,0.
Utilisez des unités entières cohérentes pour les positions, rayons, demi-dimensions, vitesses et la gravité. Un pas correspond à un tick de simulation. Les exemples utilisent une unité par pixel. Ces routines ne convertissent pas automatiquement les positions en Q8.8 et n’effectuent aucun rendu.
La distance et les normales des cercles sont des approximations entières. Ramener chaque composante à 255 au plus ne garantit pas que la somme des carrés tienne dans 65535. Gardez les écarts entre centres, les sommes de rayons et de masses inverses dans leur plage représentable, et limitez inv_mass_q8 * 255 à 32767 pour le calcul des poids ; l’exemple utilise 64.
kq2dc_overlap_circle
Approxime le chevauchement intérieur à partir de la distance réduite entre centres et de la somme des rayons.
Syntaxe
u8 kq2dc_overlap_circle(const KQCircleBody2D* a, const KQCircleBody2D* b);Paramètres
aPointeur valide vers le premier cercle.
bPointeur valide vers le second cercle.
Valeur renvoyée
Renvoie 1 si les intérieurs se chevauchent, et 0 si les formes se touchent seulement ou sont séparées.
Conditions et limites
Utilisez des unités entières cohérentes pour les positions, rayons, demi-dimensions, vitesses et la gravité. Un pas correspond à un tick de simulation. Les exemples utilisent une unité par pixel. Ces routines ne convertissent pas automatiquement les positions en Q8.8 et n’effectuent aucun rendu.
La distance et les normales des cercles sont des approximations entières. Ramener chaque composante à 255 au plus ne garantit pas que la somme des carrés tienne dans 65535. Gardez les écarts entre centres, les sommes de rayons et de masses inverses dans leur plage représentable, et limitez inv_mass_q8 * 255 à 32767 pour le calcul des poids ; l’exemple utilise 64.
Nécessite deux pointeurs valides et des rayons positifs. L’activité et la masse sont ignorées. La réduction et les racines carrées entières peuvent donner un résultat différent d’un test de distance géométrique exact.
Exemple d’utilisation
result[4]=kq2dc_overlap_circle(&balls[0],&balls[1]);
balls[1].x=18; result[5]=kq2dc_overlap_circle(&balls[0],&balls[1]);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Un cercle rouge de rayon 6 passe du centre (24,24) à gauche à (54,24) à droite. Les limites locales vont de (4,4) à (60,60). Le mur droit borne le centre à 54 et fait passer la vitesse X de 32 à -15 : restitution du mur de 128/256, puis amortissement de 255/256. Les origines des panneaux sont en (8,48)/(88,48) à l’écran. Sur DMG, le cercle et les limites sont noirs.


Commande de compilation
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-disasmImplémentation et source
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
Enregistre et active les limites du monde de cercles, sans déplacer immédiatement les corps.
Syntaxe
void kq2dc_set_bounds(KQCircleWorld2D* world, s16 min_x, s16 min_y, s16 max_x, s16 max_y);Paramètres
worldPointeur vers le monde contenant le tableau de corps et les paramètres de simulation.
min_xLimite gauche ; le centre du cercle ne peut pas descendre sous min_x + radius.
min_yLimite supérieure ; le centre du cercle ne peut pas descendre sous min_y + radius.
max_xLimite droite ; le centre du cercle ne peut pas dépasser max_x - radius.
max_yLimite inférieure ; le centre du cercle ne peut pas dépasser max_y - radius.
Valeur renvoyée
Aucune valeur de retour. Cette rubrique décrit les champs modifiés et le moment où les changements prennent effet.
Conditions et limites
Utilisez des unités entières cohérentes pour les positions, rayons, demi-dimensions, vitesses et la gravité. Un pas correspond à un tick de simulation. Les exemples utilisent une unité par pixel. Ces routines ne convertissent pas automatiquement les positions en Q8.8 et n’effectuent aucun rendu.
NULL est ignoré. L’ordre des limites et l’espace disponible ne sont pas vérifiés : fournissez une largeur et une hauteur au moins égales au diamètre du cercle. La correction de position est effectuée lors d’un pas de simulation.
Exemple d’utilisation
kq2dc_set_bounds(&world,4,4,60,60);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Un cercle rouge de rayon 6 passe du centre (24,24) à gauche à (54,24) à droite. Les limites locales vont de (4,4) à (60,60). Le mur droit borne le centre à 54 et fait passer la vitesse X de 32 à -15 : restitution du mur de 128/256, puis amortissement de 255/256. Les origines des panneaux sont en (8,48)/(88,48) à l’écran. Sur DMG, le cercle et les limites sont noirs.


Commande de compilation
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-disasmImplémentation et source
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
Intègre les cercles, résout les limites et les contacts entre cercles, puis applique l’amortissement linéaire.
Syntaxe
void kq2dc_step(KQCircleWorld2D* world);Paramètres
worldPointeur vers le monde contenant le tableau de corps et les paramètres de simulation.
Valeur renvoyée
Aucune valeur de retour. Cette rubrique décrit les champs modifiés et le moment où les changements prennent effet.
Conditions et limites
Utilisez des unités entières cohérentes pour les positions, rayons, demi-dimensions, vitesses et la gravité. Un pas correspond à un tick de simulation. Les exemples utilisent une unité par pixel. Ces routines ne convertissent pas automatiquement les positions en Q8.8 et n’effectuent aucun rendu.
Le monde emprunte son tableau : l’appelant alloue et possède la mémoire des corps et doit la garder valide. Initialiser le monde n’initialise pas les éléments du tableau.
La distance et les normales des cercles sont des approximations entières. Ramener chaque composante à 255 au plus ne garantit pas que la somme des carrés tienne dans 65535. Gardez les écarts entre centres, les sommes de rayons et de masses inverses dans leur plage représentable, et limitez inv_mass_q8 * 255 à 32767 pour le calcul des poids ; l’exemple utilise 64.
Enfin, ramène à zéro les composantes de vitesse dans -1..1. Même un amortissement de 255 réduit un peu la vitesse. Des chevauchements entre cercles au repos peuvent subsister. Les cercles statiques sont eux aussi ramenés à l’intérieur des limites actives. Zéro itération signifie une passe ; un monde ou tableau NULL est ignoré. Ce solveur discret et quantifié peut traiter les contacts dans un ordre différent selon l’évolution des vitesses.
Exemple d’utilisation
kq2dc_step(&world);
result[6]=balls[0].x; result[7]=balls[0].y; result[8]=balls[0].vx;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Un cercle rouge de rayon 6 passe du centre (24,24) à gauche à (54,24) à droite. Les limites locales vont de (4,4) à (60,60). Le mur droit borne le centre à 54 et fait passer la vitesse X de 32 à -15 : restitution du mur de 128/256, puis amortissement de 255/256. Les origines des panneaux sont en (8,48)/(88,48) à l’écran. Sur DMG, le cercle et les limites sont noirs.


Commande de compilation
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-disasmImplémentation et source
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
Associe un tableau de cercles et règle la gravité à zéro, le nombre de passes à quatre, la limite par axe à 768 et l’amortissement à 252/256.
Syntaxe
void kq2dc_world_init(KQCircleWorld2D* world, KQCircleBody2D* bodies, u8 body_count);Paramètres
worldPointeur vers le monde contenant le tableau de corps et les paramètres de simulation.
bodiesDébut d’un tableau de corps appartenant à l’appelant et contenant body_count éléments.
body_countNombre d’emplacements du tableau, de 0 à 255, entrées inactives comprises.
Valeur renvoyée
Aucune valeur de retour. Cette rubrique décrit les champs modifiés et le moment où les changements prennent effet.
Conditions et limites
Utilisez des unités entières cohérentes pour les positions, rayons, demi-dimensions, vitesses et la gravité. Un pas correspond à un tick de simulation. Les exemples utilisent une unité par pixel. Ces routines ne convertissent pas automatiquement les positions en Q8.8 et n’effectuent aucun rendu.
Le monde emprunte son tableau : l’appelant alloue et possède la mémoire des corps et doit la garder valide. Initialiser le monde n’initialise pas les éléments du tableau.
Les limites sont initialement désactivées, avec les valeurs (0,0)..(159,143) ; la restitution des murs vaut 240 et leur frottement 16. Il n’existe pas de fonction d’initialisation des cercles : l’appelant doit renseigner tous les champs. Un monde NULL est ignoré.
Exemple d’utilisation
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;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Un cercle rouge de rayon 6 passe du centre (24,24) à gauche à (54,24) à droite. Les limites locales vont de (4,4) à (60,60). Le mur droit borne le centre à 54 et fait passer la vitesse X de 32 à -15 : restitution du mur de 128/256, puis amortissement de 255/256. Les origines des panneaux sont en (8,48)/(88,48) à l’écran. Sur DMG, le cercle et les limites sont noirs.


Commande de compilation
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-disasmImplémentation et source
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 — Physique des AABB en 3D
Physique pour des boîtes 3D sans rotation, représentées par un centre et des demi-dimensions par axe. Masse et masse inverse pondèrent les contacts, restitution_q8 règle le rebond et ax/ay/az fournissent une accélération persistante. Le rendu est séparé. L’exemple affiche les vues de face et de dessus du même corps pour montrer le déplacement en profondeur et le rebond sur un mur.
Utilisez des unités entières cohérentes pour les positions, rayons, demi-dimensions, vitesses et la gravité. Un pas correspond à un tick de simulation. Les exemples utilisent une unité par pixel. Ces routines ne convertissent pas automatiquement les positions en Q8.8 et n’effectuent aucun rendu.
physics3d.c réside dans la banque ROM 2. L’exemple utilise une ROM MBC5 de 128 Ko, inclut d’abord cette implémentation et place main dans la banque 0. Ne modifiez pas le mappage ROM depuis l’extérieur pendant un appel.
last_impact_speed mémorise la vitesse maximale de rapprochement sur un axe de contact. L’intégration la remet à zéro pour les corps dynamiques actifs ; les corps statiques ou inactifs la conservent. Ni break_speed ni KQ3D_BODY_BROKEN ne déclenche une destruction automatique. Le jeu décide quand casser un corps et modifie lui-même flags/active.
kq3d_body_init
Initialise le centre 3D, les demi-dimensions et la masse ; remet à zéro vitesse, accélération, impact et indicateurs, puis active le corps.
Syntaxe
void kq3d_body_init(KQBody3D* body, s16 x, s16 y, s16 z, s16 half_x, s16 half_y, s16 half_z, s16 mass_q8);Paramètres
bodyPointeur vers le corps à modifier. Les champs non utilisés par cette opération sont conservés.
xCoordonnée X du centre ou du point, en pixels dans l’exemple.
yCoordonnée Y du centre ou du point ; le sens positif va vers le bas dans l’exemple.
zCoordonnée Z du centre, représentée verticalement dans la vue de dessus de l’exemple.
half_xDemi-dimension selon X ; la largeur totale de la boîte vaut deux fois cette valeur.
half_yDemi-dimension selon Y ; la hauteur totale de la boîte vaut deux fois cette valeur.
half_zDemi-dimension selon Z ; la profondeur totale vaut deux fois cette valeur.
mass_q8Masse, avec 256 pour 1,0 ; une valeur nulle ou négative crée un corps statique.
Valeur renvoyée
Aucune valeur de retour. Cette rubrique décrit les champs modifiés et le moment où les changements prennent effet.
Conditions et limites
Utilisez des unités entières cohérentes pour les positions, rayons, demi-dimensions, vitesses et la gravité. Un pas correspond à un tick de simulation. Les exemples utilisent une unité par pixel. Ces routines ne convertissent pas automatiquement les positions en Q8.8 et n’effectuent aucun rendu.
physics3d.c réside dans la banque ROM 2. L’exemple utilise une ROM MBC5 de 128 Ko, inclut d’abord cette implémentation et place main dans la banque 0. Ne modifiez pas le mappage ROM depuis l’extérieur pendant un appel.
La restitution vaut 224 et break_speed zéro. La masse suit les règles de kq3d_body_set_mass. NULL est ignoré ; l’appelant doit fournir des demi-dimensions valides.
Exemple d’utilisation
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;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
À gauche, la vue de face X/Y ; à droite, la vue de dessus X/Z. Les contours verts indiquent la position initiale (24,24,16), les boîtes rouges la position (36,24,24) après un tick, et les zones bleues l’obstacle statique. La vitesse X passe de 16 à -14 par rebond, tandis que la vitesse Z reste à 8. L’impact vaut 16, mais flags reste à zéro malgré break_speed=1. Les origines des panneaux sont en (8,48)/(88,48) à l’écran. Tous les repères sont noirs sur DMG.


Commande de compilation
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-disasmImplémentation et source
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
Enregistre la masse demandée et calcule un poids de masse inverse pour la correction et le rebond.
Syntaxe
void kq3d_body_set_mass(KQBody3D* body, s16 mass_q8);Paramètres
bodyPointeur vers le corps à modifier. Les champs non utilisés par cette opération sont conservés.
mass_q8Masse, avec 256 pour 1,0 ; une valeur nulle ou négative crée un corps statique.
Valeur renvoyée
Aucune valeur de retour. Cette rubrique décrit les champs modifiés et le moment où les changements prennent effet.
Conditions et limites
physics3d.c réside dans la banque ROM 2. L’exemple utilise une ROM MBC5 de 128 Ko, inclut d’abord cette implémentation et place main dans la banque 0. Ne modifiez pas le mappage ROM depuis l’extérieur pendant un appel.
Une masse nulle ou négative donne une masse inverse nulle, donc un corps statique. Pour une masse positive, le calcul entier est 32767/max(mass,64), avec un minimum de 1. La masse stockée conserve la valeur demandée : le poids obtenu n’est pas un inverse Q8 exact. Une masse de 256 donne une masse inverse de 127. Vitesse et activité restent inchangées ; NULL est ignoré.
Exemple d’utilisation
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);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
À gauche, la vue de face X/Y ; à droite, la vue de dessus X/Z. Les contours verts indiquent la position initiale (24,24,16), les boîtes rouges la position (36,24,24) après un tick, et les zones bleues l’obstacle statique. La vitesse X passe de 16 à -14 par rebond, tandis que la vitesse Z reste à 8. L’impact vaut 16, mais flags reste à zéro malgré break_speed=1. Les origines des panneaux sont en (8,48)/(88,48) à l’écran. Tous les repères sont noirs sur DMG.


Commande de compilation
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-disasmImplémentation et source
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
Divise chacun des trois produits signés par 256, tronque chaque terme vers zéro, puis additionne les termes.
Syntaxe
s16 kq3d_dot_q8_8(s16 x, s16 y, s16 z, s8 ax, s8 ay, s8 az);Paramètres
xComposante signée de 16 bits à multiplier par le coefficient correspondant ; elle peut représenter une position ou une vitesse.
yComposante signée de 16 bits à multiplier par le coefficient correspondant ; elle peut représenter une position ou une vitesse.
zComposante signée de 16 bits à multiplier par le coefficient correspondant ; elle peut représenter une position ou une vitesse.
axCoefficient signé sur un octet pour cet axe (-128..127), appliqué à l’échelle 1/256.
ayCoefficient signé sur un octet pour cet axe (-128..127), appliqué à l’échelle 1/256.
azCoefficient signé sur un octet pour cet axe (-128..127), appliqué à l’échelle 1/256.
Valeur renvoyée
Renvoie la somme des trois termes quantifiés en s16.
Conditions et limites
physics3d.c réside dans la banque ROM 2. L’exemple utilise une ROM MBC5 de 128 Ko, inclut d’abord cette implémentation et place main dans la banque 0. Ne modifiez pas le mappage ROM depuis l’extérieur pendant un appel.
Tronquer chaque terme vers zéro avant la somme peut donner un résultat différent d’un unique décalage de la somme totale. Un coefficient ne peut pas contenir 1,0=256. La somme finale n’est pas saturée.
Exemple d’utilisation
result[13]=kq3d_dot_q8_8(256,128,0,64,-64,127);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
À gauche, la vue de face X/Y ; à droite, la vue de dessus X/Z. Les contours verts indiquent la position initiale (24,24,16), les boîtes rouges la position (36,24,24) après un tick, et les zones bleues l’obstacle statique. La vitesse X passe de 16 à -14 par rebond, tandis que la vitesse Z reste à 8. L’impact vaut 16, mais flags reste à zéro malgré break_speed=1. Les origines des panneaux sont en (8,48)/(88,48) à l’écran. Tous les repères sont noirs sur DMG.


Commande de compilation
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-disasmImplémentation et source
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
Consultez les changements et vérifications du 2026-10-03 pour les différences locales de cette API.
Remet à zéro l’impact d’un corps dynamique actif, ajoute la gravité du monde et l’accélération du corps, borne chaque composante de vitesse puis avance sa position.
Syntaxe
void kq3d_integrate_body(KQWorld3D* world, KQBody3D* body);Paramètres
worldPointeur vers le monde contenant le tableau de corps et les paramètres de simulation.
bodyPointeur vers le corps à modifier. Les champs non utilisés par cette opération sont conservés.
Valeur renvoyée
Aucune valeur de retour. Cette rubrique décrit les champs modifiés et le moment où les changements prennent effet.
Conditions et limites
Utilisez des unités entières cohérentes pour les positions, rayons, demi-dimensions, vitesses et la gravité. Un pas correspond à un tick de simulation. Les exemples utilisent une unité par pixel. Ces routines ne convertissent pas automatiquement les positions en Q8.8 et n’effectuent aucun rendu.
Veillez à ce que sommes, différences, sommes de demi-dimensions et produits de correction des contacts restent dans la plage d’un entier signé de 16 bits. La limitation de vitesse intervient après l’addition et ne peut donc pas empêcher un dépassement pendant celle-ci.
Les routines d’intégration et de collision des boîtes partagent une zone de travail. Ne les rappelez pas depuis une interruption lorsqu’elles sont déjà en cours d’exécution.
physics3d.c réside dans la banque ROM 2. L’exemple utilise une ROM MBC5 de 128 Ko, inclut d’abord cette implémentation et place main dans la banque 0. Ne modifiez pas le mappage ROM depuis l’extérieur pendant un appel.
last_impact_speed mémorise la vitesse maximale de rapprochement sur un axe de contact. L’intégration la remet à zéro pour les corps dynamiques actifs ; les corps statiques ou inactifs la conservent. Ni break_speed ni KQ3D_BODY_BROKEN ne déclenche une destruction automatique. Le jeu décide quand casser un corps et modifie lui-même flags/active.
ax/ay/az persistent et s’appliquent à nouveau à l’intégration suivante. Cette fonction seule ne résout pas les contacts. NULL, les corps inactifs et les corps statiques ne sont pas modifiés.
Exemple d’utilisation
kq3d_integrate_body(&world,&temp);
result[9]=temp.x; result[10]=temp.y; result[11]=temp.z; result[12]=temp.last_impact_speed;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
À gauche, la vue de face X/Y ; à droite, la vue de dessus X/Z. Les contours verts indiquent la position initiale (24,24,16), les boîtes rouges la position (36,24,24) après un tick, et les zones bleues l’obstacle statique. La vitesse X passe de 16 à -14 par rebond, tandis que la vitesse Z reste à 8. L’impact vaut 16, mais flags reste à zéro malgré break_speed=1. Les origines des panneaux sont en (8,48)/(88,48) à l’écran. Tous les repères sont noirs sur DMG.


Commande de compilation
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-disasmImplémentation et source
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
Teste le chevauchement strict de deux boîtes définies par leur centre sur les trois axes.
Syntaxe
u8 kq3d_overlap_aabb(const KQBody3D* a, const KQBody3D* b);Paramètres
aPointeur valide vers un corps. La requête ignore l’activité, la masse et les indicateurs.
bPointeur valide vers un corps. La requête ignore l’activité, la masse et les indicateurs.
Valeur renvoyée
Renvoie 1 si les intérieurs se chevauchent, et 0 si les formes se touchent seulement ou sont séparées.
Conditions et limites
Utilisez des unités entières cohérentes pour les positions, rayons, demi-dimensions, vitesses et la gravité. Un pas correspond à un tick de simulation. Les exemples utilisent une unité par pixel. Ces routines ne convertissent pas automatiquement les positions en Q8.8 et n’effectuent aucun rendu.
Veillez à ce que sommes, différences, sommes de demi-dimensions et produits de correction des contacts restent dans la plage d’un entier signé de 16 bits. La limitation de vitesse intervient après l’addition et ne peut donc pas empêcher un dépassement pendant celle-ci.
physics3d.c réside dans la banque ROM 2. L’exemple utilise une ROM MBC5 de 128 Ko, inclut d’abord cette implémentation et place main dans la banque 0. Ne modifiez pas le mappage ROM depuis l’extérieur pendant un appel.
Exemple d’utilisation
result[14]=kq3d_overlap_aabb(&bodies[0],&bodies[1]);
bodies[1].z=32; result[15]=kq3d_overlap_aabb(&bodies[0],&bodies[1]);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
À gauche, la vue de face X/Y ; à droite, la vue de dessus X/Z. Les contours verts indiquent la position initiale (24,24,16), les boîtes rouges la position (36,24,24) après un tick, et les zones bleues l’obstacle statique. La vitesse X passe de 16 à -14 par rebond, tandis que la vitesse Z reste à 8. L’impact vaut 16, mais flags reste à zéro malgré break_speed=1. Les origines des panneaux sont en (8,48)/(88,48) à l’écran. Tous les repères sont noirs sur DMG.


Commande de compilation
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-disasmImplémentation et source
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
Consultez les changements et vérifications du 2026-10-03 pour les différences locales de cette API.
Intègre les corps dynamiques actifs et traite la correction des contacts, les rebonds et les enregistrements d’impact entre les entrées actives du monde.
Syntaxe
void kq3d_step(KQWorld3D* world);Paramètres
worldPointeur vers le monde contenant le tableau de corps et les paramètres de simulation.
Valeur renvoyée
Aucune valeur de retour. Cette rubrique décrit les champs modifiés et le moment où les changements prennent effet.
Conditions et limites
Utilisez des unités entières cohérentes pour les positions, rayons, demi-dimensions, vitesses et la gravité. Un pas correspond à un tick de simulation. Les exemples utilisent une unité par pixel. Ces routines ne convertissent pas automatiquement les positions en Q8.8 et n’effectuent aucun rendu.
Le monde emprunte son tableau : l’appelant alloue et possède la mémoire des corps et doit la garder valide. Initialiser le monde n’initialise pas les éléments du tableau.
Veillez à ce que sommes, différences, sommes de demi-dimensions et produits de correction des contacts restent dans la plage d’un entier signé de 16 bits. La limitation de vitesse intervient après l’addition et ne peut donc pas empêcher un dépassement pendant celle-ci.
Les routines d’intégration et de collision des boîtes partagent une zone de travail. Ne les rappelez pas depuis une interruption lorsqu’elles sont déjà en cours d’exécution.
physics3d.c réside dans la banque ROM 2. L’exemple utilise une ROM MBC5 de 128 Ko, inclut d’abord cette implémentation et place main dans la banque 0. Ne modifiez pas le mappage ROM depuis l’extérieur pendant un appel.
Les contacts utilisent l’axe de pénétration minimale, avec priorité à X, puis Y, puis Z en cas d’égalité. Seul un mouvement de rapprochement produit un rebond, calculé avec les masses inverses et la restitution moyenne bornée à 0..256. Les traversées rapides, la rotation, le moment cinétique et le frottement ne sont pas gérés.
last_impact_speed mémorise la vitesse maximale de rapprochement sur un axe de contact. L’intégration la remet à zéro pour les corps dynamiques actifs ; les corps statiques ou inactifs la conservent. Ni break_speed ni KQ3D_BODY_BROKEN ne déclenche une destruction automatique. Le jeu décide quand casser un corps et modifie lui-même flags/active.
Un monde ou un tableau NULL est ignoré. Même si solver_iterations vaut zéro, une passe de résolution des contacts est effectuée.
Les produits intermédiaires impact*(256+restitution) et correction*inverse-mass sont eux aussi en s16. Gardez-les à 32767 au plus ; par exemple, avec restitution à 256, limitez impact à 63.
Exemple d’utilisation
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;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
À gauche, la vue de face X/Y ; à droite, la vue de dessus X/Z. Les contours verts indiquent la position initiale (24,24,16), les boîtes rouges la position (36,24,24) après un tick, et les zones bleues l’obstacle statique. La vitesse X passe de 16 à -14 par rebond, tandis que la vitesse Z reste à 8. L’impact vaut 16, mais flags reste à zéro malgré break_speed=1. Les origines des panneaux sont en (8,48)/(88,48) à l’écran. Tous les repères sont noirs sur DMG.


Commande de compilation
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-disasmImplémentation et source
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
Associe un tableau de corps à un monde 3D avec une gravité de (0,24,0), quatre passes et une limite de vitesse par axe de 512.
Syntaxe
void kq3d_world_init(KQWorld3D* world, KQBody3D* bodies, u8 body_count);Paramètres
worldPointeur vers le monde contenant le tableau de corps et les paramètres de simulation.
bodiesDébut d’un tableau de corps appartenant à l’appelant et contenant body_count éléments.
body_countNombre d’emplacements du tableau, de 0 à 255, entrées inactives comprises.
Valeur renvoyée
Aucune valeur de retour. Cette rubrique décrit les champs modifiés et le moment où les changements prennent effet.
Conditions et limites
Utilisez des unités entières cohérentes pour les positions, rayons, demi-dimensions, vitesses et la gravité. Un pas correspond à un tick de simulation. Les exemples utilisent une unité par pixel. Ces routines ne convertissent pas automatiquement les positions en Q8.8 et n’effectuent aucun rendu.
Le monde emprunte son tableau : l’appelant alloue et possède la mémoire des corps et doit la garder valide. Initialiser le monde n’initialise pas les éléments du tableau.
physics3d.c réside dans la banque ROM 2. L’exemple utilise une ROM MBC5 de 128 Ko, inclut d’abord cette implémentation et place main dans la banque 0. Ne modifiez pas le mappage ROM depuis l’extérieur pendant un appel.
Exemple d’utilisation
kq3d_world_init(&world,bodies,2);
result[0]=world.gravity_y; result[1]=world.solver_iterations; result[2]=world.max_speed;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
À gauche, la vue de face X/Y ; à droite, la vue de dessus X/Z. Les contours verts indiquent la position initiale (24,24,16), les boîtes rouges la position (36,24,24) après un tick, et les zones bleues l’obstacle statique. La vitesse X passe de 16 à -14 par rebond, tandis que la vitesse Z reste à 8. L’impact vaut 16, mais flags reste à zéro malgré break_speed=1. Les origines des panneaux sont en (8,48)/(88,48) à l’écran. Tous les repères sont noirs sur DMG.


Commande de compilation
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-disasmImplémentation et source
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 — Tables de défilement par bandes et lignes
La bibliothèque Raster propose une table de huit bandes et un moteur LineX qui modifie X sur les 144 lignes visibles. Les bandes conviennent aux HUD fixes, à la parallaxe, aux changements de fenêtre et aux régions colorées CGB. LineX convient aux titres ondulants et aux effets d’écran. Choisissez un seul pilote ; ne les exécutez pas ensemble.
Incluez raster.h et compilez raster.c ainsi que scroll.c. Une table partagée contient jusqu’à huit bandes. Pendant sa construction avec Raster_*, n’intercalez pas d’appels directs à Scroll_Split* ou __scroll_split_* : ils contournent le suivi du nombre d’entrées et de la dernière ligne par la couche Raster.
Reconstruisez pendant VBlank ou à un moment où vous maîtrisez l’effet sur l’affichage : effacez, ajoutez les entrées, puis validez. L’effacement arrête aussi les divisions actives ; vous ne modifiez pas un tampon arrière indépendant. LY programme une interruption, et les écritures de registres prennent un temps supplémentaire. Pour une ondulation ligne par ligne, utilisez la famille distincte Raster_LineX* ; n’exécutez pas les deux pilotes ensemble.
Vague par lignes de balayage et apparition animée du titre
En modifiant la position X du fond à chaque ligne de l’écran, on fait onduler les piliers et les lettres. Cet effet convient à une téléportation, à l’arrivée d’un boss ou à un titre. L’aperçu ci-dessous fait défiler huit captures ; dans la ROM, la phase de l’onde avance à chaque image.
Les opérations Raster_Push programment jusqu’à huit bandes. Utilisez Raster_LineXRunFrame pour donner un décalage horizontal distinct à chaque ligne. Les sprites et la fenêtre ne sont pas déformés. Le rendu monopolise le CPU et masque les interruptions pendant les 144 lignes visibles ; mettez donc à jour la logique du jeu et l’audio entre les appels.

Le titre arrive de la droite avec une grande ondulation, passe à une petite oscillation puis se stabilise. Le programme inclut raster_wave.c du même répertoire ; gardez donc les deux sources ensemble. Les entrées API ci-dessous donnent les commandes de compilation et les conseils d’utilisation propres à chaque fonction.
La bibliothèque Raster propose une table de huit bandes et un moteur LineX qui modifie X sur les 144 lignes visibles. Les bandes conviennent aux HUD fixes, à la parallaxe, aux changements de fenêtre et aux régions colorées CGB. LineX convient aux titres ondulants et aux effets d’écran. Choisissez un seul pilote ; ne les exécutez pas ensemble.
Incluez raster.h et compilez raster.c ainsi que scroll.c. Une table partagée contient jusqu’à huit bandes. Pendant sa construction avec Raster_*, n’intercalez pas d’appels directs à Scroll_Split* ou __scroll_split_* : ils contournent le suivi du nombre d’entrées et de la dernière ligne par la couche Raster.
Reconstruisez pendant VBlank ou à un moment où vous maîtrisez l’effet sur l’affichage : effacez, ajoutez les entrées, puis validez. L’effacement arrête aussi les divisions actives ; vous ne modifiez pas un tampon arrière indépendant. LY programme une interruption, et les écritures de registres prennent un temps supplémentaire. Pour une ondulation ligne par ligne, utilisez la famille distincte Raster_LineX* ; n’exécutez pas les deux pilotes ensemble.
Raster_BuildHudBottom
Construit une zone de jeu supérieure défilante et un HUD inférieur fixe. LY=0 utilise les coordonnées caméra ; hud_y revient au fond (0,0).
Syntaxe
u8 Raster_BuildHudBottom(u8 hud_y, u8 camera_x, u8 camera_y);Paramètres
hud_yLigne de séparation, de 1 à 143. Zéro et les valeurs à partir de 144 renvoient BAD_RANGE.
camera_xOctet de défilement du fond, de 0 à 255. SCX/SCY indiquent où lire la carte de fond, pas une position à l’écran. Les coordonnées bouclent sur le fond de 256 pixels.
camera_yOctet de défilement du fond, de 0 à 255. SCX/SCY indiquent où lire la carte de fond, pas une position à l’écran. Les coordonnées bouclent sur le fond de 256 pixels.
Valeur renvoyée
Renvoie KQ_RASTER_OK (0) en cas de succès, ou un état d’erreur de 1 à 4. Consultez les contraintes de la fonction et Raster_GetLastError.
Conditions et limites
Incluez raster.h et compilez raster.c ainsi que scroll.c. Une table partagée contient jusqu’à huit bandes. Pendant sa construction avec Raster_*, n’intercalez pas d’appels directs à Scroll_Split* ou __scroll_split_* : ils contournent le suivi du nombre d’entrées et de la dernière ligne par la couche Raster.
Reconstruisez pendant VBlank ou à un moment où vous maîtrisez l’effet sur l’affichage : effacez, ajoutez les entrées, puis validez. L’effacement arrête aussi les divisions actives ; vous ne modifiez pas un tampon arrière indépendant. LY programme une interruption, et les écritures de registres prennent un temps supplémentaire. Pour une ondulation ligne par ligne, utilisez la famille distincte Raster_LineX* ; n’exécutez pas les deux pilotes ensemble.
Les codes d’état sont 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED et 4 BAD_RANGE. Les ajouts vérifient dans cet ordre la plage LY, la capacité, puis l’ordre des lignes. Une entrée refusée n’agrandit pas la table. Un ajout réussi ultérieur ou un effacement remet l’erreur à zéro : vérifiez chaque valeur de retour au moment de l’appel.
Des paramètres valides arrêtent les divisions existantes, vident la table et ajoutent les nouvelles bandes. Des paramètres invalides préservent la table et son compteur, tout en mémorisant BAD_RANGE. Même après une construction réussie, Raster_Commit reste nécessaire.
Exemple d’utilisation
Raster_BuildHudBottom(96,8,8);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Les lignes à partir de 96 restent fixes. La caméra (8,8) place les rectangles supérieurs en (24,8) et (24,72), tandis que celui du bas reste en (32,112). FIXED BOTTOM HUD demeure en bas.


Commande de compilation
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-disasmImplémentation et source
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
Construit deux bandes de fond pour un HUD supérieur fixe : (0,0) à LY=0, puis les coordonnées caméra à hud_height. Cela divise le défilement du fond sans utiliser la fenêtre.
Syntaxe
u8 Raster_BuildHudTop(u8 hud_height, u8 camera_x, u8 camera_y);Paramètres
hud_heightLigne de séparation, de 1 à 143. Zéro et les valeurs à partir de 144 renvoient BAD_RANGE.
camera_xOctet de défilement du fond, de 0 à 255. SCX/SCY indiquent où lire la carte de fond, pas une position à l’écran. Les coordonnées bouclent sur le fond de 256 pixels.
camera_yOctet de défilement du fond, de 0 à 255. SCX/SCY indiquent où lire la carte de fond, pas une position à l’écran. Les coordonnées bouclent sur le fond de 256 pixels.
Valeur renvoyée
Renvoie KQ_RASTER_OK (0) en cas de succès, ou un état d’erreur de 1 à 4. Consultez les contraintes de la fonction et Raster_GetLastError.
Conditions et limites
Incluez raster.h et compilez raster.c ainsi que scroll.c. Une table partagée contient jusqu’à huit bandes. Pendant sa construction avec Raster_*, n’intercalez pas d’appels directs à Scroll_Split* ou __scroll_split_* : ils contournent le suivi du nombre d’entrées et de la dernière ligne par la couche Raster.
Reconstruisez pendant VBlank ou à un moment où vous maîtrisez l’effet sur l’affichage : effacez, ajoutez les entrées, puis validez. L’effacement arrête aussi les divisions actives ; vous ne modifiez pas un tampon arrière indépendant. LY programme une interruption, et les écritures de registres prennent un temps supplémentaire. Pour une ondulation ligne par ligne, utilisez la famille distincte Raster_LineX* ; n’exécutez pas les deux pilotes ensemble.
Les codes d’état sont 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED et 4 BAD_RANGE. Les ajouts vérifient dans cet ordre la plage LY, la capacité, puis l’ordre des lignes. Une entrée refusée n’agrandit pas la table. Un ajout réussi ultérieur ou un effacement remet l’erreur à zéro : vérifiez chaque valeur de retour au moment de l’appel.
Des paramètres valides arrêtent les divisions existantes, vident la table et ajoutent les nouvelles bandes. Des paramètres invalides préservent la table et son compteur, tout en mémorisant BAD_RANGE. Même après une construction réussie, Raster_Commit reste nécessaire.
Exemple d’utilisation
Raster_BuildHudTop(32,8,8);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Les 32 premières lignes restent fixes. Le rectangle supérieur reste en (32,16) ; la caméra (8,8) déplace les deux autres en (24,72) et (24,104). FIXED TOP HUD demeure en haut.


Commande de compilation
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-disasmImplémentation et source
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
Construit deux bandes de fond avec des décalages horizontaux distincts : far_scx à LY=0 et near_scx à partir de split_y, avec le même défilement Y.
Syntaxe
u8 Raster_BuildParallax2(u8 split_y, u8 far_scx, u8 near_scx, u8 scy);Paramètres
split_yLigne de séparation, de 1 à 143. Zéro et les valeurs à partir de 144 renvoient BAD_RANGE.
far_scxOctet de défilement du fond, de 0 à 255. SCX/SCY indiquent où lire la carte de fond, pas une position à l’écran. Les coordonnées bouclent sur le fond de 256 pixels.
near_scxOctet de défilement du fond, de 0 à 255. SCX/SCY indiquent où lire la carte de fond, pas une position à l’écran. Les coordonnées bouclent sur le fond de 256 pixels.
scyOctet de défilement du fond, de 0 à 255. SCX/SCY indiquent où lire la carte de fond, pas une position à l’écran. Les coordonnées bouclent sur le fond de 256 pixels.
Valeur renvoyée
Renvoie KQ_RASTER_OK (0) en cas de succès, ou un état d’erreur de 1 à 4. Consultez les contraintes de la fonction et Raster_GetLastError.
Conditions et limites
Incluez raster.h et compilez raster.c ainsi que scroll.c. Une table partagée contient jusqu’à huit bandes. Pendant sa construction avec Raster_*, n’intercalez pas d’appels directs à Scroll_Split* ou __scroll_split_* : ils contournent le suivi du nombre d’entrées et de la dernière ligne par la couche Raster.
Reconstruisez pendant VBlank ou à un moment où vous maîtrisez l’effet sur l’affichage : effacez, ajoutez les entrées, puis validez. L’effacement arrête aussi les divisions actives ; vous ne modifiez pas un tampon arrière indépendant. LY programme une interruption, et les écritures de registres prennent un temps supplémentaire. Pour une ondulation ligne par ligne, utilisez la famille distincte Raster_LineX* ; n’exécutez pas les deux pilotes ensemble.
Les codes d’état sont 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED et 4 BAD_RANGE. Les ajouts vérifient dans cet ordre la plage LY, la capacité, puis l’ordre des lignes. Une entrée refusée n’agrandit pas la table. Un ajout réussi ultérieur ou un effacement remet l’erreur à zéro : vérifiez chaque valeur de retour au moment de l’appel.
Des paramètres valides arrêtent les divisions existantes, vident la table et ajoutent les nouvelles bandes. Des paramètres invalides préservent la table et son compteur, tout en mémorisant BAD_RANGE. Même après une construction réussie, Raster_Commit reste nécessaire.
Exemple d’utilisation
Raster_BuildParallax2(64,0,16,0);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
X passe de 0 à 16 à la ligne programmée 64. Les rectangles apparaissent en (32,16), (16,80) et (16,112) ; seule la région inférieure se décale de seize pixels vers la gauche.


Commande de compilation
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-disasmImplémentation et source
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
Enregistre scx0, scx1 et scx2 pour les bandes commençant à LY=0, y1 et y2. Attribue des décalages horizontaux distincts aux plans lointain, intermédiaire et proche, tout en partageant le défilement Y.
Syntaxe
u8 Raster_BuildParallax3(u8 y1, u8 y2, u8 scx0, u8 scx1, u8 scx2, u8 scy);Paramètres
y1Lignes de séparation, avec 1 <= y1 < y2 <= 143.
y2Lignes de séparation, avec 1 <= y1 < y2 <= 143.
scx0Octet de défilement du fond, de 0 à 255. SCX/SCY indiquent où lire la carte de fond, pas une position à l’écran. Les coordonnées bouclent sur le fond de 256 pixels.
scx1Octet de défilement du fond, de 0 à 255. SCX/SCY indiquent où lire la carte de fond, pas une position à l’écran. Les coordonnées bouclent sur le fond de 256 pixels.
scx2Octet de défilement du fond, de 0 à 255. SCX/SCY indiquent où lire la carte de fond, pas une position à l’écran. Les coordonnées bouclent sur le fond de 256 pixels.
scyOctet de défilement du fond, de 0 à 255. SCX/SCY indiquent où lire la carte de fond, pas une position à l’écran. Les coordonnées bouclent sur le fond de 256 pixels.
Valeur renvoyée
Renvoie KQ_RASTER_OK (0) en cas de succès, ou un état d’erreur de 1 à 4. Consultez les contraintes de la fonction et Raster_GetLastError.
Conditions et limites
Incluez raster.h et compilez raster.c ainsi que scroll.c. Une table partagée contient jusqu’à huit bandes. Pendant sa construction avec Raster_*, n’intercalez pas d’appels directs à Scroll_Split* ou __scroll_split_* : ils contournent le suivi du nombre d’entrées et de la dernière ligne par la couche Raster.
Reconstruisez pendant VBlank ou à un moment où vous maîtrisez l’effet sur l’affichage : effacez, ajoutez les entrées, puis validez. L’effacement arrête aussi les divisions actives ; vous ne modifiez pas un tampon arrière indépendant. LY programme une interruption, et les écritures de registres prennent un temps supplémentaire. Pour une ondulation ligne par ligne, utilisez la famille distincte Raster_LineX* ; n’exécutez pas les deux pilotes ensemble.
Les codes d’état sont 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED et 4 BAD_RANGE. Les ajouts vérifient dans cet ordre la plage LY, la capacité, puis l’ordre des lignes. Une entrée refusée n’agrandit pas la table. Un ajout réussi ultérieur ou un effacement remet l’erreur à zéro : vérifiez chaque valeur de retour au moment de l’appel.
Des paramètres valides arrêtent les divisions existantes, vident la table et ajoutent les nouvelles bandes. Des paramètres invalides préservent la table et son compteur, tout en mémorisant BAD_RANGE. Même après une construction réussie, Raster_Commit reste nécessaire.
Exemple d’utilisation
Raster_BuildParallax3(64,104,0,8,16,0);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Les lignes programmées 64 et 104 délimitent les décalages X de 0, 8 et 16. Les rectangles en (32,16), (24,80) et (16,112) montrent le déplacement croissant entre les trois bandes.


Commande de compilation
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-disasmImplémentation et source
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
Arrête immédiatement la programmation des divisions et réinitialise le compteur, l’ordre et l’état d’erreur avant de reconstruire une table dans la même scène. Ne met pas à zéro tous les octets de stockage de la table.
Syntaxe
void Raster_Clear();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Incluez raster.h et compilez raster.c ainsi que scroll.c. Une table partagée contient jusqu’à huit bandes. Pendant sa construction avec Raster_*, n’intercalez pas d’appels directs à Scroll_Split* ou __scroll_split_* : ils contournent le suivi du nombre d’entrées et de la dernière ligne par la couche Raster.
Reconstruisez pendant VBlank ou à un moment où vous maîtrisez l’effet sur l’affichage : effacez, ajoutez les entrées, puis validez. L’effacement arrête aussi les divisions actives ; vous ne modifiez pas un tampon arrière indépendant. LY programme une interruption, et les écritures de registres prennent un temps supplémentaire. Pour une ondulation ligne par ligne, utilisez la famille distincte Raster_LineX* ; n’exécutez pas les deux pilotes ensemble.
Les codes d’état sont 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED et 4 BAD_RANGE. Les ajouts vérifient dans cet ordre la plage LY, la capacité, puis l’ordre des lignes. Une entrée refusée n’agrandit pas la table. Un ajout réussi ultérieur ou un effacement remet l’erreur à zéro : vérifiez chaque valeur de retour au moment de l’appel.
L’arrêt des divisions ne remet pas SCX, SCY, WX ou WY à zéro. Définissez l’état de base souhaité avec les fonctions habituelles, telles que Scroll_SetBg. Ces fonctions ne restaurent pas non plus les anciens bits IE VBlank/STAT ni IME.
Exemple d’utilisation
Raster_Clear();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Des rectangles rouges de 24x16 pixels, noirs sur DMG, apparaissent en (32,16), (24,80) et (16,112). Les bandes inférieures sont davantage décalées vers la gauche. Les résultats internes indiquent un compteur de 3, une erreur de 0 et un résultat de validation de 0.


Commande de compilation
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-disasmImplémentation et source
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
Active la table partagée construite. Même si un ajout a échoué, les entrées ajoutées avec succès auparavant sont activées ; l’appelant doit vérifier chaque ajout.
Syntaxe
u8 Raster_Commit();Valeur renvoyée
Renvoie la dernière erreur mémorisée. Zéro ne prouve pas que tous les ajouts précédents ont réussi.
Conditions et limites
Incluez raster.h et compilez raster.c ainsi que scroll.c. Une table partagée contient jusqu’à huit bandes. Pendant sa construction avec Raster_*, n’intercalez pas d’appels directs à Scroll_Split* ou __scroll_split_* : ils contournent le suivi du nombre d’entrées et de la dernière ligne par la couche Raster.
Reconstruisez pendant VBlank ou à un moment où vous maîtrisez l’effet sur l’affichage : effacez, ajoutez les entrées, puis validez. L’effacement arrête aussi les divisions actives ; vous ne modifiez pas un tampon arrière indépendant. LY programme une interruption, et les écritures de registres prennent un temps supplémentaire. Pour une ondulation ligne par ligne, utilisez la famille distincte Raster_LineX* ; n’exécutez pas les deux pilotes ensemble.
Les codes d’état sont 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED et 4 BAD_RANGE. Les ajouts vérifient dans cet ordre la plage LY, la capacité, puis l’ordre des lignes. Une entrée refusée n’agrandit pas la table. Un ajout réussi ultérieur ou un effacement remet l’erreur à zéro : vérifiez chaque valeur de retour au moment de l’appel.
Une table non vide active les bits IE VBlank/STAT et exécute EI pour autoriser les interruptions ; les autres bits IE sont conservés. Une table vide désactive la programmation des divisions sans restaurer la configuration globale des interruptions.
Exemple d’utilisation
result[2]=Raster_Commit();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Des rectangles rouges de 24x16 pixels, noirs sur DMG, apparaissent en (32,16), (24,80) et (16,112). Les bandes inférieures sont davantage décalées vers la gauche. Les résultats internes indiquent un compteur de 3, une erreur de 0 et un résultat de validation de 0.


Commande de compilation
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-disasmImplémentation et source
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
Efface puis valide une table vide pour désactiver les bandes raster. Utilisez cet arrêt explicite en entrant dans une scène sans défilement divisé.
Syntaxe
void Raster_Disable();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Incluez raster.h et compilez raster.c ainsi que scroll.c. Une table partagée contient jusqu’à huit bandes. Pendant sa construction avec Raster_*, n’intercalez pas d’appels directs à Scroll_Split* ou __scroll_split_* : ils contournent le suivi du nombre d’entrées et de la dernière ligne par la couche Raster.
Reconstruisez pendant VBlank ou à un moment où vous maîtrisez l’effet sur l’affichage : effacez, ajoutez les entrées, puis validez. L’effacement arrête aussi les divisions actives ; vous ne modifiez pas un tampon arrière indépendant. LY programme une interruption, et les écritures de registres prennent un temps supplémentaire. Pour une ondulation ligne par ligne, utilisez la famille distincte Raster_LineX* ; n’exécutez pas les deux pilotes ensemble.
Les codes d’état sont 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED et 4 BAD_RANGE. Les ajouts vérifient dans cet ordre la plage LY, la capacité, puis l’ordre des lignes. Une entrée refusée n’agrandit pas la table. Un ajout réussi ultérieur ou un effacement remet l’erreur à zéro : vérifiez chaque valeur de retour au moment de l’appel.
L’arrêt des divisions ne remet pas SCX, SCY, WX ou WY à zéro. Définissez l’état de base souhaité avec les fonctions habituelles, telles que Scroll_SetBg. Ces fonctions ne restaurent pas non plus les anciens bits IE VBlank/STAT ni IME.
Exemple d’utilisation
Raster_Disable();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Des rectangles rouges de 24x16 pixels, noirs sur DMG, apparaissent en (32,16), (24,80) et (16,112). Les bandes inférieures sont davantage décalées vers la gauche. Les résultats internes indiquent un compteur de 3, une erreur de 0 et un résultat de validation de 0.


Commande de compilation
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-disasmImplémentation et source
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
Lit le nombre de bandes ajoutées par la couche Raster. Clear/Disable le remet à zéro ; une simple validation le conserve.
Syntaxe
u8 Raster_GetCount();Valeur renvoyée
Renvoie le nombre d’entrées, de 0 à 8. Soustrayez-le de huit pour connaître la capacité restante. La lecture ne modifie pas l’état.
Conditions et limites
Incluez raster.h et compilez raster.c ainsi que scroll.c. Une table partagée contient jusqu’à huit bandes. Pendant sa construction avec Raster_*, n’intercalez pas d’appels directs à Scroll_Split* ou __scroll_split_* : ils contournent le suivi du nombre d’entrées et de la dernière ligne par la couche Raster.
Reconstruisez pendant VBlank ou à un moment où vous maîtrisez l’effet sur l’affichage : effacez, ajoutez les entrées, puis validez. L’effacement arrête aussi les divisions actives ; vous ne modifiez pas un tampon arrière indépendant. LY programme une interruption, et les écritures de registres prennent un temps supplémentaire. Pour une ondulation ligne par ligne, utilisez la famille distincte Raster_LineX* ; n’exécutez pas les deux pilotes ensemble.
Les codes d’état sont 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED et 4 BAD_RANGE. Les ajouts vérifient dans cet ordre la plage LY, la capacité, puis l’ordre des lignes. Une entrée refusée n’agrandit pas la table. Un ajout réussi ultérieur ou un effacement remet l’erreur à zéro : vérifiez chaque valeur de retour au moment de l’appel.
Exemple d’utilisation
result[0]=Raster_GetCount();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Des rectangles rouges de 24x16 pixels, noirs sur DMG, apparaissent en (32,16), (24,80) et (16,112). Les bandes inférieures sont davantage décalées vers la gauche. Les résultats internes indiquent un compteur de 3, une erreur de 0 et un résultat de validation de 0.


Commande de compilation
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-disasmImplémentation et source
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
Lit le dernier état Raster mémorisé sans l’effacer. Ce n’est pas un historique cumulatif de tous les échecs précédents.
Syntaxe
u8 Raster_GetLastError();Valeur renvoyée
Renvoie l’état mémorisé, de 0 à 4. La validation renvoie cette valeur, mais n’annule pas automatiquement un échec et ne jette pas la table.
Conditions et limites
Incluez raster.h et compilez raster.c ainsi que scroll.c. Une table partagée contient jusqu’à huit bandes. Pendant sa construction avec Raster_*, n’intercalez pas d’appels directs à Scroll_Split* ou __scroll_split_* : ils contournent le suivi du nombre d’entrées et de la dernière ligne par la couche Raster.
Reconstruisez pendant VBlank ou à un moment où vous maîtrisez l’effet sur l’affichage : effacez, ajoutez les entrées, puis validez. L’effacement arrête aussi les divisions actives ; vous ne modifiez pas un tampon arrière indépendant. LY programme une interruption, et les écritures de registres prennent un temps supplémentaire. Pour une ondulation ligne par ligne, utilisez la famille distincte Raster_LineX* ; n’exécutez pas les deux pilotes ensemble.
Les codes d’état sont 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED et 4 BAD_RANGE. Les ajouts vérifient dans cet ordre la plage LY, la capacité, puis l’ordre des lignes. Une entrée refusée n’agrandit pas la table. Un ajout réussi ultérieur ou un effacement remet l’erreur à zéro : vérifiez chaque valeur de retour au moment de l’appel.
Exemple d’utilisation
result[1]=Raster_GetLastError();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Des rectangles rouges de 24x16 pixels, noirs sur DMG, apparaissent en (32,16), (24,80) et (16,112). Les bandes inférieures sont davantage décalées vers la gauche. Les résultats internes indiquent un compteur de 3, une erreur de 0 et un résultat de validation de 0.


Commande de compilation
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-disasmImplémentation et source
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
Vide la table de bandes partagée, arrête les divisions et initialise le compteur, la validité du dernier LY et l’état d’erreur. Contrairement à Scroll_Init, ne réinitialise pas les coordonnées du fond et de la fenêtre.
Syntaxe
void Raster_Init();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Incluez raster.h et compilez raster.c ainsi que scroll.c. Une table partagée contient jusqu’à huit bandes. Pendant sa construction avec Raster_*, n’intercalez pas d’appels directs à Scroll_Split* ou __scroll_split_* : ils contournent le suivi du nombre d’entrées et de la dernière ligne par la couche Raster.
Reconstruisez pendant VBlank ou à un moment où vous maîtrisez l’effet sur l’affichage : effacez, ajoutez les entrées, puis validez. L’effacement arrête aussi les divisions actives ; vous ne modifiez pas un tampon arrière indépendant. LY programme une interruption, et les écritures de registres prennent un temps supplémentaire. Pour une ondulation ligne par ligne, utilisez la famille distincte Raster_LineX* ; n’exécutez pas les deux pilotes ensemble.
Les codes d’état sont 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED et 4 BAD_RANGE. Les ajouts vérifient dans cet ordre la plage LY, la capacité, puis l’ordre des lignes. Une entrée refusée n’agrandit pas la table. Un ajout réussi ultérieur ou un effacement remet l’erreur à zéro : vérifiez chaque valeur de retour au moment de l’appel.
L’arrêt des divisions ne remet pas SCX, SCY, WX ou WY à zéro. Définissez l’état de base souhaité avec les fonctions habituelles, telles que Scroll_SetBg. Ces fonctions ne restaurent pas non plus les anciens bits IE VBlank/STAT ni IME.
Exemple d’utilisation
Raster_Init();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Des rectangles rouges de 24x16 pixels, noirs sur DMG, apparaissent en (32,16), (24,80) et (16,112). Les bandes inférieures sont davantage décalées vers la gauche. Les résultats internes indiquent un compteur de 3, une erreur de 0 et un résultat de validation de 0.


Commande de compilation
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-disasmImplémentation et source
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
Calcule SCX pour la ligne demandée sans modifier l’état, l’affichage ni la phase.
Syntaxe
u8 Raster_LineXGetOffset(const RasterLineX* effect, u8 ly);Paramètres
effectPointeur vers un RasterLineX initialisé, qui reste valide pendant tout l’appel.
lyCoordonnée de ligne à consulter (0..255) ; les lignes visibles vont de 0 à 143. La recherche boucle sur la période de l’onde au lieu de signaler une erreur de plage.
Valeur renvoyée
SCX sur huit bits égal au X de base plus le déplacement de cette ligne. Dans l’exemple, la recherche à la phase 8, ligne 0 renvoie 17.
Conditions et limites
SCX est une valeur sur huit bits et le fond boucle sur 256 pixels. Les déplacements négatifs sont représentés par des octets modulo 256. Remplissez aussi la carte au-delà de la zone visible.
L’effet modifie le défilement horizontal du fond ; les sprites et la fenêtre ne se déforment pas. RunFrame monopolise le CPU et masque les interruptions pendant les 144 lignes visibles. Mettez à jour la logique du jeu et l’audio entre les appels, et ne combinez pas ce moteur avec un pilote raster par interruption STAT.
Les images proviennent d’exécutions DMG et CGB dans KOKURA. Chaque pixel de la scène 160×144, piliers et texte compris, est comparé aux coordonnées attendues ligne par ligne. Le minutage sur matériel réel n’a pas été testé.
Placez kitaqgb, kokura et kitaq-docs dans un même dossier parent et ouvrez PowerShell dans ce dossier. La ROM prend en charge DMG et CGB ; choisissez dmg ou cgb avec KOKURA --hardware.
Exemple d’utilisation
wave_lookup = Raster_LineXGetOffset(&wave, 0);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Les piliers et les lettres ondulent horizontalement jusqu’à 24 pixels. Une onde couvre 64 lignes et sa phase avance d’une ligne par image. Sur CGB, piliers et lettres sont bleus. Observez les décalages horizontaux différents d’une ligne à l’autre, plutôt qu’un déplacement uniforme de tout l’écran.


Commande de compilation
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.pngImplémentation et source
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
Initialise le profil et le X de base, avec une phase nulle et un pas de phase par image. Cet appel ne dessine rien et n’écrit pas les registres de défilement.
Syntaxe
void Raster_LineXInit(RasterLineX* effect, u8 profile, u8 base_x);Paramètres
effectPointeur vers un espace RasterLineX inscriptible ; aucune initialisation préalable n’est nécessaire.
profile0 (FLAT) n’applique aucun déplacement ; 1 (X_TITLE) répète des décalages de −4 à +3 pixels toutes les 16 lignes ; 2 (TRAVEL_GATE) répète une onde de ±24 pixels toutes les 64 lignes. Les autres valeurs n’appliquent aucun déplacement.
base_xX du fond ajouté au déplacement de l’onde, en pixels (0..255).
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
SCX est une valeur sur huit bits et le fond boucle sur 256 pixels. Les déplacements négatifs sont représentés par des octets modulo 256. Remplissez aussi la carte au-delà de la zone visible.
L’effet modifie le défilement horizontal du fond ; les sprites et la fenêtre ne se déforment pas. RunFrame monopolise le CPU et masque les interruptions pendant les 144 lignes visibles. Mettez à jour la logique du jeu et l’audio entre les appels, et ne combinez pas ce moteur avec un pilote raster par interruption STAT.
Les images proviennent d’exécutions DMG et CGB dans KOKURA. Chaque pixel de la scène 160×144, piliers et texte compris, est comparé aux coordonnées attendues ligne par ligne. Le minutage sur matériel réel n’a pas été testé.
Placez kitaqgb, kokura et kitaq-docs dans un même dossier parent et ouvrez PowerShell dans ce dossier. La ROM prend en charge DMG et CGB ; choisissez dmg ou cgb avec KOKURA --hardware.
Exemple d’utilisation
Raster_LineXInit(&wave, KQ_RASTER_LINE_TRAVEL_GATE, 0);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Les piliers et les lettres ondulent horizontalement jusqu’à 24 pixels. Une onde couvre 64 lignes et sa phase avance d’une ligne par image. Sur CGB, piliers et lettres sont bleus. Observez les décalages horizontaux différents d’une ligne à l’autre, plutôt qu’un déplacement uniforme de tout l’écran.


Commande de compilation
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.pngImplémentation et source
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
Attend VBlank et rend les 144 lignes visibles suivantes avec un X de fond propre à chaque ligne. Avance ensuite le compteur de division et met à jour la phase selon l’intervalle choisi.
Syntaxe
void Raster_LineXRunFrame(RasterLineX* effect);Paramètres
effectPointeur vers un RasterLineX initialisé, qui reste valide pendant tout l’appel.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Si le LCD est éteint, revient immédiatement sans modifier l’effet. Sinon, bloque jusqu’à la mise à jour de SCX pour les 144 lignes, restaure l’état d’activation des interruptions et synchronise les fonctions Scroll avec le SCX final. Le retour ne garantit pas que VBlank soit actif. Avant d’écrire directement en VRAM, attendez VBlank ou utilisez une routine de transfert qui gère les périodes d’accès autorisées.
SCX est une valeur sur huit bits et le fond boucle sur 256 pixels. Les déplacements négatifs sont représentés par des octets modulo 256. Remplissez aussi la carte au-delà de la zone visible.
L’effet modifie le défilement horizontal du fond ; les sprites et la fenêtre ne se déforment pas. RunFrame monopolise le CPU et masque les interruptions pendant les 144 lignes visibles. Mettez à jour la logique du jeu et l’audio entre les appels, et ne combinez pas ce moteur avec un pilote raster par interruption STAT.
Les images proviennent d’exécutions DMG et CGB dans KOKURA. Chaque pixel de la scène 160×144, piliers et texte compris, est comparé aux coordonnées attendues ligne par ligne. Le minutage sur matériel réel n’a pas été testé.
Placez kitaqgb, kokura et kitaq-docs dans un même dossier parent et ouvrez PowerShell dans ce dossier. La ROM prend en charge DMG et CGB ; choisissez dmg ou cgb avec KOKURA --hardware.
Exemple d’utilisation
Raster_LineXRunFrame(&wave);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Les piliers et les lettres ondulent horizontalement jusqu’à 24 pixels. Une onde couvre 64 lignes et sa phase avance d’une ligne par image. Sur CGB, piliers et lettres sont bleus. Observez les décalages horizontaux différents d’une ligne à l’autre, plutôt qu’un déplacement uniforme de tout l’écran.


Commande de compilation
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.pngImplémentation et source
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
Fixe directement la position de l’onde, en conservant le X de base, la vitesse et le compteur de division.
Syntaxe
void Raster_LineXSetPhase(RasterLineX* effect, u8 phase);Paramètres
effectPointeur vers un RasterLineX initialisé, qui reste valide pendant tout l’appel.
phaseValeur de phase sur huit bits ; l’onde choisie se répète tous les 16 ou 64 pas.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
SCX est une valeur sur huit bits et le fond boucle sur 256 pixels. Les déplacements négatifs sont représentés par des octets modulo 256. Remplissez aussi la carte au-delà de la zone visible.
L’effet modifie le défilement horizontal du fond ; les sprites et la fenêtre ne se déforment pas. RunFrame monopolise le CPU et masque les interruptions pendant les 144 lignes visibles. Mettez à jour la logique du jeu et l’audio entre les appels, et ne combinez pas ce moteur avec un pilote raster par interruption STAT.
Les images proviennent d’exécutions DMG et CGB dans KOKURA. Chaque pixel de la scène 160×144, piliers et texte compris, est comparé aux coordonnées attendues ligne par ligne. Le minutage sur matériel réel n’a pas été testé.
Placez kitaqgb, kokura et kitaq-docs dans un même dossier parent et ouvrez PowerShell dans ce dossier. La ROM prend en charge DMG et CGB ; choisissez dmg ou cgb avec KOKURA --hardware.
Exemple d’utilisation
Raster_LineXSetPhase(&wave, 8);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Les piliers et les lettres ondulent horizontalement jusqu’à 24 pixels. Une onde couvre 64 lignes et sa phase avance d’une ligne par image. Sur CGB, piliers et lettres sont bleus. Observez les décalages horizontaux différents d’une ligne à l’autre, plutôt qu’un déplacement uniforme de tout l’écran.


Commande de compilation
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.pngImplémentation et source
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
Sélectionne un profil et remet à zéro la phase et le compteur de division des images. Conserve le X de base et la vitesse.
Syntaxe
void Raster_LineXSetProfile(RasterLineX* effect, u8 profile);Paramètres
effectPointeur vers un RasterLineX initialisé, qui reste valide pendant tout l’appel.
profile0 (FLAT) n’applique aucun déplacement ; 1 (X_TITLE) répète des décalages de −4 à +3 pixels toutes les 16 lignes ; 2 (TRAVEL_GATE) répète une onde de ±24 pixels toutes les 64 lignes. Les autres valeurs n’appliquent aucun déplacement.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
SCX est une valeur sur huit bits et le fond boucle sur 256 pixels. Les déplacements négatifs sont représentés par des octets modulo 256. Remplissez aussi la carte au-delà de la zone visible.
L’effet modifie le défilement horizontal du fond ; les sprites et la fenêtre ne se déforment pas. RunFrame monopolise le CPU et masque les interruptions pendant les 144 lignes visibles. Mettez à jour la logique du jeu et l’audio entre les appels, et ne combinez pas ce moteur avec un pilote raster par interruption STAT.
Les images proviennent d’exécutions DMG et CGB dans KOKURA. Chaque pixel de la scène 160×144, piliers et texte compris, est comparé aux coordonnées attendues ligne par ligne. Le minutage sur matériel réel n’a pas été testé.
Placez kitaqgb, kokura et kitaq-docs dans un même dossier parent et ouvrez PowerShell dans ce dossier. La ROM prend en charge DMG et CGB ; choisissez dmg ou cgb avec KOKURA --hardware.
Exemple d’utilisation
Raster_LineXSetProfile(&wave, KQ_RASTER_LINE_X_TITLE);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le titre original ORBIT GUARD entre par la droite avec une forte ondulation. Après 48 images rendues, celle-ci devient un léger frémissement ; à partir de l’image 96, le titre est immobile. L’entrée se répète après 160 images. Les images montrent successivement l’arrivée, la petite ondulation et le titre stabilisé.






Commande de compilation
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.pngImplémentation et source
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
Règle l’incrément de phase et l’intervalle de mise à jour. Réinitialise le compteur de division tout en conservant la phase actuelle.
Syntaxe
void Raster_LineXSetSpeed(RasterLineX* effect, u8 phase_step, u8 frame_divider);Paramètres
effectPointeur vers un RasterLineX initialisé, qui reste valide pendant tout l’appel.
phase_stepIncrément de phase par mise à jour (0..255). Zéro fige l’onde. La valeur 255 recule d’un pas grâce au bouclage sur huit bits.
frame_dividerNombre d’appels RunFrame ayant rendu une image par mise à jour de phase (1..255). Zéro sélectionne un. Les appels qui reviennent parce que le LCD est éteint ne comptent pas.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
SCX est une valeur sur huit bits et le fond boucle sur 256 pixels. Les déplacements négatifs sont représentés par des octets modulo 256. Remplissez aussi la carte au-delà de la zone visible.
L’effet modifie le défilement horizontal du fond ; les sprites et la fenêtre ne se déforment pas. RunFrame monopolise le CPU et masque les interruptions pendant les 144 lignes visibles. Mettez à jour la logique du jeu et l’audio entre les appels, et ne combinez pas ce moteur avec un pilote raster par interruption STAT.
Les images proviennent d’exécutions DMG et CGB dans KOKURA. Chaque pixel de la scène 160×144, piliers et texte compris, est comparé aux coordonnées attendues ligne par ligne. Le minutage sur matériel réel n’a pas été testé.
Placez kitaqgb, kokura et kitaq-docs dans un même dossier parent et ouvrez PowerShell dans ce dossier. La ROM prend en charge DMG et CGB ; choisissez dmg ou cgb avec KOKURA --hardware.
Exemple d’utilisation
Raster_LineXSetSpeed(&wave, 1, 1);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Les piliers et les lettres ondulent horizontalement jusqu’à 24 pixels. Une onde couvre 64 lignes et sa phase avance d’une ligne par image. Sur CGB, piliers et lettres sont bleus. Observez les décalages horizontaux différents d’une ligne à l’autre, plutôt qu’un déplacement uniforme de tout l’écran.


Commande de compilation
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.pngImplémentation et source
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
Ajoute une bande qui modifie SCX/SCY du fond au LY programmé. Cette opération réservée au fond ne change ni la fenêtre ni les couleurs.
Syntaxe
u8 Raster_Push(u8 ly, u8 scx, u8 scy);Paramètres
lyLigne visible programmée, de 0 à 143, strictement supérieure à l’entrée précédente. Une première entrée à LY=0 est appliquée par le traitement VBlank pour établir l’état de début d’image.
scxOctet de défilement du fond, de 0 à 255. SCX/SCY indiquent où lire la carte de fond, pas une position à l’écran. Les coordonnées bouclent sur le fond de 256 pixels.
scyOctet de défilement du fond, de 0 à 255. SCX/SCY indiquent où lire la carte de fond, pas une position à l’écran. Les coordonnées bouclent sur le fond de 256 pixels.
Valeur renvoyée
Renvoie KQ_RASTER_OK (0) en cas de succès, ou un état d’erreur de 1 à 4. Consultez les contraintes de la fonction et Raster_GetLastError.
Conditions et limites
Incluez raster.h et compilez raster.c ainsi que scroll.c. Une table partagée contient jusqu’à huit bandes. Pendant sa construction avec Raster_*, n’intercalez pas d’appels directs à Scroll_Split* ou __scroll_split_* : ils contournent le suivi du nombre d’entrées et de la dernière ligne par la couche Raster.
Reconstruisez pendant VBlank ou à un moment où vous maîtrisez l’effet sur l’affichage : effacez, ajoutez les entrées, puis validez. L’effacement arrête aussi les divisions actives ; vous ne modifiez pas un tampon arrière indépendant. LY programme une interruption, et les écritures de registres prennent un temps supplémentaire. Pour une ondulation ligne par ligne, utilisez la famille distincte Raster_LineX* ; n’exécutez pas les deux pilotes ensemble.
Les codes d’état sont 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED et 4 BAD_RANGE. Les ajouts vérifient dans cet ordre la plage LY, la capacité, puis l’ordre des lignes. Une entrée refusée n’agrandit pas la table. Un ajout réussi ultérieur ou un effacement remet l’erreur à zéro : vérifiez chaque valeur de retour au moment de l’appel.
Exemple d’utilisation
Raster_Push(0,0,0);Raster_Push(64,8,0);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Des rectangles rouges de 24x16 pixels, noirs sur DMG, apparaissent en (32,16), (24,80) et (16,112). Les bandes inférieures sont davantage décalées vers la gauche. Les résultats internes indiquent un compteur de 3, une erreur de 0 et un résultat de validation de 0.


Commande de compilation
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-disasmImplémentation et source
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
Ajoute une bande qui change la couleur zéro de la palette de fond CGB zéro pendant l’image. Ne sélectionne pas une autre palette et ne modifie pas ses trois autres couleurs. L’enregistrement sur DMG ne produit aucun effet de couleur.
Syntaxe
u8 Raster_PushBgColor0(u8 ly, u16 rgb15);Paramètres
lyLigne visible programmée, de 0 à 143, strictement supérieure à l’entrée précédente. Une première entrée à LY=0 est appliquée par le traitement VBlank pour établir l’état de début d’image.
rgb15RGB15 : rouge dans les bits 0..4, vert dans 5..9 et bleu dans 10..14. 0x001F donne du rouge, 0x03E0 du vert et 0x7C00 du bleu. La plage de l’entrée n’est pas vérifiée.
Valeur renvoyée
Renvoie KQ_RASTER_OK (0) en cas de succès, ou un état d’erreur de 1 à 4. Consultez les contraintes de la fonction et Raster_GetLastError.
Conditions et limites
Incluez raster.h et compilez raster.c ainsi que scroll.c. Une table partagée contient jusqu’à huit bandes. Pendant sa construction avec Raster_*, n’intercalez pas d’appels directs à Scroll_Split* ou __scroll_split_* : ils contournent le suivi du nombre d’entrées et de la dernière ligne par la couche Raster.
Reconstruisez pendant VBlank ou à un moment où vous maîtrisez l’effet sur l’affichage : effacez, ajoutez les entrées, puis validez. L’effacement arrête aussi les divisions actives ; vous ne modifiez pas un tampon arrière indépendant. LY programme une interruption, et les écritures de registres prennent un temps supplémentaire. Pour une ondulation ligne par ligne, utilisez la famille distincte Raster_LineX* ; n’exécutez pas les deux pilotes ensemble.
Les codes d’état sont 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED et 4 BAD_RANGE. Les ajouts vérifient dans cet ordre la plage LY, la capacité, puis l’ordre des lignes. Une entrée refusée n’agrandit pas la table. Un ajout réussi ultérieur ou un effacement remet l’erreur à zéro : vérifiez chaque valeur de retour au moment de l’appel.
Les changements de couleur utilisent BCPS/BCPD et ne conservent pas l’ancien index BCPS. Si le code principal écrit aussi les palettes, réglez explicitement cet index. Le gestionnaire attend un mode LCD accessible ; la séparation visible des couleurs peut donc survenir après la ligne LY programmée.
Exemple d’utilisation
Raster_PushBgColor0(0,0x7C00);Raster_PushBgColor0(64,0x001F);Raster_PushBgColor0(112,0x03E0);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Dans la capture CGB vérifiée à vitesse normale, les lignes 0..65 sont bleues, 66..113 rouges et 114..143 vertes. Les LY programmés sont 0, 64 et 112 ; les délais d’interruption et d’accès à la palette contribuent au décalage des limites visibles. Il n’existe pas de version couleur DMG.

Commande de compilation
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-disasmImplémentation et source
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
Modifie le défilement du fond et les coordonnées de la fenêtre dans une même bande. La fonction ajoute BG et WIN et convertit le X écran de la fenêtre en WX.
Syntaxe
u8 Raster_PushBgWindowScreen(u8 ly, u8 scx, u8 scy, u8 screen_x, u8 screen_y, u8 flags);Paramètres
lyLigne visible programmée, de 0 à 143, strictement supérieure à l’entrée précédente. Une première entrée à LY=0 est appliquée par le traitement VBlank pour établir l’état de début d’image.
scxOctet de défilement du fond, de 0 à 255. SCX/SCY indiquent où lire la carte de fond, pas une position à l’écran. Les coordonnées bouclent sur le fond de 256 pixels.
scyOctet de défilement du fond, de 0 à 255. SCX/SCY indiquent où lire la carte de fond, pas une position à l’écran. Les coordonnées bouclent sur le fond de 256 pixels.
screen_xCoordonnée X écran du bord gauche de la fenêtre. La fonction ajoute sept pour obtenir WX. Utilisez normalement 0..159. Les valeurs à partir de 249 débordent lors de l’addition sur un octet ; ne les utilisez pas pour masquer la fenêtre.
screen_yWY de la fenêtre, en pixels depuis le bord supérieur. Contrairement à X, Y ne nécessite pas l’ajout de sept. À partir de 144, WY ne désigne aucune ligne de départ dans la zone visible.
flagsPassez normalement WIN_SHOW ou WIN_HIDE. La fonction ajoute WIN ; zéro suffit donc pour modifier les coordonnées sans changer la visibilité. Les autres bits pris en charge sont transmis ; évitez les opérations BG ou de couleur involontaires.
Valeur renvoyée
Renvoie KQ_RASTER_OK (0) en cas de succès, ou un état d’erreur de 1 à 4. Consultez les contraintes de la fonction et Raster_GetLastError.
Conditions et limites
Incluez raster.h et compilez raster.c ainsi que scroll.c. Une table partagée contient jusqu’à huit bandes. Pendant sa construction avec Raster_*, n’intercalez pas d’appels directs à Scroll_Split* ou __scroll_split_* : ils contournent le suivi du nombre d’entrées et de la dernière ligne par la couche Raster.
Reconstruisez pendant VBlank ou à un moment où vous maîtrisez l’effet sur l’affichage : effacez, ajoutez les entrées, puis validez. L’effacement arrête aussi les divisions actives ; vous ne modifiez pas un tampon arrière indépendant. LY programme une interruption, et les écritures de registres prennent un temps supplémentaire. Pour une ondulation ligne par ligne, utilisez la famille distincte Raster_LineX* ; n’exécutez pas les deux pilotes ensemble.
Les codes d’état sont 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED et 4 BAD_RANGE. Les ajouts vérifient dans cet ordre la plage LY, la capacité, puis l’ordre des lignes. Une entrée refusée n’agrandit pas la table. Un ajout réussi ultérieur ou un effacement remet l’erreur à zéro : vérifiez chaque valeur de retour au moment de l’appel.
Exemple d’utilisation
Raster_PushBgWindowScreen(0,8,0,24,48,KQ_RASTER_WIN_SHOW);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Un X de fond à 8 déplace le rectangle rouge en (24,16). L’origine de la fenêtre reste en (24,48), donc son rectangle bleu demeure en (32,56). Cela montre l’indépendance des deux systèmes de coordonnées.


Commande de compilation
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-disasmImplémentation et source
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
Ajoute une bande étendue exécutant les opérations de fond, de fenêtre, de visibilité ou de couleur choisies par les indicateurs. Pour modifier seulement le fond, utilisez Raster_Push, qui prend moins d’arguments.
Syntaxe
u8 Raster_PushEx(u8 ly, u8 scx, u8 scy, u8 wx, u8 wy, u8 flags);Paramètres
lyLigne visible programmée, de 0 à 143, strictement supérieure à l’entrée précédente. Une première entrée à LY=0 est appliquée par le traitement VBlank pour établir l’état de début d’image.
scxOctet de défilement du fond, de 0 à 255. SCX/SCY indiquent où lire la carte de fond, pas une position à l’écran. Les coordonnées bouclent sur le fond de 256 pixels.
scyOctet de défilement du fond, de 0 à 255. SCX/SCY indiquent où lire la carte de fond, pas une position à l’écran. Les coordonnées bouclent sur le fond de 256 pixels.
wxValeur matérielle brute de WX. Ajoutez sept à la coordonnée X écran habituelle ; WX=7 place la fenêtre au bord gauche. La fonction ne borne ni ne valide WX.
wyWY de la fenêtre, en pixels depuis le bord supérieur. Contrairement à X, Y ne nécessite pas l’ajout de sept. À partir de 144, WY ne désigne aucune ligne de départ dans la zone visible.
flagsIndicateurs : BG=1 modifie le défilement du fond, WIN=2 modifie WX/WY, WIN_SHOW=4 affiche la fenêtre, WIN_HIDE=8 la masque et BG_COLOR0=16 modifie la couleur zéro du fond CGB. Les bits supérieurs inconnus sont ignorés. Si SHOW et HIDE sont tous deux présents, SHOW s’applique en dernier. Les changements de couleur réutilisent les champs SCX/SCY ; ne les combinez pas avec un défilement ordinaire du fond.
Valeur renvoyée
Renvoie KQ_RASTER_OK (0) en cas de succès, ou un état d’erreur de 1 à 4. Consultez les contraintes de la fonction et Raster_GetLastError.
Conditions et limites
Incluez raster.h et compilez raster.c ainsi que scroll.c. Une table partagée contient jusqu’à huit bandes. Pendant sa construction avec Raster_*, n’intercalez pas d’appels directs à Scroll_Split* ou __scroll_split_* : ils contournent le suivi du nombre d’entrées et de la dernière ligne par la couche Raster.
Reconstruisez pendant VBlank ou à un moment où vous maîtrisez l’effet sur l’affichage : effacez, ajoutez les entrées, puis validez. L’effacement arrête aussi les divisions actives ; vous ne modifiez pas un tampon arrière indépendant. LY programme une interruption, et les écritures de registres prennent un temps supplémentaire. Pour une ondulation ligne par ligne, utilisez la famille distincte Raster_LineX* ; n’exécutez pas les deux pilotes ensemble.
Les codes d’état sont 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED et 4 BAD_RANGE. Les ajouts vérifient dans cet ordre la plage LY, la capacité, puis l’ordre des lignes. Une entrée refusée n’agrandit pas la table. Un ajout réussi ultérieur ou un effacement remet l’erreur à zéro : vérifiez chaque valeur de retour au moment de l’appel.
Exemple d’utilisation
Raster_PushEx(104,16,0,7,0,KQ_RASTER_BG|KQ_RASTER_WIN_HIDE);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Des rectangles rouges de 24x16 pixels, noirs sur DMG, apparaissent en (32,16), (24,80) et (16,112). Les bandes inférieures sont davantage décalées vers la gauche. Les résultats internes indiquent un compteur de 3, une erreur de 0 et un résultat de validation de 0.


Commande de compilation
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-disasmImplémentation et source
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
Ajoute une bande de fenêtre avec les valeurs matérielles brutes WX/WY. Ajoute automatiquement WIN et fournit zéro pour les deux octets de données du fond.
Syntaxe
u8 Raster_PushWindowRaw(u8 ly, u8 wx, u8 wy, u8 flags);Paramètres
lyLigne visible programmée, de 0 à 143, strictement supérieure à l’entrée précédente. Une première entrée à LY=0 est appliquée par le traitement VBlank pour établir l’état de début d’image.
wxValeur matérielle brute de WX. Ajoutez sept à la coordonnée X écran habituelle ; WX=7 place la fenêtre au bord gauche. La fonction ne borne ni ne valide WX.
wyWY de la fenêtre, en pixels depuis le bord supérieur. Contrairement à X, Y ne nécessite pas l’ajout de sept. À partir de 144, WY ne désigne aucune ligne de départ dans la zone visible.
flagsPassez normalement WIN_SHOW ou WIN_HIDE. La fonction ajoute WIN ; zéro suffit donc pour modifier les coordonnées sans changer la visibilité. Les autres bits pris en charge sont transmis ; évitez les opérations BG ou de couleur involontaires.
Valeur renvoyée
Renvoie KQ_RASTER_OK (0) en cas de succès, ou un état d’erreur de 1 à 4. Consultez les contraintes de la fonction et Raster_GetLastError.
Conditions et limites
Incluez raster.h et compilez raster.c ainsi que scroll.c. Une table partagée contient jusqu’à huit bandes. Pendant sa construction avec Raster_*, n’intercalez pas d’appels directs à Scroll_Split* ou __scroll_split_* : ils contournent le suivi du nombre d’entrées et de la dernière ligne par la couche Raster.
Reconstruisez pendant VBlank ou à un moment où vous maîtrisez l’effet sur l’affichage : effacez, ajoutez les entrées, puis validez. L’effacement arrête aussi les divisions actives ; vous ne modifiez pas un tampon arrière indépendant. LY programme une interruption, et les écritures de registres prennent un temps supplémentaire. Pour une ondulation ligne par ligne, utilisez la famille distincte Raster_LineX* ; n’exécutez pas les deux pilotes ensemble.
Les codes d’état sont 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED et 4 BAD_RANGE. Les ajouts vérifient dans cet ordre la plage LY, la capacité, puis l’ordre des lignes. Une entrée refusée n’agrandit pas la table. Un ajout réussi ultérieur ou un effacement remet l’erreur à zéro : vérifiez chaque valeur de retour au moment de l’appel.
Exemple d’utilisation
Raster_PushWindowRaw(0,31,48,KQ_RASTER_WIN_SHOW);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
WX=31 et WY=48 placent l’origine de la fenêtre en (24,48) à l’écran. Son rectangle bleu de 16x16 en position locale (8,8) apparaît en (32,56). Le rectangle rouge du fond supérieur reste en (32,16). Les deux sont noirs sur DMG.


Commande de compilation
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-disasmImplémentation et source
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
Ajoute une bande de fenêtre en coordonnées écran. Ajoute sept à X avant d’appeler la variante brute, afin de positionner la fenêtre sans confondre X écran et WX.
Syntaxe
u8 Raster_PushWindowScreen(u8 ly, u8 screen_x, u8 screen_y, u8 flags);Paramètres
lyLigne visible programmée, de 0 à 143, strictement supérieure à l’entrée précédente. Une première entrée à LY=0 est appliquée par le traitement VBlank pour établir l’état de début d’image.
screen_xCoordonnée X écran du bord gauche de la fenêtre. La fonction ajoute sept pour obtenir WX. Utilisez normalement 0..159. Les valeurs à partir de 249 débordent lors de l’addition sur un octet ; ne les utilisez pas pour masquer la fenêtre.
screen_yWY de la fenêtre, en pixels depuis le bord supérieur. Contrairement à X, Y ne nécessite pas l’ajout de sept. À partir de 144, WY ne désigne aucune ligne de départ dans la zone visible.
flagsPassez normalement WIN_SHOW ou WIN_HIDE. La fonction ajoute WIN ; zéro suffit donc pour modifier les coordonnées sans changer la visibilité. Les autres bits pris en charge sont transmis ; évitez les opérations BG ou de couleur involontaires.
Valeur renvoyée
Renvoie KQ_RASTER_OK (0) en cas de succès, ou un état d’erreur de 1 à 4. Consultez les contraintes de la fonction et Raster_GetLastError.
Conditions et limites
Incluez raster.h et compilez raster.c ainsi que scroll.c. Une table partagée contient jusqu’à huit bandes. Pendant sa construction avec Raster_*, n’intercalez pas d’appels directs à Scroll_Split* ou __scroll_split_* : ils contournent le suivi du nombre d’entrées et de la dernière ligne par la couche Raster.
Reconstruisez pendant VBlank ou à un moment où vous maîtrisez l’effet sur l’affichage : effacez, ajoutez les entrées, puis validez. L’effacement arrête aussi les divisions actives ; vous ne modifiez pas un tampon arrière indépendant. LY programme une interruption, et les écritures de registres prennent un temps supplémentaire. Pour une ondulation ligne par ligne, utilisez la famille distincte Raster_LineX* ; n’exécutez pas les deux pilotes ensemble.
Les codes d’état sont 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED et 4 BAD_RANGE. Les ajouts vérifient dans cet ordre la plage LY, la capacité, puis l’ordre des lignes. Une entrée refusée n’agrandit pas la table. Un ajout réussi ultérieur ou un effacement remet l’erreur à zéro : vérifiez chaque valeur de retour au moment de l’appel.
Exemple d’utilisation
Raster_PushWindowScreen(0,24,48,KQ_RASTER_WIN_SHOW);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Passer directement les coordonnées écran (24,48) produit le même rectangle bleu de fenêtre en (32,56) que l’exemple brut. La bibliothèque ajoute sept à X. Le rectangle rouge du fond supérieur est en (32,16).


Commande de compilation
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-disasmImplémentation et source
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 — Nombres aléatoires, texte, cartes, sauvegardes et services RPG/ADV/SLG
Les fonctions de texte à position absolue dessinent directement sur la carte du fond. text_window ouvre une zone encadrée, text_clear_rect remplit une région et text_print_xy écrit les octets de tuiles sans décoder les contrôles. text_print_u8, text_print_u16 et text_print_s16 convertissent les nombres en décimal en n’utilisant que les cases nécessaires. Réservez et effacez un champ complet pour remplacer des valeurs de longueurs différentes.
Les fonctions RNG déclarées dans rpg.h sont implémentées dans lib/rng.c. Elles partagent le générateur GB du compilateur : rng_seed le réinitialise, rng8/rng_next8 consomment un octet, rng16/rng_next16 en consomment deux, et rand_range/rng_range, rng_chance et weighted_choice adaptent les tirages aux choix du jeu. Compilez rng.c avec le programme si vous appelez ces fonctions. Pour des tests reproductibles, fixez la graine et l’ordre des appels ; les choix par modulo ne garantissent pas des probabilités exactes.
Le décodage RLE utilise des paires d’octets count/value et un compte nul terminal. rle_decode lit un pointeur ordinaire vers la RAM ; rle_decode_far lit un pointeur associé à une banque ROM vers la RAM ; __rle_decode_vram décompresse directement en VRAM avec des écritures adaptées au LCD. Les fonctions RAM sont dans lib/rle.c ; l’opération VRAM directe est générée par le compilateur. Toutes trois renvoient le nombre d’octets produits et exigent un flux valide ainsi qu’un espace de destination suffisant.
Le stockage d’état de jeu déclaré dans rpg.h est implémenté par lib/flags.c. Les trois fonctions d’indicateurs agissent sur 2048 bits booléens indépendants ; quest_state et quest_set_state agissent sur 64 octets indépendants pour les étapes définies par le jeu. Compilez flags.c, respectez les limites d’ID et utilisez un système de sauvegarde distinct si la progression doit survivre à l’extinction.
Le dialogue fenêtré partage un rectangle actif, un curseur et un réglage de vitesse. text_open initialise la zone, text_close l’efface, text_set_speed règle les attentes VBlank par caractère. text_print et text_print_far interprètent les flux ; text_choice exécute un sélecteur vertical bloquant. Chargez les tuiles, dimensionnez la zone et prévoyez la gestion de ces appels bloquants dans le jeu.
Fournit le dessin de cartes et métatuiles, les scripts, les sauvegardes SRAM et la recherche de chemins. Les cases ordinaires mesurent 8×8 pixels, les métatuiles 16×16. Chargement/dessin, masques de déplacement et d’attaque sont distincts ; le jeu coordonne le chargement graphique et l’exécution des événements.
La recherche utilise environ 4 Kio d’espace de travail partagé non réentrant. Limitez les cartes à 1024 cases et les distances explorées à 254. La distance 0xFF signifie « non atteint » : un trajet de 255 pas n’est donc pas représentable. Les sorties de coût et de masque nécessitent width*height octets accessibles en écriture.
Par défaut, quatre emplacements de 512 octets contiennent chacun un en-tête de six octets et jusqu’à 506 octets de données. L’exemple utilise MBC5 avec 8 Kio de SRAM. Les appels se terminent avec la RAM désactivée, sans restaurer sa banque ni son état d’activation précédent.
Les menus proposent une sélection bloquante ou des appels séparés de traitement des entrées et de dessin, pilotés par la boucle de jeu. Le menu d’inventaire affiche les noms des objets et leurs quantités.
camera_center
Centre une case de carte ordinaire dans une zone visible de 20×18 tuiles, avec limitation aux bords de la carte.
Syntaxe
void camera_center(u8 x, u8 y);Paramètres
xCoordonnée X de la case.
yCoordonnée Y de la case.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
L’origine part de max(x−10,0), max(y−9,0), est limitée aux bords de la carte, puis les octets faibles d’origine*8 sont écrits dans SCX/SCY. Cette opération ne s’applique pas en mode métatuile. Elle ne charge pas de nouvelles lignes ou colonnes en VRAM.
Exemple d’utilisation
camera_center(5,4);result[9]=*((u8*)0xFF43);result[10]=*((u8*)0xFF42);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
La grille de gauche montre les coûts de déplacement en trois pas au plus ; celle de droite, un plus court chemin de S à G. Des astérisques verts tracent neuf pas autour d’un mur rouge de trois cases ; les chiffres bleus donnent les coûts. Le DMG utilise la même disposition en noir. Les contrôles RAM montrent aussi que le masque d’attaque ignore les murs.


Commande de compilation
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=noneImplémentation et source
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
Lit un mot petit-boutiste au moyen d’un pointeur indiquant sa banque.
Syntaxe
#define far_read16(p) __farpeek16((p).bank, (p).ptr)Paramètres
pfar_ptr_t contenant bank et ptr, où ptr est une adresse visible par le CPU.
Valeur renvoyée
Le mot sous forme de u16.
Conditions et limites
La macro lit p.bank et p.ptr séparément ; ne passez pas d’expression à effets de bord. La fonction intrinsèque sélectionne temporairement la banque ROM puis la restaure. Évitez les changements de banque concurrents depuis les interruptions.
Exemple d’utilisation
result[1]=far_read16(far);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Lisez les octets hexadécimaux 34 12 AB depuis une autre banque ROM : premier octet 52, mot petit-boutiste 4660 et dernier octet copié 171.


Commande de compilation
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=noneImplémentation et source
kitaqgb/lib/rpg.h:172
far_read8
Lit un octet au moyen d’un pointeur indiquant sa banque.
Syntaxe
#define far_read8(p) __farpeek8((p).bank, (p).ptr)Paramètres
pfar_ptr_t contenant bank et ptr, où ptr est une adresse visible par le CPU.
Valeur renvoyée
L’octet sous forme de u8.
Conditions et limites
La macro lit p.bank et p.ptr séparément ; ne passez pas d’expression à effets de bord. La fonction intrinsèque sélectionne temporairement la banque ROM puis la restaure. Évitez les changements de banque concurrents depuis les interruptions.
Exemple d’utilisation
far.bank=1;far.ptr=bank_bytes;result[0]=far_read8(far);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Lisez les octets hexadécimaux 34 12 AB depuis une autre banque ROM : premier octet 52, mot petit-boutiste 4660 et dernier octet copié 171.


Commande de compilation
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=noneImplémentation et source
kitaqgb/lib/rpg.h:171
far_read_block
Copie des octets consécutifs vers la RAM depuis un pointeur indiquant sa banque.
Syntaxe
#define far_read_block(dst, p, len) __farmemcpy((dst), (p).bank, (p).ptr, (len))Paramètres
dstDébut d’une zone RAM de len octets accessible en écriture.
pfar_ptr_t contenant bank et ptr, où ptr est une adresse visible par le CPU.
lenNombre d’octets ; gardez toute la source dans sa banque.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Macro qui appelle __farmemcpy. Elle ne franchit pas automatiquement les limites de banque ROM et ne gère pas un déplacement de zones mémoire qui se chevauchent.
Exemple d’utilisation
far_read_block(copy,far,3);result[2]=copy[2];Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Lisez les octets hexadécimaux 34 12 AB depuis une autre banque ROM : premier octet 52, mot petit-boutiste 4660 et dernier octet copié 171.


Commande de compilation
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=noneImplémentation et source
kitaqgb/lib/rpg.h:173
flag_clear
Remet un indicateur de jeu à 0 sans effacer les indicateurs voisins. Utilisez cette fonction lorsqu’une condition d’événement est annulée ou pour initialiser explicitement un indicateur. Un indicateur déjà nul reste à zéro.
Syntaxe
void flag_clear(u16 id);Paramètres
idNuméro d’indicateur de 0 à 2047, passé en u16. Le décalage en octets est id / 8 et le bit dans cet octet est id % 8, à partir du bit de poids faible. Le type de paramètre plus large n’agrandit pas le stockage fixe de 2048 indicateurs.
Valeur renvoyée
Aucune (void).
Conditions et limites
La fonction ne valide pas l’ID. Gardez les ID d’indicateurs inférieurs à 2048 et les ID de quêtes inférieurs à 64 ; un accès hors limites peut lire ou écraser de la RAM sans rapport. Les exemples initialisent explicitement les valeurs au lieu de dépendre du contenu au démarrage.
flags.c possède 256 octets de RAM pour les indicateurs et 64 octets distincts pour les quêtes. Ces fonctions n’accèdent pas à la RAM de sauvegarde de la cartouche et ne conservent pas les données après extinction. Pour préserver la progression, le jeu doit sérialiser les valeurs d’indicateurs et de quêtes via son système de sauvegarde, puis les restaurer au chargement.
Incluez rpg.h et compilez lib/flags.c avec le jeu. Les tableaux sont privés à ce fichier source ; accédez-y par les API d’indicateurs et de quêtes. Tous les appelants partagent ce stockage : coordonnez vous-même les écritures de la boucle principale et des gestionnaires d’interruption.
Exemple d’utilisation
flag_clear(9);flag_clear(9); // Mark it closed; clearing twice still leaves 0.
cleared=flag_get(9);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple désactive l’indicateur de porte 9 après l’avoir activé. DOOR CLOSED affiche 000 même si l’effacement est appelé deux fois. L’observation précédente DOOR OPEN reste visible à 001 pour comparer les deux valeurs relevées.
Le programme complet affiche les résultats décimaux sur fond blanc : texte noir sur DMG et bleu sur CGB. FAILED doit valoir 000. Les captures montrent uniquement le comportement des états en RAM ; elles ne démontrent pas la sauvegarde d’une partie.
La vérification sur l’émulateur DMG a couvert tous les ID d’indicateurs de 0 à 2047, les activations et effacements répétés, les entrées voisines et les 256 valeurs d’état de chacune des 64 quêtes. Un motif final de 256 octets d’indicateurs et les 64 octets de quêtes ont été comparés aux données attendues. Les deux écrans pédagogiques ont été vérifiés après 240 images. Le matériel réel et la persistance des sauvegardes n’ont pas été testés.


Commande de compilation
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-disasmImplémentation et source
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
Lit un indicateur de jeu binaire dans le tableau de bits RAM de la bibliothèque. Utilisez-le pour savoir si une porte est ouverte, si un objet a été ramassé ou si un autre événement défini par le jeu s’est produit. La lecture ne modifie pas l’indicateur.
Syntaxe
u8 flag_get(u16 id);Paramètres
idNuméro d’indicateur de 0 à 2047, passé en u16. Le décalage en octets est id / 8 et le bit dans cet octet est id % 8, à partir du bit de poids faible. Le type de paramètre plus large n’agrandit pas le stockage fixe de 2048 indicateurs.
Valeur renvoyée
Booléen u8 normalisé : 0 si l’indicateur est désactivé, 1 s’il est activé. Cette bibliothèque GB appelle l’intrinsèque GB __bit_test, qui normalise le résultat.
Conditions et limites
La fonction ne valide pas l’ID. Gardez les ID d’indicateurs inférieurs à 2048 et les ID de quêtes inférieurs à 64 ; un accès hors limites peut lire ou écraser de la RAM sans rapport. Les exemples initialisent explicitement les valeurs au lieu de dépendre du contenu au démarrage.
flags.c possède 256 octets de RAM pour les indicateurs et 64 octets distincts pour les quêtes. Ces fonctions n’accèdent pas à la RAM de sauvegarde de la cartouche et ne conservent pas les données après extinction. Pour préserver la progression, le jeu doit sérialiser les valeurs d’indicateurs et de quêtes via son système de sauvegarde, puis les restaurer au chargement.
Incluez rpg.h et compilez lib/flags.c avec le jeu. Les tableaux sont privés à ce fichier source ; accédez-y par les API d’indicateurs et de quêtes. Tous les appelants partagent ce stockage : coordonnez vous-même les écritures de la boucle principale et des gestionnaires d’interruption.
Exemple d’utilisation
before=flag_get(9); // Door-open flag: 0 after explicit initialization.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple affecte l’indicateur 9 à une porte. Après sa remise à zéro explicite, BEFORE affiche 000. L’activation puis la désactivation affichent ensuite DOOR OPEN 001 et DOOR CLOSED 000, montrant que les lectures reflètent la condition mémorisée.
Le programme complet affiche les résultats décimaux sur fond blanc : texte noir sur DMG et bleu sur CGB. FAILED doit valoir 000. Les captures montrent uniquement le comportement des états en RAM ; elles ne démontrent pas la sauvegarde d’une partie.
La vérification sur l’émulateur DMG a couvert tous les ID d’indicateurs de 0 à 2047, les activations et effacements répétés, les entrées voisines et les 256 valeurs d’état de chacune des 64 quêtes. Un motif final de 256 octets d’indicateurs et les 64 octets de quêtes ont été comparés aux données attendues. Les deux écrans pédagogiques ont été vérifiés après 240 images. Le matériel réel et la persistance des sauvegardes n’ont pas été testés.


Commande de compilation
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-disasmImplémentation et source
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
Met un indicateur de jeu à 1 en conservant les sept autres bits de son octet. Un indicateur déjà activé reste actif ; utilisez cette fonction pour mémoriser un événement unique, comme l’ouverture d’une porte.
Syntaxe
void flag_set(u16 id);Paramètres
idNuméro d’indicateur de 0 à 2047, passé en u16. Le décalage en octets est id / 8 et le bit dans cet octet est id % 8, à partir du bit de poids faible. Le type de paramètre plus large n’agrandit pas le stockage fixe de 2048 indicateurs.
Valeur renvoyée
Aucune (void).
Conditions et limites
La fonction ne valide pas l’ID. Gardez les ID d’indicateurs inférieurs à 2048 et les ID de quêtes inférieurs à 64 ; un accès hors limites peut lire ou écraser de la RAM sans rapport. Les exemples initialisent explicitement les valeurs au lieu de dépendre du contenu au démarrage.
flags.c possède 256 octets de RAM pour les indicateurs et 64 octets distincts pour les quêtes. Ces fonctions n’accèdent pas à la RAM de sauvegarde de la cartouche et ne conservent pas les données après extinction. Pour préserver la progression, le jeu doit sérialiser les valeurs d’indicateurs et de quêtes via son système de sauvegarde, puis les restaurer au chargement.
Incluez rpg.h et compilez lib/flags.c avec le jeu. Les tableaux sont privés à ce fichier source ; accédez-y par les API d’indicateurs et de quêtes. Tous les appelants partagent ce stockage : coordonnez vous-même les écritures de la boucle principale et des gestionnaires d’interruption.
Exemple d’utilisation
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.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple active deux fois l’indicateur de porte 9. DOOR OPEN affiche 001 et l’indicateur voisin 8 reste à NEIGHBOR 000. Les deux occupent le même octet ; la valeur voisine montre donc que l’activation d’un indicateur préserve l’autre.
Le programme complet affiche les résultats décimaux sur fond blanc : texte noir sur DMG et bleu sur CGB. FAILED doit valoir 000. Les captures montrent uniquement le comportement des états en RAM ; elles ne démontrent pas la sauvegarde d’une partie.
La vérification sur l’émulateur DMG a couvert tous les ID d’indicateurs de 0 à 2047, les activations et effacements répétés, les entrées voisines et les 256 valeurs d’état de chacune des 64 quêtes. Un motif final de 256 octets d’indicateurs et les 64 octets de quêtes ont été comparés aux données attendues. Les deux écrans pédagogiques ont été vérifiés après 240 images. Le matériel réel et la persistance des sauvegardes n’ont pas été testés.


Commande de compilation
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-disasmImplémentation et source
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
Lit la hauteur de la carte active.
Syntaxe
u8 map_current_height();Valeur renvoyée
Renvoie la hauteur en cases, ou zéro si aucune carte n’est chargée.
Conditions et limites
Les coordonnées désignent les cases de la carte active : 8×8 pixels pour les tuiles ordinaires, 16×16 pour les métatuiles.
Exemple d’utilisation
result[1]=map_current_height();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
La grille de gauche montre les coûts de déplacement en trois pas au plus ; celle de droite, un plus court chemin de S à G. Des astérisques verts tracent neuf pas autour d’un mur rouge de trois cases ; les chiffres bleus donnent les coûts. Le DMG utilise la même disposition en noir. Les contrôles RAM montrent aussi que le masque d’attaque ignore les murs.


Commande de compilation
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=noneImplémentation et source
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
Lit la largeur de la carte active.
Syntaxe
u8 map_current_width();Valeur renvoyée
Renvoie la largeur en cases, ou zéro si aucune carte n’est chargée.
Conditions et limites
Les coordonnées désignent les cases de la carte active : 8×8 pixels pour les tuiles ordinaires, 16×16 pour les métatuiles.
Exemple d’utilisation
result[0]=map_current_width();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
La grille de gauche montre les coûts de déplacement en trois pas au plus ; celle de droite, un plus court chemin de S à G. Des astérisques verts tracent neuf pas autour d’un mur rouge de trois cases ; les chiffres bleus donnent les coûts. Le DMG utilise la même disposition en noir. Les contrôles RAM montrent aussi que le masque d’attaque ignore les murs.


Commande de compilation
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=noneImplémentation et source
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
Dessine 10×9 métatuiles depuis l’origine demandée et mémorise cette position de caméra pour les rafraîchissements après modification.
Syntaxe
void map_draw_visible(u8 camera_tx, u8 camera_ty);Paramètres
camera_txX de la case la plus à gauche ; limitez-le à 246 pour éviter un rebouclage d’octet pendant le parcours.
camera_tyY de la case la plus haute ; limitez-le à 247.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Les cases extérieures dessinent la métatuile d’identifiant zéro ; fournissez donc toujours la définition zéro. L’appel laisse inchangées les cases hors de la zone de 20×18 tuiles et les attributs CGB.
Exemple d’utilisation
map_draw_visible(1,0);result[9]=*((u8*)0x9800);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Modifiez un identifiant de métatuile en RAM, signalez la modification puis appliquez-la. La caméra (1,0) montre un carré vert de 16×16 en haut à gauche. L’exemple applique explicitement les métadonnées de palette aux attributs CGB. Le DMG affiche un carré noir.


Commande de compilation
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=noneImplémentation et source
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
Si une modification est signalée, redessine la zone visible depuis l’origine de caméra mémorisée et efface le drapeau de modification.
Syntaxe
void map_flush_dirty();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Ne fait rien sans modification signalée. Le rafraîchissement couvre toutes les 10×9 métatuiles, pas uniquement la case modifiée.
Exemple d’utilisation
map_flush_dirty();result[11]=*((u8*)0x9800);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Modifiez un identifiant de métatuile en RAM, signalez la modification puis appliquez-la. La caméra (1,0) montre un carré vert de 16×16 en haut à gauche. L’exemple applique explicitement les métadonnées de palette aux attributs CGB. Le DMG affiche un carré noir.


Commande de compilation
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=noneImplémentation et source
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
Lit les métadonnées de palette dans la définition de métatuile de la case.
Syntaxe
u8 map_get_attr(u8 tx, u8 ty);Paramètres
txCoordonnée X de métatuile.
tyCoordonnée Y de métatuile.
Valeur renvoyée
Renvoie l’octet de palette. Les cases extérieures utilisent la définition zéro ; sans mode métatuile, renvoie zéro.
Conditions et limites
Les coordonnées désignent les cases de la carte active : 8×8 pixels pour les tuiles ordinaires, 16×16 pour les métatuiles.
Exemple d’utilisation
result[3]=map_get_attr(0,0);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Modifiez un identifiant de métatuile en RAM, signalez la modification puis appliquez-la. La caméra (1,0) montre un carré vert de 16×16 en haut à gauche. L’exemple applique explicitement les métadonnées de palette aux attributs CGB. Le DMG affiche un carré noir.


Commande de compilation
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=noneImplémentation et source
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
Lit un identifiant d’événement de métatuile ; les cartes ordinaires indiquent la présence d’un événement.
Syntaxe
u8 map_get_event(u8 tx, u8 ty);Paramètres
txCoordonnée X de métatuile.
tyCoordonnée Y de métatuile.
Valeur renvoyée
Renvoie l’octet d’événement de métatuile ou le booléen de carte ordinaire ; les cases absentes ou extérieures donnent zéro.
Conditions et limites
Les coordonnées désignent les cases de la carte active : 8×8 pixels pour les tuiles ordinaires, 16×16 pour les métatuiles.
Exemple d’utilisation
result[7]=map_get_event(0,0);result[8]=map_get_event(3,0);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Modifiez un identifiant de métatuile en RAM, signalez la modification puis appliquez-la. La caméra (1,0) montre un carré vert de 16×16 en haut à gauche. L’exemple applique explicitement les métadonnées de palette aux attributs CGB. Le DMG affiche un carré noir.


Commande de compilation
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=noneImplémentation et source
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
Lit l’identifiant de métatuile d’une case.
Syntaxe
u8 map_get_metatile(u8 tx, u8 ty);Paramètres
txCoordonnée X de métatuile.
tyCoordonnée Y de métatuile.
Valeur renvoyée
Renvoie l’identifiant, ou zéro hors de la carte ou sans mode métatuile.
Conditions et limites
Les coordonnées désignent les cases de la carte active : 8×8 pixels pour les tuiles ordinaires, 16×16 pour les métatuiles.
Exemple d’utilisation
result[1]=map_get_metatile(0,0);result[2]=map_get_metatile(3,0);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Modifiez un identifiant de métatuile en RAM, signalez la modification puis appliquez-la. La caméra (1,0) montre un carré vert de 16×16 en haut à gauche. L’exemple applique explicitement les métadonnées de palette aux attributs CGB. Le DMG affiche un carré noir.


Commande de compilation
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=noneImplémentation et source
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
Teste si une case de destination bloque le déplacement ; le mode métatuile utilise le champ collision de sa définition.
Syntaxe
u8 map_is_blocked(u8 x, u8 y);Paramètres
xCoordonnée X de la case.
yCoordonnée Y de la case.
Valeur renvoyée
Renvoie 1 pour un mur, des coordonnées extérieures ou une carte absente, et 0 pour une case franchissable. Un tableau de collision NULL sur une carte ordinaire rend toutes ses cases intérieures franchissables.
Conditions et limites
Les coordonnées désignent les cases de la carte active : 8×8 pixels pour les tuiles ordinaires, 16×16 pour les métatuiles.
Exemple d’utilisation
result[4]=map_is_blocked(2,2);result[5]=map_is_blocked(6,2);result[6]=map_is_blocked(1,2);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
La grille de gauche montre les coûts de déplacement en trois pas au plus ; celle de droite, un plus court chemin de S à G. Des astérisques verts tracent neuf pas autour d’un mur rouge de trois cases ; les chiffres bleus donnent les coûts. Le DMG utilise la même disposition en noir. Les contrôles RAM montrent aussi que le masque d’attaque ignore les murs.


Commande de compilation
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=noneImplémentation et source
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
Teste la solidité et délègue aux bits de collision en mode carte ordinaire.
Syntaxe
u8 map_is_solid(u8 tx, u8 ty);Paramètres
txCoordonnée X de métatuile.
tyCoordonnée Y de métatuile.
Valeur renvoyée
Renvoie 1 pour une collision non nulle ou une case extérieure, sinon 0.
Conditions et limites
Les coordonnées désignent les cases de la carte active : 8×8 pixels pour les tuiles ordinaires, 16×16 pour les métatuiles.
Exemple d’utilisation
result[4]=map_is_solid(0,0);result[5]=map_is_solid(1,0);result[6]=map_is_solid(3,0);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Modifiez un identifiant de métatuile en RAM, signalez la modification puis appliquez-la. La caméra (1,0) montre un carré vert de 16×16 en haut à gauche. L’exemple applique explicitement les métadonnées de palette aux attributs CGB. Le DMG affiche un carré noir.


Commande de compilation
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=noneImplémentation et source
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
Charge un descripteur de carte ordinaire et dessine jusqu’à 20×18 tuiles depuis son coin supérieur gauche dans la carte de fond choisie.
Syntaxe
void map_load(u8 bank, const map_t* map);Paramètres
bankBanque ROM du descripteur, des bits de collision et des événements.
mapmap_t compact de neuf octets. tiles contient width*height identifiants de tuile ; collision_bits range les cases en commençant par le bit de poids faible ; events stocke un octet par case. La lecture des tuiles utilise bank_tiles.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Une seule carte active est partagée. Le descripteur est copié, mais ses tableaux doivent rester lisibles aussi longtemps que nécessaire. Chargez séparément les graphismes de tuiles en VRAM.
Les coordonnées désignent les cases de la carte active : 8×8 pixels pour les tuiles ordinaires, 16×16 pour les métatuiles.
Les cases situées hors d’une petite carte ne sont pas effacées. Pour les cartes ordinaires, bank_tiles=0 signifie banque zéro ; la banque du descripteur n’est pas héritée.
Exemple d’utilisation
map_load(0,maps);result[2]=map_current_width();result[3]=map_current_height();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
La grille de gauche montre les coûts de déplacement en trois pas au plus ; celle de droite, un plus court chemin de S à G. Des astérisques verts tracent neuf pas autour d’un mur rouge de trois cases ; les chiffres bleus donnent les coûts. Le DMG utilise la même disposition en noir. Les contrôles RAM montrent aussi que le masque d’attaque ignore les murs.


Commande de compilation
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=noneImplémentation et source
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
Sélectionne une carte de métatuiles et développe une zone visible de 10×9 cases, caméra en (0,0), en 20×18 tuiles.
Syntaxe
void map_load_metatile(u8 bank, const metatile_map_t* map);Paramètres
bankBanque ROM contenant le descripteur.
mapPointeur vers metatile_map_t. Les dimensions comptent les cases de 16×16 pixels. Il référence un tableau d’identifiants et une table de définitions metatile_t de sept octets.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Une seule carte active est partagée. Le descripteur est copié, mais ses tableaux doivent rester lisibles aussi longtemps que nécessaire. Chargez séparément les graphismes de tuiles en VRAM.
bank_tiles=0 hérite de la banque du descripteur ; une valeur non nulle choisit la banque des identifiants comme des définitions. Une définition stocke les tuiles supérieure gauche, supérieure droite, inférieure gauche et inférieure droite, puis collision, palette et événement. Le dessin n’applique pas automatiquement les métadonnées de palette.
Exemple d’utilisation
map_load_metatile(0,&level);result[0]=*((u8*)0x9800);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Modifiez un identifiant de métatuile en RAM, signalez la modification puis appliquez-la. La caméra (1,0) montre un carré vert de 16×16 en haut à gauche. L’exemple applique explicitement les métadonnées de palette aux attributs CGB. Le DMG affiche un carré noir.


Commande de compilation
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=noneImplémentation et source
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
Marque la zone visible pour un nouveau dessin lorsqu’une coordonnée de métatuile valide est fournie.
Syntaxe
void map_mark_dirty(u8 tx, u8 ty);Paramètres
txCoordonnée X de métatuile.
tyCoordonnée Y de métatuile.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Active un unique drapeau de modification partagé au lieu de mettre à jour chaque case dans une file. Les coordonnées extérieures sont ignorées. L’appelant modifie séparément les identifiants ou les définitions avant de signaler la modification.
Exemple d’utilisation
ids[1]=1;map_mark_dirty(1,0);result[10]=*((u8*)0x9800);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Modifiez un identifiant de métatuile en RAM, signalez la modification puis appliquez-la. La caméra (1,0) montre un carré vert de 16×16 en haut à gauche. L’exemple applique explicitement les métadonnées de palette aux attributs CGB. Le DMG affiche un carré noir.


Commande de compilation
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=noneImplémentation et source
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
Vérifie si une case contient un événement, sans l’exécuter.
Syntaxe
u8 map_trigger_at(u8 x, u8 y);Paramètres
xCoordonnée X de la case.
yCoordonnée Y de la case.
Valeur renvoyée
Renvoie 1 si un événement est présent, sinon 0 ; ne renvoie ni l’octet d’événement stocké ni l’identifiant d’événement de métatuile.
Conditions et limites
Les coordonnées désignent les cases de la carte active : 8×8 pixels pour les tuiles ordinaires, 16×16 pour les métatuiles.
Exemple d’utilisation
result[7]=map_trigger_at(5,4);result[8]=map_trigger_at(6,4);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
La grille de gauche montre les coûts de déplacement en trois pas au plus ; celle de droite, un plus court chemin de S à G. Des astérisques verts tracent neuf pas autour d’un mur rouge de trois cases ; les chiffres bleus donnent les coûts. Le DMG utilise la même disposition en noir. Les contrôles RAM montrent aussi que le masque d’attaque ignore les murs.


Commande de compilation
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=noneImplémentation et source
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
Trouve un plus court chemin par déplacements cardinaux et écrit ses directions du départ vers l’arrivée.
Syntaxe
u8 path_find_bfs(u8 sx, u8 sy, u8 gx, u8 gy, u8* out_path, u8 max_len);Paramètres
sxX de la case de départ, dans les limites.
syY de la case de départ.
gxX de la case d’arrivée ; une arrivée bloquée distincte de l’origine est refusée.
gyY de la case d’arrivée.
out_pathTableau accessible en écriture d’au moins max_len octets ; 0=haut, 1=droite, 2=bas, 3=gauche.
max_lenCapacité de sortie ; un chemin trop long provoque un échec au lieu d’être tronqué.
Valeur renvoyée
Renvoie la longueur du chemin ; zéro signifie inaccessible, coordonnées invalides, max_len insuffisant ou arrivée déjà atteinte.
Conditions et limites
Les coordonnées désignent les cases de la carte active : 8×8 pixels pour les tuiles ordinaires, 16×16 pour les métatuiles.
La recherche utilise environ 4 Kio d’espace de travail partagé non réentrant. Limitez les cartes à 1024 cases et les distances explorées à 254. La distance 0xFF signifie « non atteint » : un trajet de 255 pas n’est donc pas représentable. Les sorties de coût et de masque nécessitent width*height octets accessibles en écriture.
max_len limite la sortie, pas le rayon de recherche. N’utilisez pas la sortie comme nouvelle route après un échec.
Exemple d’utilisation
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);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
La grille de gauche montre les coûts de déplacement en trois pas au plus ; celle de droite, un plus court chemin de S à G. Des astérisques verts tracent neuf pas autour d’un mur rouge de trois cases ; les chiffres bleus donnent les coûts. Le DMG utilise la même disposition en noir. Les contrôles RAM montrent aussi que le masque d’attaque ignore les murs.


Commande de compilation
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=noneImplémentation et source
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
Remplace tout l’octet d’état d’une quête. Le jeu définit le sens de chaque valeur : par exemple, 1 pour acceptée et 3 pour terminée. La fonction ne vérifie pas si cette transition est autorisée et ne déclenche ni récompense ni rappel.
Syntaxe
void quest_set_state(u8 quest_id, u8 state);Paramètres
quest_idNuméro de quête de 0 à 63, passé en u8. Il indexe directement l’un des 64 octets d’état ; c’est un ID défini par le jeu, pas un pointeur ni un nombre de quêtes terminées.
stateNouvel état u8, de 0 à 255. Les huit bits remplacent la valeur précédente. La bibliothèque n’attribue aucun sens prédéfini aux valeurs et ne réserve ni 0 ni 255.
Valeur renvoyée
Aucune (void).
Conditions et limites
La fonction ne valide pas l’ID. Gardez les ID d’indicateurs inférieurs à 2048 et les ID de quêtes inférieurs à 64 ; un accès hors limites peut lire ou écraser de la RAM sans rapport. Les exemples initialisent explicitement les valeurs au lieu de dépendre du contenu au démarrage.
flags.c possède 256 octets de RAM pour les indicateurs et 64 octets distincts pour les quêtes. Ces fonctions n’accèdent pas à la RAM de sauvegarde de la cartouche et ne conservent pas les données après extinction. Pour préserver la progression, le jeu doit sérialiser les valeurs d’indicateurs et de quêtes via son système de sauvegarde, puis les restaurer au chargement.
Incluez rpg.h et compilez lib/flags.c avec le jeu. Les tableaux sont privés à ce fichier source ; accédez-y par les API d’indicateurs et de quêtes. Tous les appelants partagent ce stockage : coordonnez vous-même les écritures de la boucle principale et des gestionnaires d’interruption.
Exemple d’utilisation
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.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple stocke 1 pour la quête 2, puis le remplace par 3. ACCEPTED montre la première observation, 001, et COMPLETED la nouvelle valeur, 003. LAST QUEST vaut 255 après stockage de 255 dans la quête d’ID 63, dernière entrée valide.
Le programme complet affiche les résultats décimaux sur fond blanc : texte noir sur DMG et bleu sur CGB. FAILED doit valoir 000. Les captures montrent uniquement le comportement des états en RAM ; elles ne démontrent pas la sauvegarde d’une partie.
La vérification sur l’émulateur DMG a couvert tous les ID d’indicateurs de 0 à 2047, les activations et effacements répétés, les entrées voisines et les 256 valeurs d’état de chacune des 64 quêtes. Un motif final de 256 octets d’indicateurs et les 64 octets de quêtes ont été comparés aux données attendues. Les deux écrans pédagogiques ont été vérifiés après 240 images. Le matériel réel et la persistance des sauvegardes n’ont pas été testés.


Commande de compilation
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-disasmImplémentation et source
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
Lit l’octet mémorisé pour une quête. Contrairement à un indicateur d’un bit, cet octet peut distinguer plusieurs étapes, comme non commencée, acceptée et terminée. La fonction lit uniquement le stockage ; elle n’exécute aucune logique de quête et ne fait pas avancer l’étape.
Syntaxe
u8 quest_state(u8 quest_id);Paramètres
quest_idNuméro de quête de 0 à 63, passé en u8. Il indexe directement l’un des 64 octets d’état ; c’est un ID défini par le jeu, pas un pointeur ni un nombre de quêtes terminées.
Valeur renvoyée
Valeur u8 mémorisée, de 0 à 255. C’est un octet d’état complet, pas un booléen normalisé ; comparez-le aux étapes définies par votre jeu.
Conditions et limites
La fonction ne valide pas l’ID. Gardez les ID d’indicateurs inférieurs à 2048 et les ID de quêtes inférieurs à 64 ; un accès hors limites peut lire ou écraser de la RAM sans rapport. Les exemples initialisent explicitement les valeurs au lieu de dépendre du contenu au démarrage.
flags.c possède 256 octets de RAM pour les indicateurs et 64 octets distincts pour les quêtes. Ces fonctions n’accèdent pas à la RAM de sauvegarde de la cartouche et ne conservent pas les données après extinction. Pour préserver la progression, le jeu doit sérialiser les valeurs d’indicateurs et de quêtes via son système de sauvegarde, puis les restaurer au chargement.
Incluez rpg.h et compilez lib/flags.c avec le jeu. Les tableaux sont privés à ce fichier source ; accédez-y par les API d’indicateurs et de quêtes. Tous les appelants partagent ce stockage : coordonnez vous-même les écritures de la boucle principale et des gestionnaires d’interruption.
Exemple d’utilisation
finished=quest_state(2); // Read back 3 without advancing any quest logic.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple lit la quête 2 après que le jeu a explicitement changé son état de 1 à 3. ACCEPTED affiche 001 et COMPLETED affiche 003. Les noms et le sens des étapes sont choisis par l’exemple, pas imposés par la bibliothèque.
Le programme complet affiche les résultats décimaux sur fond blanc : texte noir sur DMG et bleu sur CGB. FAILED doit valoir 000. Les captures montrent uniquement le comportement des états en RAM ; elles ne démontrent pas la sauvegarde d’une partie.
La vérification sur l’émulateur DMG a couvert tous les ID d’indicateurs de 0 à 2047, les activations et effacements répétés, les entrées voisines et les 256 valeurs d’état de chacune des 64 quêtes. Un motif final de 256 octets d’indicateurs et les 64 octets de quêtes ont été comparés aux données attendues. Les deux écrans pédagogiques ont été vérifiés après 240 images. Le matériel réel et la persistance des sauvegardes n’ont pas été testés.


Commande de compilation
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-disasmImplémentation et source
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
Choisit une valeur à partir de zéro et inférieure à max avec rng8() % max. Une borne de 10 donne par exemple un indice de 0 à 9. Une borne nulle renvoie immédiatement zéro sans tirage.
Syntaxe
u8 rand_range(u8 max);Paramètres
maxBorne supérieure exclue en u8 (0–255). Pour max > 0, le résultat est inférieur à max. Ce paramètre ne peut pas représenter 256 ; utilisez rng8 pour obtenir toute la plage d’un octet sans réduction modulo.
Valeur renvoyée
Pour max > 0, un u8 de 0 à max−1 après un tirage. Pour max == 0, zéro sans tirage. Même max == 1 consomme un tirage, bien que le résultat soit toujours nul.
Conditions et limites
La réduction modulo peut favoriser certains résultats lorsque la plage d’entrée n’est pas divisible par la borne. Le générateur sous-jacent n’est pas nécessairement uniforme non plus. Traitez les sélections bornées et les seuils de chance comme des approximations de jeu, pas des probabilités exactes.
Ces appels partagent un état persistant. La reproduction exige la même cible, la même graine et le même ordre d’appels, y compris ceux des autres fonctions auxiliaires. Gardez réglage de graine et tirages dans un même contexte d’exécution ; ces vérifications ne prouvent pas la sûreté d’un accès concurrent depuis une interruption.
GB et FC utilisent des algorithmes différents et ne garantissent pas la même suite avec la même graine. Ce sont des générateurs déterministes pour le jeu, pas des sources d’aléa cryptographique. Les tests vérifient le comportement de l’implémentation, pas sa qualité statistique ni sa période.
Incluez rpg.h et compilez lib/rng.c avec le jeu pour utiliser les fonctions de bibliothèque. Les intrinsèques __rng_seed et __rng8 sont émises par le compilateur ; un programme limité à ces deux fonctions n’a pas besoin d’objet rng.c.
Exemple d’utilisation
rng_seed(0x1234);
bounded=rand_range(10); // An index from 0 through 9; this seed yields 2.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple choisit un indice inférieur à 10. RANGE 10 affiche 00002, car le premier octet de la graine 0x1234 vaut 2. ZERO BOUND vaut 00000 et NEXT BYTE reste ensuite à 00002, confirmant que la borne nulle n’a consommé aucun tirage.
Le programme complet affiche les résultats décimaux sur fond blanc : texte noir sur DMG, bleu sur CGB. FAILED doit indiquer 00000. Les images montrent la sortie réelle de cet exemple dans l’émulateur.
La validation a comparé, pour chaque cas, 32 sorties et huit tirages d’octet suivants à un modèle hôte indépendant : 93 cas GB et 18 cas FC, avec graines constantes ou calculées à l’exécution et limites GB de plage, chance et poids. Les écrans pédagogiques ont été contrôlés après 240 images émulées. Le matériel réel et la qualité statistique n’ont pas été testés.


Commande de compilation
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-disasmImplémentation et source
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
Parcourt les voisins cardinaux à coût unitaire par recherche en largeur pour calculer les coûts de déplacement.
Syntaxe
void range_fill_move(u8 sx, u8 sy, u8 move, u8* out_costmap);Paramètres
sxX de la case de départ, dans les limites.
syY de la case de départ.
moveLimite de déplacement de 0 à 254 ; zéro atteint seulement l’origine.
out_costmapTableau de coûts de width*height octets accessible en écriture : 255 pour non atteint, zéro à l’origine.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Les coordonnées désignent les cases de la carte active : 8×8 pixels pour les tuiles ordinaires, 16×16 pour les métatuiles.
La recherche utilise environ 4 Kio d’espace de travail partagé non réentrant. Limitez les cartes à 1024 cases et les distances explorées à 254. La distance 0xFF signifie « non atteint » : un trajet de 255 pas n’est donc pas représentable. Les sorties de coût et de masque nécessitent width*height octets accessibles en écriture.
Une carte absente ou une origine invalide laisse la sortie inchangée. Les cases de destination bloquées ne sont pas traversées.
Exemple d’utilisation
range_fill_move(0,2,3,costs);for(i=0;i<30;i++)result[13+i]=costs[i];Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
La grille de gauche montre les coûts de déplacement en trois pas au plus ; celle de droite, un plus court chemin de S à G. Des astérisques verts tracent neuf pas autour d’un mur rouge de trois cases ; les chiffres bleus donnent les coûts. Le DMG utilise la même disposition en noir. Les contrôles RAM montrent aussi que le masque d’attaque ignore les murs.


Commande de compilation
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=noneImplémentation et source
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
Décompresse un flux d’octets RLE dans la RAM ordinaire inscriptible. Chaque paire count/value répète un octet count fois ; un compte nul termine le flux. Utilisez cette variante lorsque les données encodées sont accessibles par un pointeur ordinaire et que vous souhaitez examiner ou modifier les octets décompressés avant leur transfert.
Syntaxe
u16 rle_decode(void* dst, const void* src);Paramètres
dstPointeur vers une RAM inscriptible assez grande pour tout le flux décompressé. Aucune capacité n’est passée à la fonction. Séparez la sortie de la source encodée pour éviter d’écraser des paires pas encore lues.
srcPointeur lisible vers des paires d’octets count/value terminées par un compte nul. Une répétition normale utilise un compte de 1 à 255 ; la valeur peut être n’importe quel octet, zéro compris. Le zéro terminal n’est suivi d’aucun octet de valeur. Le pointeur doit rester lisible dans le mappage courant pendant tout l’appel.
Valeur renvoyée
Nombre d’octets écrits en u16. Un compte nul immédiat ne produit aucun octet et renvoie 0. Le terminateur n’est pas copié. La longueur décompressée doit tenir dans u16 ; le retour n’a pas de code d’erreur distinct et ne représente pas un nombre de tuiles.
Conditions et limites
Le codage porte sur des octets, pas sur du texte. Par exemple, {3, 0x12, 2, 0xA5, 0} donne cinq octets : 12 12 12 A5 A5. Cette liste de sortie est en hexadécimal. Une valeur nulle dans une paire à compte non nul est une donnée ordinaire, pas un marqueur de fin.
Aucun argument ne décrit la taille encodée, la capacité de sortie ou les données mal formées. Validez les ressources à leur création ou chargement, fournissez le zéro terminal et calculez la taille décompressée avant le décodage. Un flux invalide ou non terminé peut lire au-delà de la source et écrire au-delà de la destination.
Les décodeurs RAM utilisent des écritures ordinaires sans synchronisation avec les périodes d’accès du LCD. Gardez leurs destinations en RAM. Pour afficher le résultat, transférez-le séparément avec une API de copie VRAM adaptée, comme le fait l’exemple lorsque le LCD est arrêté.
Pendant une lecture avec banque, ne laissez pas une interruption changer le mappage ROM ni réutiliser la routine de copie distante : ces fonctions partagent leur suivi de banque. Placez le décodeur à pointeur ordinaire et sa source dans des mappages compatibles ; le passage à la banque de la fonction ne doit pas masquer le pointeur source ordinaire.
rle_decode et rle_decode_far sont déclarées dans rpg.h et implémentées dans lib/rle.c. Compilez cette implémentation une seule fois avec le jeu. L’exemple complet inclut rle.c après #pragma bank 0 pour garder appelant et décodeurs dans la banque commune ; ne passez pas aussi rle.c comme entrée séparée pour cet exemple. L’intrinsèque __rle_decode_vram ne nécessite aucun fichier d’implémentation de bibliothèque.
Exemple d’utilisation
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.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple décompresse neuf octets encodés dans un tampon RAM entouré de zones de garde, puis copie les 48 octets obtenus à l’adresse de tuiles 0x8800. RLE TO RAM affiche 048. La rangée supérieure, rouge sur CGB, présente les trois tuiles décodées par cette voie à pointeur ordinaire.
Chaque rangée contient de gauche à droite un carré plein de 8×8, un contour de 8×8 épais d’un pixel et un rectangle plein de 4×8 occupant la moitié gauche d’une tuile de 8×8. Ils sont aux colonnes de tuiles 2, 5 et 8 (x = 16, 40 et 64 pixels). Les rangées commencent à y = 32, 72 et 112 pixels. Les formes sont noires sur DMG ; les rangées CGB sont rouges, vertes et bleues. FAILED doit afficher 000. Les nombres comptent des octets : trois tuiles GB de 16 octets nécessitent 48 octets décompressés.
La matrice de validation couvre 42 cas : flux vide, répétition d’un octet, données nulles, répétition de 255 octets, sortie de 510 octets franchissant une page et données encodées franchissant une page source. Elle compare les 528 octets observés de destination et de garde, la longueur produite et le mappage ROM restauré. Les cas VRAM directe incluent LCD allumé/éteint sur DMG et CGB, ainsi que VBK 1 sur CGB. Les deux écrans pédagogiques sont contrôlés après 240 images émulées. Les ressources invalides, l’utilisation concurrente par interruption et le matériel réel ne sont pas couverts.


Commande de compilation
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-disasmImplémentation et source
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
Décompresse le même format count/value en RAM en lisant chaque octet encodé avec __farpeek8 dans la banque ROM fournie. Utilisez cette variante pour les ressources compressées d’une banque ROM commutable. La destination reste un pointeur RAM ordinaire ; l’argument de banque décrit la source.
Syntaxe
u16 rle_decode_far(void* dst, u8 bank, const void* src);Paramètres
dstPointeur vers une RAM inscriptible assez grande pour tout le flux décompressé. Aucune capacité n’est passée à la fonction. Séparez la sortie de la source encodée pour éviter d’écraser des paires pas encore lues.
bankNuméro de banque ROM source en u8. Banque et adresse CPU doivent correspondre au mapper de la cartouche et à l’emplacement de la ressource. La sélection de banque est restaurée après chaque lecture d’octet encodé. Ce n’est pas un sélecteur de banque VRAM de destination, et il ne peut pas représenter un numéro MBC5 sur neuf bits.
srcPointeur CPU vers le flux encodé dans la banque fournie. L’adresse avance, mais le numéro de banque reste fixe. Gardez tout le flux, zéro terminal compris, dans un mappage lisible ; franchir 0x7FFF ne poursuit pas automatiquement dans la banque ROM suivante.
Valeur renvoyée
Nombre d’octets écrits en u16. Un compte nul immédiat ne produit aucun octet et renvoie 0. Le terminateur n’est pas copié. La longueur décompressée doit tenir dans u16 ; le retour n’a pas de code d’erreur distinct et ne représente pas un nombre de tuiles.
Conditions et limites
Le codage porte sur des octets, pas sur du texte. Par exemple, {3, 0x12, 2, 0xA5, 0} donne cinq octets : 12 12 12 A5 A5. Cette liste de sortie est en hexadécimal. Une valeur nulle dans une paire à compte non nul est une donnée ordinaire, pas un marqueur de fin.
Aucun argument ne décrit la taille encodée, la capacité de sortie ou les données mal formées. Validez les ressources à leur création ou chargement, fournissez le zéro terminal et calculez la taille décompressée avant le décodage. Un flux invalide ou non terminé peut lire au-delà de la source et écrire au-delà de la destination.
Les décodeurs RAM utilisent des écritures ordinaires sans synchronisation avec les périodes d’accès du LCD. Gardez leurs destinations en RAM. Pour afficher le résultat, transférez-le séparément avec une API de copie VRAM adaptée, comme le fait l’exemple lorsque le LCD est arrêté.
Pendant une lecture avec banque, ne laissez pas une interruption changer le mappage ROM ni réutiliser la routine de copie distante : ces fonctions partagent leur suivi de banque. Placez le décodeur à pointeur ordinaire et sa source dans des mappages compatibles ; le passage à la banque de la fonction ne doit pas masquer le pointeur source ordinaire.
rle_decode et rle_decode_far sont déclarées dans rpg.h et implémentées dans lib/rle.c. Compilez cette implémentation une seule fois avec le jeu. L’exemple complet inclut rle.c après #pragma bank 0 pour garder appelant et décodeurs dans la banque commune ; ne passez pas aussi rle.c comme entrée séparée pour cet exemple. L’intrinsèque __rle_decode_vram ne nécessite aucun fichier d’implémentation de bibliothèque.
Exemple d’utilisation
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);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple lit le flux encodé dans la banque ROM 2, décompresse 48 octets en RAM et les transfère à 0x8830. BANKED RAM affiche 048. La rangée centrale est verte sur CGB. Un marqueur de la banque ROM 1 est aussi vérifié pour confirmer la restauration du mappage de l’appelant.
Chaque rangée contient de gauche à droite un carré plein de 8×8, un contour de 8×8 épais d’un pixel et un rectangle plein de 4×8 occupant la moitié gauche d’une tuile de 8×8. Ils sont aux colonnes de tuiles 2, 5 et 8 (x = 16, 40 et 64 pixels). Les rangées commencent à y = 32, 72 et 112 pixels. Les formes sont noires sur DMG ; les rangées CGB sont rouges, vertes et bleues. FAILED doit afficher 000. Les nombres comptent des octets : trois tuiles GB de 16 octets nécessitent 48 octets décompressés.
La matrice de validation couvre 42 cas : flux vide, répétition d’un octet, données nulles, répétition de 255 octets, sortie de 510 octets franchissant une page et données encodées franchissant une page source. Elle compare les 528 octets observés de destination et de garde, la longueur produite et le mappage ROM restauré. Les cas VRAM directe incluent LCD allumé/éteint sur DMG et CGB, ainsi que VBK 1 sur CGB. Les deux écrans pédagogiques sont contrôlés après 240 images émulées. Les ressources invalides, l’utilisation concurrente par interruption et le matériel réel ne sont pas couverts.


Commande de compilation
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-disasmImplémentation et source
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
Construit une valeur non signée de 16 bits avec deux tirages rng8 successifs. Le premier octet occupe les bits 15–8, le second les bits 7–0. À utiliser lorsque la plage souhaitée dépasse un octet.
Syntaxe
u16 rng16();Valeur renvoyée
Un résultat u16 (0–65535), formé par (first_byte << 8) | second_byte. Exactement deux tirages d’octet sont consommés ; cela n’établit pas une distribution uniforme des 65536 valeurs.
Conditions et limites
Ces appels partagent un état persistant. La reproduction exige la même cible, la même graine et le même ordre d’appels, y compris ceux des autres fonctions auxiliaires. Gardez réglage de graine et tirages dans un même contexte d’exécution ; ces vérifications ne prouvent pas la sûreté d’un accès concurrent depuis une interruption.
GB et FC utilisent des algorithmes différents et ne garantissent pas la même suite avec la même graine. Ce sont des générateurs déterministes pour le jeu, pas des sources d’aléa cryptographique. Les tests vérifient le comportement de l’implémentation, pas sa qualité statistique ni sa période.
Incluez rpg.h et compilez lib/rng.c avec le jeu pour utiliser les fonctions de bibliothèque. Les intrinsèques __rng_seed et __rng8 sont émises par le compilateur ; un programme limité à ces deux fonctions n’a pas besoin d’objet rng.c.
Exemple d’utilisation
rng_seed(0x1234);
word=rng16(); // First draw 2 is high, second draw 34 is low: 0x0222 = 546.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple montre l’assemblage d’un mot. Après réinitialisation à 0x1234, les octets 2 et 34 forment 0x0222 ; RNG16 affiche donc 00546. FIRST et SECOND montrent séparément les octets correspondants.
Le programme complet affiche les résultats décimaux sur fond blanc : texte noir sur DMG, bleu sur CGB. FAILED doit indiquer 00000. Les images montrent la sortie réelle de cet exemple dans l’émulateur.
La validation a comparé, pour chaque cas, 32 sorties et huit tirages d’octet suivants à un modèle hôte indépendant : 93 cas GB et 18 cas FC, avec graines constantes ou calculées à l’exécution et limites GB de plage, chance et poids. Les écrans pédagogiques ont été contrôlés après 240 images émulées. Le matériel réel et la qualité statistique n’ont pas été testés.


Commande de compilation
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-disasmImplémentation et source
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
Obtient un octet pseudo-aléatoire via la bibliothèque GB. rng8 appelle __rng8 exactement une fois ; c’est le tirage de base utilisé par les autres fonctions de rng.c.
Syntaxe
u8 rng8();Valeur renvoyée
Un résultat u8 (0–255), après un avancement du générateur partagé. Cela décrit le type et les bornes, pas une équiprobabilité de chaque octet.
Conditions et limites
Ces appels partagent un état persistant. La reproduction exige la même cible, la même graine et le même ordre d’appels, y compris ceux des autres fonctions auxiliaires. Gardez réglage de graine et tirages dans un même contexte d’exécution ; ces vérifications ne prouvent pas la sûreté d’un accès concurrent depuis une interruption.
GB et FC utilisent des algorithmes différents et ne garantissent pas la même suite avec la même graine. Ce sont des générateurs déterministes pour le jeu, pas des sources d’aléa cryptographique. Les tests vérifient le comportement de l’implémentation, pas sa qualité statistique ni sa période.
Incluez rpg.h et compilez lib/rng.c avec le jeu pour utiliser les fonctions de bibliothèque. Les intrinsèques __rng_seed et __rng8 sont émises par le compilateur ; un programme limité à ces deux fonctions n’a pas besoin d’objet rng.c.
Exemple d’utilisation
rng_seed(0x1234); // Reset the same generator used by the intrinsics.
wrapped=rng8(); // One byte draw: 2 after the preceding seed.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple compare le tirage d’octet de bibliothèque à l’intrinsèque. Après rng_seed(0x1234), RNG8 affiche 00002 comme FIRST. Fixer la graine ne consomme pas le premier tirage.
Le programme complet affiche les résultats décimaux sur fond blanc : texte noir sur DMG, bleu sur CGB. FAILED doit indiquer 00000. Les images montrent la sortie réelle de cet exemple dans l’émulateur.
La validation a comparé, pour chaque cas, 32 sorties et huit tirages d’octet suivants à un modèle hôte indépendant : 93 cas GB et 18 cas FC, avec graines constantes ou calculées à l’exécution et limites GB de plage, chance et poids. Les écrans pédagogiques ont été contrôlés après 240 images émulées. Le matériel réel et la qualité statistique n’ont pas été testés.


Commande de compilation
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-disasmImplémentation et source
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
Fait un choix oui/non avec rng_range(100) < percent. Utile pour des chances de jeu approximatives, par exemple décider si un ennemi laisse tomber un objet. Zéro renvoie toujours faux ; 100 ou plus renvoie toujours vrai. Aucun de ces cas limites ne consomme de tirage.
Syntaxe
u8 rng_chance(u8 percent);Paramètres
percentChance demandée en u8. Les valeurs 1–99 utilisent un octet réduit modulo ; 0 renvoie faux et 100–255 renvoient vrai. Les valeurs intermédiaires sont des seuils approximatifs, pas une garantie de pourcentages exacts.
Valeur renvoyée
Booléen normalisé : 0 pour faux, 1 pour vrai. Un seuil de 1 à 99 consomme un tirage d’octet.
Conditions et limites
La réduction modulo peut favoriser certains résultats lorsque la plage d’entrée n’est pas divisible par la borne. Le générateur sous-jacent n’est pas nécessairement uniforme non plus. Traitez les sélections bornées et les seuils de chance comme des approximations de jeu, pas des probabilités exactes.
Ces appels partagent un état persistant. La reproduction exige la même cible, la même graine et le même ordre d’appels, y compris ceux des autres fonctions auxiliaires. Gardez réglage de graine et tirages dans un même contexte d’exécution ; ces vérifications ne prouvent pas la sûreté d’un accès concurrent depuis une interruption.
GB et FC utilisent des algorithmes différents et ne garantissent pas la même suite avec la même graine. Ce sont des générateurs déterministes pour le jeu, pas des sources d’aléa cryptographique. Les tests vérifient le comportement de l’implémentation, pas sa qualité statistique ni sa période.
Incluez rpg.h et compilez lib/rng.c avec le jeu pour utiliser les fonctions de bibliothèque. Les intrinsèques __rng_seed et __rng8 sont émises par le compilateur ; un programme limité à ces deux fonctions n’a pas besoin d’objet rng.c.
Exemple d’utilisation
rng_seed(0x1234);
chance=rng_chance(50); // Here 2 % 100 < 50, so the result is 1 (true).Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple effectue une décision approximative à 50 %. L’octet issu de la graine vaut 2, et 2 % 100 < 50 est vrai ; CHANCE 50 affiche donc 00001. Un seul succès ne démontre pas un taux de réussite de 50 % à long terme.
Le programme complet affiche les résultats décimaux sur fond blanc : texte noir sur DMG, bleu sur CGB. FAILED doit indiquer 00000. Les images montrent la sortie réelle de cet exemple dans l’émulateur.
La validation a comparé, pour chaque cas, 32 sorties et huit tirages d’octet suivants à un modèle hôte indépendant : 93 cas GB et 18 cas FC, avec graines constantes ou calculées à l’exécution et limites GB de plage, chance et poids. Les écrans pédagogiques ont été contrôlés après 240 images émulées. Le matériel réel et la qualité statistique n’ont pas été testés.


Commande de compilation
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-disasmImplémentation et source
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
Renvoie le même mot obtenu par deux tirages que rng16. Cet alias de bibliothèque place le premier tirage dans l’octet haut et le second dans l’octet bas ; il ne saute aucune valeur supplémentaire avant de tirer.
Syntaxe
u16 rng_next16();Valeur renvoyée
Un résultat u16 (0–65535), formé par (first_byte << 8) | second_byte. Exactement deux tirages d’octet sont consommés ; cela n’établit pas une distribution uniforme des 65536 valeurs.
Conditions et limites
Ces appels partagent un état persistant. La reproduction exige la même cible, la même graine et le même ordre d’appels, y compris ceux des autres fonctions auxiliaires. Gardez réglage de graine et tirages dans un même contexte d’exécution ; ces vérifications ne prouvent pas la sûreté d’un accès concurrent depuis une interruption.
GB et FC utilisent des algorithmes différents et ne garantissent pas la même suite avec la même graine. Ce sont des générateurs déterministes pour le jeu, pas des sources d’aléa cryptographique. Les tests vérifient le comportement de l’implémentation, pas sa qualité statistique ni sa période.
Incluez rpg.h et compilez lib/rng.c avec le jeu pour utiliser les fonctions de bibliothèque. Les intrinsèques __rng_seed et __rng8 sont émises par le compilateur ; un programme limité à ces deux fonctions n’a pas besoin d’objet rng.c.
Exemple d’utilisation
rng_seed(0x1234);
nextword=rng_next16(); // The same two-draw word: 546.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple compare l’alias de mot à rng16 après des graines identiques. NEXT16 et RNG16 affichent 00546, soit deux tirages d’octet dans l’ordre haut/bas.
Le programme complet affiche les résultats décimaux sur fond blanc : texte noir sur DMG, bleu sur CGB. FAILED doit indiquer 00000. Les images montrent la sortie réelle de cet exemple dans l’émulateur.
La validation a comparé, pour chaque cas, 32 sorties et huit tirages d’octet suivants à un modèle hôte indépendant : 93 cas GB et 18 cas FC, avec graines constantes ou calculées à l’exécution et limites GB de plage, chance et poids. Les écrans pédagogiques ont été contrôlés après 240 images émulées. Le matériel réel et la qualité statistique n’ont pas été testés.


Commande de compilation
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-disasmImplémentation et source
kitaqgb/lib/rpg.h:209
Alias the two-step 16-bit generator.
kitaqgb/lib/rng.c:30
u16 rng_next16()
{
return rng16();
}rng_next8
Tire l’octet suivant avec la même opération que rng8. Le nom souligne l’avancement de la suite ; appeler successivement les deux noms consomme deux tirages consécutifs du même générateur partagé.
Syntaxe
u8 rng_next8();Valeur renvoyée
Un résultat u8 (0–255), après un avancement du générateur partagé. Cela décrit le type et les bornes, pas une équiprobabilité de chaque octet.
Conditions et limites
Ces appels partagent un état persistant. La reproduction exige la même cible, la même graine et le même ordre d’appels, y compris ceux des autres fonctions auxiliaires. Gardez réglage de graine et tirages dans un même contexte d’exécution ; ces vérifications ne prouvent pas la sûreté d’un accès concurrent depuis une interruption.
GB et FC utilisent des algorithmes différents et ne garantissent pas la même suite avec la même graine. Ce sont des générateurs déterministes pour le jeu, pas des sources d’aléa cryptographique. Les tests vérifient le comportement de l’implémentation, pas sa qualité statistique ni sa période.
Incluez rpg.h et compilez lib/rng.c avec le jeu pour utiliser les fonctions de bibliothèque. Les intrinsèques __rng_seed et __rng8 sont émises par le compilateur ; un programme limité à ces deux fonctions n’a pas besoin d’objet rng.c.
Exemple d’utilisation
rng_seed(0x1234);
nextbyte=rng_next8(); // One draw, just like rng8(): 2.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple vérifie l’alias d’octet après la même graine. NEXT8 et RNG8 affichent tous deux 00002, car le programme réinitialise la graine avant chaque comparaison ; sans ces remises à zéro, ils consommeraient des valeurs successives.
Le programme complet affiche les résultats décimaux sur fond blanc : texte noir sur DMG, bleu sur CGB. FAILED doit indiquer 00000. Les images montrent la sortie réelle de cet exemple dans l’émulateur.
La validation a comparé, pour chaque cas, 32 sorties et huit tirages d’octet suivants à un modèle hôte indépendant : 93 cas GB et 18 cas FC, avec graines constantes ou calculées à l’exécution et limites GB de plage, chance et poids. Les écrans pédagogiques ont été contrôlés après 240 images émulées. Le matériel réel et la qualité statistique n’ont pas été testés.


Commande de compilation
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-disasmImplémentation et source
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
Appelle rand_range avec la même borne supérieure exclue. Ce nom regroupe la sélection bornée avec les autres fonctions rng_. Il utilise le même tirage d’octet et le même modulo, y compris le résultat sans tirage pour une borne nulle.
Syntaxe
u8 rng_range(u8 max);Paramètres
maxBorne supérieure exclue en u8 (0–255). Pour max > 0, le résultat est inférieur à max. Ce paramètre ne peut pas représenter 256 ; utilisez rng8 pour obtenir toute la plage d’un octet sans réduction modulo.
Valeur renvoyée
Pour max > 0, un u8 de 0 à max−1 après un tirage. Pour max == 0, zéro sans tirage. Même max == 1 consomme un tirage, bien que le résultat soit toujours nul.
Conditions et limites
La réduction modulo peut favoriser certains résultats lorsque la plage d’entrée n’est pas divisible par la borne. Le générateur sous-jacent n’est pas nécessairement uniforme non plus. Traitez les sélections bornées et les seuils de chance comme des approximations de jeu, pas des probabilités exactes.
Ces appels partagent un état persistant. La reproduction exige la même cible, la même graine et le même ordre d’appels, y compris ceux des autres fonctions auxiliaires. Gardez réglage de graine et tirages dans un même contexte d’exécution ; ces vérifications ne prouvent pas la sûreté d’un accès concurrent depuis une interruption.
GB et FC utilisent des algorithmes différents et ne garantissent pas la même suite avec la même graine. Ce sont des générateurs déterministes pour le jeu, pas des sources d’aléa cryptographique. Les tests vérifient le comportement de l’implémentation, pas sa qualité statistique ni sa période.
Incluez rpg.h et compilez lib/rng.c avec le jeu pour utiliser les fonctions de bibliothèque. Les intrinsèques __rng_seed et __rng8 sont émises par le compilateur ; un programme limité à ces deux fonctions n’a pas besoin d’objet rng.c.
Exemple d’utilisation
rng_seed(0x1234);
alias=rng_range(10); // The same exclusive upper bound and result, 2.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple compare les deux noms de sélection bornée. Réinitialiser la graine avant chaque appel donne ALIAS 10 et RANGE 10 à 00002. La borne 10 elle-même est exclue.
Le programme complet affiche les résultats décimaux sur fond blanc : texte noir sur DMG, bleu sur CGB. FAILED doit indiquer 00000. Les images montrent la sortie réelle de cet exemple dans l’émulateur.
La validation a comparé, pour chaque cas, 32 sorties et huit tirages d’octet suivants à un modèle hôte indépendant : 93 cas GB et 18 cas FC, avec graines constantes ou calculées à l’exécution et limites GB de plage, chance et poids. Les écrans pédagogiques ont été contrôlés après 240 images émulées. Le matériel réel et la qualité statistique n’ont pas été testés.


Commande de compilation
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-disasmImplémentation et source
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
Fixe la graine via l’interface de bibliothèque GB. C’est un enrobage de __rng_seed : il réinitialise le même état partagé que rng8, rng16 et les fonctions de sélection, sans créer de générateur distinct.
Syntaxe
void rng_seed(u16 seed);Paramètres
seedGraine non signée de 16 bits, de 0 à 65535. Les deux octets sont stockés tels quels. Choisissez et notez la graine avant la suite de tirages de jeu à reproduire.
Valeur renvoyée
Aucune (void).
Conditions et limites
L’état zéro est accepté. Au prochain tirage d’octet, le générateur GB le remplace par 0x5AA5 avant d’avancer ; __rng_seed(0) suivi de __rng8() renvoie donc 122. Réinitialiser sans cesse la graine redémarre la suite au lieu d’ajouter du hasard.
Ces appels partagent un état persistant. La reproduction exige la même cible, la même graine et le même ordre d’appels, y compris ceux des autres fonctions auxiliaires. Gardez réglage de graine et tirages dans un même contexte d’exécution ; ces vérifications ne prouvent pas la sûreté d’un accès concurrent depuis une interruption.
GB et FC utilisent des algorithmes différents et ne garantissent pas la même suite avec la même graine. Ce sont des générateurs déterministes pour le jeu, pas des sources d’aléa cryptographique. Les tests vérifient le comportement de l’implémentation, pas sa qualité statistique ni sa période.
Incluez rpg.h et compilez lib/rng.c avec le jeu pour utiliser les fonctions de bibliothèque. Les intrinsèques __rng_seed et __rng8 sont émises par le compilateur ; un programme limité à ces deux fonctions n’a pas besoin d’objet rng.c.
Exemple d’utilisation
rng_seed(0x1234); // Reset the same generator used by the intrinsics.
wrapped=rng8(); // One byte draw: 2 after the preceding seed.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple compare le tirage d’octet de bibliothèque à l’intrinsèque. Après rng_seed(0x1234), RNG8 affiche 00002 comme FIRST. Fixer la graine ne consomme pas le premier tirage.
Le programme complet affiche les résultats décimaux sur fond blanc : texte noir sur DMG, bleu sur CGB. FAILED doit indiquer 00000. Les images montrent la sortie réelle de cet exemple dans l’émulateur.
La validation a comparé, pour chaque cas, 32 sorties et huit tirages d’octet suivants à un modèle hôte indépendant : 93 cas GB et 18 cas FC, avec graines constantes ou calculées à l’exécution et limites GB de plage, chance et poids. Les écrans pédagogiques ont été contrôlés après 240 images émulées. Le matériel réel et la qualité statistique n’ont pas été testés.


Commande de compilation
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-disasmImplémentation et source
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
Effectue le même contrôle d’intégrité que save_exists sans extraire les données.
Syntaxe
u8 save_check(u8 slot);Paramètres
slotNuméro d’emplacement de 0 à 3.
Valeur renvoyée
Renvoie 1 si valide, sinon 0. Une sauvegarde de longueur nulle peut être valide.
Conditions et limites
Par défaut, quatre emplacements de 512 octets contiennent chacun un en-tête de six octets et jusqu’à 506 octets de données. L’exemple utilise MBC5 avec 8 Kio de SRAM. Les appels se terminent avec la RAM désactivée, sans restaurer sa banque ni son état d’activation précédent.
Exemple d’utilisation
result[4]=save_check(0);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Sauvegardez trois octets, 7/42/255, puis testez une longueur différente, un emplacement invalide et une somme de contrôle endommagée. Un chargement réussi donne 42 au milieu ; une lecture échouée préserve la destination à 77 ; la validation après effacement renvoie 0.


Commande de compilation
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=8kImplémentation et source
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
Met à zéro les 512 octets d’un emplacement pour invalider sa sauvegarde.
Syntaxe
void save_clear(u8 slot);Paramètres
slotNuméro d’emplacement de 0 à 3.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Par défaut, quatre emplacements de 512 octets contiennent chacun un en-tête de six octets et jusqu’à 506 octets de données. L’exemple utilise MBC5 avec 8 Kio de SRAM. Les appels se terminent avec la RAM désactivée, sans restaurer sa banque ni son état d’activation précédent.
Ignore les emplacements hors de 0..3 et laisse les autres inchangés.
Exemple d’utilisation
save_clear(0);result[16]=save_check(0);result[17]=save_write(3,payload,0);result[18]=save_exists(3);save_clear(3);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Sauvegardez trois octets, 7/42/255, puis testez une longueur différente, un emplacement invalide et une somme de contrôle endommagée. Un chargement réussi donne 42 au milieu ; une lecture échouée préserve la destination à 77 ; la validation après effacement renvoie 0.


Commande de compilation
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=8kImplémentation et source
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
Valide l’en-tête, la longueur et la somme de contrôle d’un emplacement pour vérifier la présence d’une sauvegarde utilisable.
Syntaxe
u8 save_exists(u8 slot);Paramètres
slotNuméro d’emplacement de 0 à 3.
Valeur renvoyée
Renvoie 1 si valide, sinon 0. Une sauvegarde de longueur nulle peut être valide.
Conditions et limites
Par défaut, quatre emplacements de 512 octets contiennent chacun un en-tête de six octets et jusqu’à 506 octets de données. L’exemple utilise MBC5 avec 8 Kio de SRAM. Les appels se terminent avec la RAM désactivée, sans restaurer sa banque ni son état d’activation précédent.
Exemple d’utilisation
result[0]=save_exists(0);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Sauvegardez trois octets, 7/42/255, puis testez une longueur différente, un emplacement invalide et une somme de contrôle endommagée. Un chargement réussi donne 42 au milieu ; une lecture échouée préserve la destination à 77 ; la validation après effacement renvoie 0.


Commande de compilation
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=8kImplémentation et source
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
Sélectionne la banque RAM zéro, l’active brièvement puis la désactive.
Syntaxe
void save_init();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Par défaut, quatre emplacements de 512 octets contiennent chacun un en-tête de six octets et jusqu’à 506 octets de données. L’exemple utilise MBC5 avec 8 Kio de SRAM. Les appels se terminent avec la RAM désactivée, sans restaurer sa banque ni son état d’activation précédent.
N’efface pas les sauvegardes, ne détecte pas le matériel de la cartouche et ne formate pas les emplacements.
Exemple d’utilisation
save_init();save_clear(0);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Sauvegardez trois octets, 7/42/255, puis testez une longueur différente, un emplacement invalide et une somme de contrôle endommagée. Un chargement réussi donne 42 au milieu ; une lecture échouée préserve la destination à 77 ; la validation après effacement renvoie 0.


Commande de compilation
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=8kImplémentation et source
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
Charge les données sauvegardées avec la même validation que save_read.
Syntaxe
u8 save_load(u8 slot, void* data, u16 len);Paramètres
slotNuméro d’emplacement de 0 à 3.
dataDestination accessible en écriture de len octets.
lenLongueur des données de 0 à 506 octets. La lecture exige une correspondance exacte avec la longueur enregistrée.
Valeur renvoyée
Renvoie 1 si le chargement réussit, sinon 0 ; la longueur demandée doit correspondre à la longueur enregistrée.
Conditions et limites
Par défaut, quatre emplacements de 512 octets contiennent chacun un en-tête de six octets et jusqu’à 506 octets de données. L’exemple utilise MBC5 avec 8 Kio de SRAM. Les appels se terminent avec la RAM désactivée, sans restaurer sa banque ni son état d’activation précédent.
La somme de contrôle additive sur huit bits ne détecte pas toutes les corruptions. Les écritures ne sont pas atomiques face à une coupure de courant ; un résultat de succès ne garantit donc pas à lui seul la persistance physique.
Exemple d’utilisation
readback[1]=0;result[10]=save_load(0,readback,3);result[11]=readback[1];Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Sauvegardez trois octets, 7/42/255, puis testez une longueur différente, un emplacement invalide et une somme de contrôle endommagée. Un chargement réussi donne 42 au milieu ; une lecture échouée préserve la destination à 77 ; la validation après effacement renvoie 0.


Commande de compilation
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=8kImplémentation et source
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
Valide l’en-tête, la longueur exacte et la somme de contrôle, puis copie les données uniquement si tout est valide.
Syntaxe
u8 save_read(u8 slot, void* data, u16 len);Paramètres
slotNuméro d’emplacement de 0 à 3.
dataDestination accessible en écriture de len octets.
lenLongueur des données de 0 à 506 octets. La lecture exige une correspondance exacte avec la longueur enregistrée.
Valeur renvoyée
Renvoie 1 en cas de succès, 0 si la validation échoue ; l’échec laisse la destination inchangée.
Conditions et limites
Par défaut, quatre emplacements de 512 octets contiennent chacun un en-tête de six octets et jusqu’à 506 octets de données. L’exemple utilise MBC5 avec 8 Kio de SRAM. Les appels se terminent avec la RAM désactivée, sans restaurer sa banque ni son état d’activation précédent.
La somme de contrôle additive sur huit bits ne détecte pas toutes les corruptions. Les écritures ne sont pas atomiques face à une coupure de courant ; un résultat de succès ne garantit donc pas à lui seul la persistance physique.
Exemple d’utilisation
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];Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Sauvegardez trois octets, 7/42/255, puis testez une longueur différente, un emplacement invalide et une somme de contrôle endommagée. Un chargement réussi donne 42 au milieu ; une lecture échouée préserve la destination à 77 ; la validation après effacement renvoie 0.


Commande de compilation
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=8kImplémentation et source
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
Écrit les données, leur longueur et la somme de contrôle dans un emplacement.
Syntaxe
u8 save_write(u8 slot, const void* data, u16 len);Paramètres
slotNuméro d’emplacement de 0 à 3.
dataSource lisible de len octets.
lenLongueur des données de 0 à 506 octets. La lecture exige une correspondance exacte avec la longueur enregistrée.
Valeur renvoyée
Renvoie 1 pour des arguments valides, 0 pour un emplacement ou une longueur invalide ; n’effectue pas de vérification par relecture.
Conditions et limites
Par défaut, quatre emplacements de 512 octets contiennent chacun un en-tête de six octets et jusqu’à 506 octets de données. L’exemple utilise MBC5 avec 8 Kio de SRAM. Les appels se terminent avec la RAM désactivée, sans restaurer sa banque ni son état d’activation précédent.
La somme de contrôle additive sur huit bits ne détecte pas toutes les corruptions. Les écritures ne sont pas atomiques face à une coupure de courant ; un résultat de succès ne garantit donc pas à lui seul la persistance physique.
Exemple d’utilisation
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);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Sauvegardez trois octets, 7/42/255, puis testez une longueur différente, un emplacement invalide et une somme de contrôle endommagée. Un chargement réussi donne 42 au milieu ; une lecture échouée préserve la destination à 77 ; la validation après effacement renvoie 0.


Commande de compilation
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=8kImplémentation et source
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
Sélectionne un script et réinitialise son compteur d’attente, le résultat du choix et l’emplacement de retour sauvegardé.
Syntaxe
void script_run(u8 bank, const u8* script);Paramètres
bankBanque ROM du flux d’instructions.
scriptDébut d’un flux valide terminé ; cet appel le prépare sans exécuter de commandes.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Codes d’opération : 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). Les mots sont en petit-boutiste. Gardez les chaînes, tables de pointeurs et instructions lisibles et dans leurs banques mappées.
Exemple d’utilisation
flag_clear(19);script_run(1,(const u8*)&entry);result[0]=flag_get(19);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Sautez de la banque 1 à la banque 2, activez le drapeau 19 et attendez. Les deux premiers appels d’attente renvoient 1 ; le drapeau de destination passe à 1 ; la fin après WAIT renvoie 2. Le drapeau prouve que le contrôle a atteint l’autre banque.


Commande de compilation
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=noneImplémentation et source
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
Avance dans les commandes jusqu’à ce qu’une sortie, un choix, une attente ou la fin rende le contrôle.
Syntaxe
u8 script_step();Valeur renvoyée
0=retour de contrôle TEXT/CHOICE ; 1=attente ; 2=terminé ou inactif. Les codes d’opération inconnus terminent aussi avec 2.
Conditions et limites
Codes d’opération : 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). Les mots sont en petit-boutiste. Gardez les chaînes, tables de pointeurs et instructions lisibles et dans leurs banques mappées.
WAIT n renvoie 1 au décodage, puis attend encore n appels. CALL_EVENT ne possède qu’un emplacement de retour sauvegardé. CHOICE exige un nombre non nul et bloque en interne jusqu’au choix. Une boucle de sauts sans restitution de contrôle bloque la boucle de jeu ; assurez-vous d’atteindre une commande de fin ou de restitution de contrôle.
Exemple d’utilisation
result[3]=script_step();result[4]=flag_get(19);result[5]=script_step();result[6]=script_step();result[7]=script_step();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Sautez de la banque 1 à la banque 2, activez le drapeau 19 et attendez. Les deux premiers appels d’attente renvoient 1 ; le drapeau de destination passe à 1 ; la fin après WAIT renvoie 2. Le drapeau prouve que le contrôle a atteint l’autre banque.


Commande de compilation
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=noneImplémentation et source
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
Fait attendre le nombre demandé de prochains appels à script_step.
Syntaxe
void script_wait_frames(u8 n);Paramètres
nNombre d’appels en attente, de 0 à 255 ; zéro annule l’attente.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Cela ne correspond à un nombre de trames que si script_step est appelé une fois par trame ; la fonction n’attend pas elle-même VBlank.
Exemple d’utilisation
script_wait_frames(2);result[1]=script_step();result[2]=script_step();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Sautez de la banque 1 à la banque 2, activez le drapeau 19 et attendez. Les deux premiers appels d’attente renvoient 1 ; le drapeau de destination passe à 1 ; la fin après WAIT renvoie 2. Le drapeau prouve que le contrôle a atteint l’autre banque.


Commande de compilation
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=noneImplémentation et source
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
Dessine une liste verticale dans la zone active et attend un choix. UP/DOWN déplacent le curseur avec rebouclage ; A valide et B annule. La boucle redessine les choix et interroge l’entrée une fois après une attente VBlank. Renvoie un indice à partir de zéro, ou 255 pour une annulation ou une liste vide.
Syntaxe
u8 text_choice(const u8* const* choices, u8 count);Paramètres
choicesPointeur vers un tableau de count pointeurs de chaînes lisibles. Chaque chaîne se termine par zéro et contient des ID de tuile bruts ; les libellés n’interprètent pas les codes de dialogue. Gardez table et chaînes mappées jusqu’à la fin du choix.
countNombre de choix. Zéro renvoie immédiatement 255 sans lire la table de pointeurs. Sinon, prévoyez au moins count lignes intérieures et assez de largeur pour une case de curseur plus le libellé le plus long. Aucun découpage ni défilement n’est effectué.
Valeur renvoyée
Indice de 0 à count−1 lors d’une validation par A. La valeur 255 signifie annulation par B ou count nul ; distinguez ces cas dans l’appelant si nécessaire. La fonction ne ferme pas la zone et n’efface pas la liste.
Conditions et limites
Utilisez un rectangle BG valide et chargez d’abord les tuiles de police et de cadre. La zone logicielle utilise la carte BG choisie par le bit 3 de LCDC, sans activer la couche Window matérielle. Sur CGB, utilisez VBK 0 pour les numéros et réglez les couleurs séparément. Les exemples fournissent la police mappée en ASCII et les tuiles de cadre, curseur et indicateur de page. Dialogues et choix utilisent des ID de tuile d’un octet, sans décodage UTF-8. Pour d’autres caractères, fournissez leurs glyphes et encodez le texte avec ces ID, en réservant les octets de contrôle du dialogue.
Ouvrez et dimensionnez la zone avant l’appel. La sélection utilise sa position mémorisée sans vérifier qu’elle est ouverte. Les libellés commencent deux colonnes après le bord gauche et une ligne sous le haut ; le curseur est juste à leur gauche. Leur affichage n’utilise pas le réglage de vitesse du dialogue.
La boucle réagit aux nouveaux appuis, UP avant DOWN et A avant B. Maintenir une direction ne répète pas le mouvement ; relâchez puis appuyez à nouveau. Le masque précédent commençant à zéro, un bouton tenu peut agir dès l’entrée. Déplacement et A simultanés renvoient l’indice après déplacement, même si le dernier curseur dessiné montre encore l’ancienne position.
Ces fonctions sont bloquantes : pendant l’attente, elles n’appellent ni mise à jour du jeu, ni service musical, ni boucle de rendu. LCD éteint, __wait_vblank revient immédiatement ; vitesse des caractères et WAIT ne créent donc pas de délais en trames. Gardez le LCD actif pour le dialogue temporisé et les entrées cadencées par trame. Utilisez une machine à états côté jeu si d’autres tâches doivent avancer pendant la conversation.
Les écritures de tuiles sûres sous-jacentes attendent un mode LCD accessible et encadrent l’écriture par DI/EI. Elles peuvent activer les interruptions au lieu de préserver un état initialement désactivé. Ne les appelez pas depuis un gestionnaire d’interruption et ne comptez pas sur elles pour préserver cet état.
Chaque exemple complet inclut text.c une fois. Compilez avec les répertoires d’inclusion de la bibliothèque et des exemples du manuel ; n’ajoutez pas aussi lib/text.c comme source séparée. L’exemple de flux distant utilise MBC5 et une ROM de 64 Kio pour contenir les données de banque 2.
Exemple d’utilisation
selected=text_choice(dialogue_choices,3);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Appuyez une fois sur DOWN puis sur A. Dans la capture, le curseur pointant à droite est à côté de SHIELD en (2,4) et SELECTED vaut 1. Les libellés commencent en (3,3), (3,4) et (3,5). Cadre, curseur et libellés sont verts sur CGB, noirs sur DMG ; résultat et consignes restent noirs.
Les tests sur émulateur comparent tout le contenu BG et les quatre images d’exemple. D’autres exécutions couvrent ouverture/fermeture, flux ordinaires et bancarisés, temporisations, pages explicites et automatiques, avances A/B/START, boutons tenus, choix circulaires, listes vides et priorités simultanées. Des points de contrôle avant et après l’entrée scriptée vérifient le blocage réel des pages. Matériel physique et concurrence des interruptions ne sont pas testés.


Commande de compilation
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-disasmImplémentation et source
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
Remplit un rectangle de la carte de tuiles du fond avec TEXT_TILE_FILL. Utilisez-le pour effacer un libellé, un champ numérique ou une partie de panneau. Le curseur actif ne bouge pas ; la zone de texte reste ouverte et garde ses dimensions.
Syntaxe
void text_clear_rect(u8 x, u8 y, u8 w, u8 h);Paramètres
xColonne de départ, en cases de 8×8 de la carte du fond. Toute la sortie doit tenir dans les colonnes 0–31. Sans défilement du fond, les colonnes visibles sont 0–19.
yLigne de départ, de 0 à 31, en cases de 8×8 de la carte du fond. Sans défilement, les lignes 0–17 sont visibles. Un rectangle doit aussi tenir verticalement dans la carte.
wLargeur en cases. Pour text_window, elle comprend les deux colonnes du cadre, laissant max(w−2, 0) colonnes intérieures. Pour text_clear_rect, c’est le nombre de cases à remplir sur chaque ligne.
hHauteur en cases. Pour text_window, elle comprend les bords supérieur et inférieur, laissant max(h−2, 0) lignes intérieures. Pour text_clear_rect, c’est le nombre de lignes à remplir.
Valeur renvoyée
Aucune valeur de retour. La fonction écrit les cases de la carte avant de rendre la main ; elle ne renvoie ni nombre de caractères ni code d’état.
Conditions et limites
Ces fonctions écrivent dans la carte BG sélectionnée par le bit 3 de LCDC. La fenêtre de texte est une zone logicielle sur cette carte, et non le plan Window matériel. Gardez VBK à 0 sur CGB pour écrire les numéros de tuiles ; ces appels ne règlent ni attributs de couleur, ni palettes, ni défilement.
Chargez la police et les graphismes du cadre avant de dessiner. Les ID de cadre par défaut vont de 1 à 6, la tuile de remplissage vaut 0 et les chiffres commencent à ASCII 0 (tuile 48). Le signe moins utilise ASCII - (tuile 45). L’exemple fournit six tuiles de cadre et la police du manuel, dont les ID de glyphes correspondent à l’ASCII.
Gardez rectangles et texte dans la carte de 32×32. Le remplissage ne réduit pas la largeur ou la hauteur aux limites de la carte. Une largeur ou une hauteur nulle ne remplit rien ; text_window enregistre néanmoins une zone ouverte, sans intérieur utilisable.
Les fonctions numériques publiques utilisent exactement la largeur du nouveau nombre. Elles n’effacent pas les cases restantes à droite. Écrire 7 sur 12345 au même endroit affiche 72345. Pour n’obtenir que 7, effacez d’abord le champ réservé de cinq cases avec text_clear_rect. Réservez six cases pour un entier signé sur 16 bits.
Les intrinsèques d’écriture vérifient l’état du LCD : éteint, elles écrivent immédiatement ; allumé, elles attendent un mode autorisant l’écriture et encadrent celle-ci par DI/EI. Ce chemin peut réactiver les interruptions au retour ; ne supposez donc pas qu’il préserve leur désactivation. Ici, les exemples et tests octet par octet écrivent avec le LCD éteint.
L’exemple complet inclut text.c une seule fois pour compiler l’implémentation avec le programme. Ne passez pas également lib/text.c comme entrée séparée. Pour personnaliser les constantes de tuiles TEXT_*, définissez-les avant d’inclure rpg.h et l’implémentation ; utilisez les mêmes définitions partout où la bibliothèque est compilée.
Exemple d’utilisation
text_clear_rect(7,5,5,1);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Au départ, le cadre contient KEEP ERASE KEEP sur la ligne 5. Effacer cinq cases en (7,5) supprime ERASE tout en conservant les deux KEEP et le cadre. La ligne CLEAN efface elle aussi un champ numérique de cinq cases avant d’écrire 7.
La vérification compare chaque pixel visible et les 1024 octets de la carte BG dans les deux écrans d’exemple. Des ROM DMG/CGB distinctes testent les 256 valeurs d’octet non signé, les changements de nombre de chiffres et les extrêmes signés, en conservant des points sentinelles à côté de chaque nombre. Les contrôles de placement couvrent les rectangles vides ou étroits, les bords de carte, les octets de tuiles dont la valeur correspond à un code de contrôle et le curseur de fenêtre après des écritures absolues. Il s’agit de tests sur émulateur, pas sur matériel physique.


Commande de compilation
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-disasmImplémentation et source
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
Efface la zone de texte active, cadre compris, avec TEXT_TILE_FILL et la marque fermée. Un nouvel appel lorsqu’elle est fermée est sans effet. Les anciennes tuiles de fond présentes avant l’ouverture ne sont pas restaurées.
Syntaxe
void text_close();Valeur renvoyée
Aucune valeur de retour. Le dessin et les attentes bloquantes ont lieu avant le retour.
Conditions et limites
Utilisez un rectangle BG valide et chargez d’abord les tuiles de police et de cadre. La zone logicielle utilise la carte BG choisie par le bit 3 de LCDC, sans activer la couche Window matérielle. Sur CGB, utilisez VBK 0 pour les numéros et réglez les couleurs séparément. Les exemples fournissent la police mappée en ASCII et les tuiles de cadre, curseur et indicateur de page. Dialogues et choix utilisent des ID de tuile d’un octet, sans décodage UTF-8. Pour d’autres caractères, fournissez leurs glyphes et encodez le texte avec ces ID, en réservant les octets de contrôle du dialogue.
Les caractères ordinaires sont ignorés si la zone est fermée ou sans intérieur utilisable. Les contrôles restent interprétés : WAIT peut bloquer et les commandes de page peuvent attendre ou effacer la zone mémorisée. text_print sur une zone fermée n’est donc pas systématiquement sans effet.
Ces fonctions sont bloquantes : pendant l’attente, elles n’appellent ni mise à jour du jeu, ni service musical, ni boucle de rendu. LCD éteint, __wait_vblank revient immédiatement ; vitesse des caractères et WAIT ne créent donc pas de délais en trames. Gardez le LCD actif pour le dialogue temporisé et les entrées cadencées par trame. Utilisez une machine à états côté jeu si d’autres tâches doivent avancer pendant la conversation.
Les écritures de tuiles sûres sous-jacentes attendent un mode LCD accessible et encadrent l’écriture par DI/EI. Elles peuvent activer les interruptions au lieu de préserver un état initialement désactivé. Ne les appelez pas depuis un gestionnaire d’interruption et ne comptez pas sur elles pour préserver cet état.
Chaque exemple complet inclut text.c une fois. Compilez avec les répertoires d’inclusion de la bibliothèque et des exemples du manuel ; n’ajoutez pas aussi lib/text.c comme source séparée. L’exemple de flux distant utilise MBC5 et une ROM de 64 Kio pour contenir les données de banque 2.
Exemple d’utilisation
text_close();
text_print("HIDDEN"); // With the area closed, ordinary characters are not drawn.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple ouvre une zone de 18×3 cases en (1,9), écrit ERASE ME, la ferme puis tente d’écrire HIDDEN. Sous CLOSED AREA, les cases x=1–18 et y=9–11 doivent être vides, sans texte ni cadre. Le dialogue bleu au-dessus reste visible.
Les tests sur émulateur comparent tout le contenu BG et les quatre images d’exemple. D’autres exécutions couvrent ouverture/fermeture, flux ordinaires et bancarisés, temporisations, pages explicites et automatiques, avances A/B/START, boutons tenus, choix circulaires, listes vides et priorités simultanées. Des points de contrôle avant et après l’entrée scriptée vérifient le blocage réel des pages. Matériel physique et concurrence des interruptions ne sont pas testés.


Commande de compilation
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-disasmImplémentation et source
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
Ouvre une zone de texte logicielle sur la carte de fond. Mémorise sa position et sa taille, replace le curseur au premier emplacement intérieur, dessine le cadre et vide l’intérieur. Ouvrir une autre zone change la zone et le curseur actifs, sans effacer une zone déjà dessinée ailleurs.
Syntaxe
void text_open(u8 x, u8 y, u8 w, u8 h);Paramètres
xColonne gauche de la zone en cases BG de 8×8 pixels. Gardez toute la largeur dans les colonnes 0–31.
yLigne supérieure de la zone en cases BG de 8×8 pixels. Gardez toute la hauteur dans les lignes 0–31.
wLargeur totale en cases, bordures gauche et droite comprises. Il faut au moins trois cases pour une colonne intérieure de caractères.
hHauteur totale en cases, bordures supérieure et inférieure comprises. Il faut au moins trois cases pour une ligne intérieure de caractères.
Valeur renvoyée
Aucune valeur de retour. Le dessin et les attentes bloquantes ont lieu avant le retour.
Conditions et limites
Utilisez un rectangle BG valide et chargez d’abord les tuiles de police et de cadre. La zone logicielle utilise la carte BG choisie par le bit 3 de LCDC, sans activer la couche Window matérielle. Sur CGB, utilisez VBK 0 pour les numéros et réglez les couleurs séparément. Les exemples fournissent la police mappée en ASCII et les tuiles de cadre, curseur et indicateur de page. Dialogues et choix utilisent des ID de tuile d’un octet, sans décodage UTF-8. Pour d’autres caractères, fournissez leurs glyphes et encodez le texte avec ces ID, en réservant les octets de contrôle du dialogue.
Ces fonctions sont bloquantes : pendant l’attente, elles n’appellent ni mise à jour du jeu, ni service musical, ni boucle de rendu. LCD éteint, __wait_vblank revient immédiatement ; vitesse des caractères et WAIT ne créent donc pas de délais en trames. Gardez le LCD actif pour le dialogue temporisé et les entrées cadencées par trame. Utilisez une machine à états côté jeu si d’autres tâches doivent avancer pendant la conversation.
Les écritures de tuiles sûres sous-jacentes attendent un mode LCD accessible et encadrent l’écriture par DI/EI. Elles peuvent activer les interruptions au lieu de préserver un état initialement désactivé. Ne les appelez pas depuis un gestionnaire d’interruption et ne comptez pas sur elles pour préserver cet état.
Chaque exemple complet inclut text.c une fois. Compilez avec les répertoires d’inclusion de la bibliothèque et des exemples du manuel ; n’ajoutez pas aussi lib/text.c comme source séparée. L’exemple de flux distant utilise MBC5 et une ROM de 64 Kio pour contenir les données de banque 2.
Exemple d’utilisation
text_open(1,2,18,5);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
DIALOGUE FLOW ouvre un cadre de 18×5 cases en (1,2), avec un intérieur de 16×3. NEAR, READY et BANK 2 occupent les trois lignes. Les traits visibles s’étendent de x=11 à 147 et y=19 à 51 pixels. Cadre et texte sont bleus sur CGB, noirs sur DMG. L’ouverture ultérieure de la zone de test d’effacement laisse ce cadre visible.
Les tests sur émulateur comparent tout le contenu BG et les quatre images d’exemple. D’autres exécutions couvrent ouverture/fermeture, flux ordinaires et bancarisés, temporisations, pages explicites et automatiques, avances A/B/START, boutons tenus, choix circulaires, listes vides et priorités simultanées. Des points de contrôle avant et après l’entrée scriptée vérifient le blocage réel des pages. Matériel physique et concurrence des interruptions ne sont pas testés.


Commande de compilation
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-disasmImplémentation et source
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
Lit un flux de contrôle via un pointeur ordinaire et écrit ses tuiles de caractères au curseur de la fenêtre active. Interprète retours à la ligne, attentes temporisées et de page, avec renvoi à la largeur intérieure. Ne revient qu’à END ; une attente de page peut donc bloquer jusqu’à l’appui sur un bouton.
Syntaxe
void text_print(const u8* str);Paramètres
strPointeur lisible vers un flux terminé par TEXT_CTRL_END (0). Gardez tout le flux mappé pendant les attentes bloquantes, y compris l’opérande après WAIT. Aucune longueur de tampon ni vérification de validité n’est fournie.
Valeur renvoyée
Aucune valeur de retour. Le dessin et les attentes bloquantes ont lieu avant le retour.
Conditions et limites
Utilisez un rectangle BG valide et chargez d’abord les tuiles de police et de cadre. La zone logicielle utilise la carte BG choisie par le bit 3 de LCDC, sans activer la couche Window matérielle. Sur CGB, utilisez VBK 0 pour les numéros et réglez les couleurs séparément. Les exemples fournissent la police mappée en ASCII et les tuiles de cadre, curseur et indicateur de page. Dialogues et choix utilisent des ID de tuile d’un octet, sans décodage UTF-8. Pour d’autres caractères, fournissez leurs glyphes et encodez le texte avec ces ID, en réservant les octets de contrôle du dialogue.
Octets de contrôle : 0x00 termine le flux ; 0x0A passe à la ligne intérieure suivante ; 0x01 consomme l’octet suivant comme nombre d’attentes VBlank, y compris zéro ; 0x02 attend un changement de page, vide l’intérieur et réinitialise le curseur. Les autres octets sont des ID de tuile. Un opérande WAIT nul n’est pas un marqueur END.
Dépasser la dernière ligne intérieure par saut ou renvoi automatique affiche le repère de page, attend A, B ou START, vide l’intérieur puis reprend à la première case. La page est remplacée, pas défilée. Un 0x02 explicite attend sans ajouter de repère. Le test de page débute sans bouton mémorisé : un bouton déjà tenu au début peut donc faire avancer la page.
Les caractères ordinaires sont ignorés si la zone est fermée ou sans intérieur utilisable. Les contrôles restent interprétés : WAIT peut bloquer et les commandes de page peuvent attendre ou effacer la zone mémorisée. text_print sur une zone fermée n’est donc pas systématiquement sans effet.
Ces fonctions sont bloquantes : pendant l’attente, elles n’appellent ni mise à jour du jeu, ni service musical, ni boucle de rendu. LCD éteint, __wait_vblank revient immédiatement ; vitesse des caractères et WAIT ne créent donc pas de délais en trames. Gardez le LCD actif pour le dialogue temporisé et les entrées cadencées par trame. Utilisez une machine à états côté jeu si d’autres tâches doivent avancer pendant la conversation.
Les écritures de tuiles sûres sous-jacentes attendent un mode LCD accessible et encadrent l’écriture par DI/EI. Elles peuvent activer les interruptions au lieu de préserver un état initialement désactivé. Ne les appelez pas depuis un gestionnaire d’interruption et ne comptez pas sur elles pour préserver cet état.
Chaque exemple complet inclut text.c une fois. Compilez avec les répertoires d’inclusion de la bibliothèque et des exemples du manuel ; n’ajoutez pas aussi lib/text.c comme source séparée. L’exemple de flux distant utilise MBC5 et une ROM de 64 Kio pour contenir les données de banque 2.
Exemple d’utilisation
text_print(dialogue_near);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le flux ordinaire écrit NEAR, un saut de ligne, READY et une attente de douze appels avant END. NEAR commence à la tuile (2,3), READY à (2,4). Le flux bancarisé suivant reprend au même curseur ; son premier saut place donc BANK 2 sur la troisième ligne intérieure.
Les tests sur émulateur comparent tout le contenu BG et les quatre images d’exemple. D’autres exécutions couvrent ouverture/fermeture, flux ordinaires et bancarisés, temporisations, pages explicites et automatiques, avances A/B/START, boutons tenus, choix circulaires, listes vides et priorités simultanées. Des points de contrôle avant et après l’entrée scriptée vérifient le blocage réel des pages. Matériel physique et concurrence des interruptions ne sont pas testés.


Commande de compilation
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-disasmImplémentation et source
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
Interprète le même flux de dialogue en lisant chaque octet dans la banque ROM indiquée avec __farpeek8. Utilisez-le pour un dialogue hors de la banque source actuellement mappée. Placement, vitesse, renvoi à la ligne et contrôle des pages sont identiques à text_print.
Syntaxe
void text_print_far(u8 bank, const u8* str);Paramètres
bankNuméro de banque ROM source sur huit bits non signés. L’exemple stocke le flux en banque 2 et vérifie que l’appelant peut encore lire un repère en banque 1 après l’affichage.
strAdresse CPU du flux dans la banque indiquée. L’adresse avance, mais la banque reste fixe ; franchir la fenêtre ROM commutable ne poursuit pas automatiquement dans la banque suivante.
Valeur renvoyée
Aucune valeur de retour. Le dessin et les attentes bloquantes ont lieu avant le retour.
Conditions et limites
Utilisez un rectangle BG valide et chargez d’abord les tuiles de police et de cadre. La zone logicielle utilise la carte BG choisie par le bit 3 de LCDC, sans activer la couche Window matérielle. Sur CGB, utilisez VBK 0 pour les numéros et réglez les couleurs séparément. Les exemples fournissent la police mappée en ASCII et les tuiles de cadre, curseur et indicateur de page. Dialogues et choix utilisent des ID de tuile d’un octet, sans décodage UTF-8. Pour d’autres caractères, fournissez leurs glyphes et encodez le texte avec ces ID, en réservant les octets de contrôle du dialogue.
Octets de contrôle : 0x00 termine le flux ; 0x0A passe à la ligne intérieure suivante ; 0x01 consomme l’octet suivant comme nombre d’attentes VBlank, y compris zéro ; 0x02 attend un changement de page, vide l’intérieur et réinitialise le curseur. Les autres octets sont des ID de tuile. Un opérande WAIT nul n’est pas un marqueur END.
Dépasser la dernière ligne intérieure par saut ou renvoi automatique affiche le repère de page, attend A, B ou START, vide l’intérieur puis reprend à la première case. La page est remplacée, pas défilée. Un 0x02 explicite attend sans ajouter de repère. Le test de page débute sans bouton mémorisé : un bouton déjà tenu au début peut donc faire avancer la page.
Les caractères ordinaires sont ignorés si la zone est fermée ou sans intérieur utilisable. Les contrôles restent interprétés : WAIT peut bloquer et les commandes de page peuvent attendre ou effacer la zone mémorisée. text_print sur une zone fermée n’est donc pas systématiquement sans effet.
Ces fonctions sont bloquantes : pendant l’attente, elles n’appellent ni mise à jour du jeu, ni service musical, ni boucle de rendu. LCD éteint, __wait_vblank revient immédiatement ; vitesse des caractères et WAIT ne créent donc pas de délais en trames. Gardez le LCD actif pour le dialogue temporisé et les entrées cadencées par trame. Utilisez une machine à états côté jeu si d’autres tâches doivent avancer pendant la conversation.
Les écritures de tuiles sûres sous-jacentes attendent un mode LCD accessible et encadrent l’écriture par DI/EI. Elles peuvent activer les interruptions au lieu de préserver un état initialement désactivé. Ne les appelez pas depuis un gestionnaire d’interruption et ne comptez pas sur elles pour préserver cet état.
Chaque exemple complet inclut text.c une fois. Compilez avec les répertoires d’inclusion de la bibliothèque et des exemples du manuel ; n’ajoutez pas aussi lib/text.c comme source séparée. L’exemple de flux distant utilise MBC5 et une ROM de 64 Kio pour contenir les données de banque 2.
Exemple d’utilisation
text_print_far(2,dialogue_far);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple lit le saut de ligne et BANK 2 en banque ROM 2. BANK RESTORED affiche 161 après lecture du repère dans la banque 1 de l’appelant. La ligne BANK 2 commence en (2,5) ; le nombre de restauration apparaît en (16,14).
Les tests sur émulateur comparent tout le contenu BG et les quatre images d’exemple. D’autres exécutions couvrent ouverture/fermeture, flux ordinaires et bancarisés, temporisations, pages explicites et automatiques, avances A/B/START, boutons tenus, choix circulaires, listes vides et priorités simultanées. Des points de contrôle avant et après l’entrée scriptée vérifient le blocage réel des pages. Matériel physique et concurrence des interruptions ne sont pas testés.


Commande de compilation
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-disasmImplémentation et source
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
Affiche une valeur signée sur 16 bits en décimal. Une valeur négative commence par la tuile du signe moins, suivie de sa valeur absolue ; zéro et les valeurs positives n’ont pas de signe. La sortie la plus longue, -32768, occupe six cases.
Syntaxe
void text_print_s16(u8 x, u8 y, s16 value);Paramètres
xColonne de départ, en cases de 8×8 de la carte du fond. Toute la sortie doit tenir dans les colonnes 0–31. Sans défilement du fond, les colonnes visibles sont 0–19.
yLigne de départ, de 0 à 31, en cases de 8×8 de la carte du fond. Sans défilement, les lignes 0–17 sont visibles. Un rectangle doit aussi tenir verticalement dans la carte.
valueValeur signée de −32768 à 32767. L’exemple convertit explicitement le motif de 16 bits 32768 (0x8000) en s16 pour afficher −32768.
Valeur renvoyée
Aucune valeur de retour. La fonction écrit les cases de la carte avant de rendre la main ; elle ne renvoie ni nombre de caractères ni code d’état.
Conditions et limites
Ces fonctions écrivent dans la carte BG sélectionnée par le bit 3 de LCDC. La fenêtre de texte est une zone logicielle sur cette carte, et non le plan Window matériel. Gardez VBK à 0 sur CGB pour écrire les numéros de tuiles ; ces appels ne règlent ni attributs de couleur, ni palettes, ni défilement.
Chargez la police et les graphismes du cadre avant de dessiner. Les ID de cadre par défaut vont de 1 à 6, la tuile de remplissage vaut 0 et les chiffres commencent à ASCII 0 (tuile 48). Le signe moins utilise ASCII - (tuile 45). L’exemple fournit six tuiles de cadre et la police du manuel, dont les ID de glyphes correspondent à l’ASCII.
Gardez rectangles et texte dans la carte de 32×32. Le remplissage ne réduit pas la largeur ou la hauteur aux limites de la carte. Une largeur ou une hauteur nulle ne remplit rien ; text_window enregistre néanmoins une zone ouverte, sans intérieur utilisable.
Les fonctions numériques publiques utilisent exactement la largeur du nouveau nombre. Elles n’effacent pas les cases restantes à droite. Écrire 7 sur 12345 au même endroit affiche 72345. Pour n’obtenir que 7, effacez d’abord le champ réservé de cinq cases avec text_clear_rect. Réservez six cases pour un entier signé sur 16 bits.
Les intrinsèques d’écriture vérifient l’état du LCD : éteint, elles écrivent immédiatement ; allumé, elles attendent un mode autorisant l’écriture et encadrent celle-ci par DI/EI. Ce chemin peut réactiver les interruptions au retour ; ne supposez donc pas qu’il préserve leur désactivation. Ici, les exemples et tests octet par octet écrivent avec le LCD éteint.
L’exemple complet inclut text.c une seule fois pour compiler l’implémentation avec le programme. Ne passez pas également lib/text.c comme entrée séparée. Pour personnaliser les constantes de tuiles TEXT_*, définissez-les avant d’inclure rpg.h et l’implémentation ; utilisez les mêmes définitions partout où la bibliothèque est compilée.
Exemple d’utilisation
text_print_s16(11,12,(s16)32768);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
La ligne S16 affiche -32768 à partir de (11,12), sur six cases signe moins compris, en vert sur CGB. Elle teste la plus petite valeur signée sur 16 bits, dont la valeur absolue positive ne tient pas dans s16.
La vérification compare chaque pixel visible et les 1024 octets de la carte BG dans les deux écrans d’exemple. Des ROM DMG/CGB distinctes testent les 256 valeurs d’octet non signé, les changements de nombre de chiffres et les extrêmes signés, en conservant des points sentinelles à côté de chaque nombre. Les contrôles de placement couvrent les rectangles vides ou étroits, les bords de carte, les octets de tuiles dont la valeur correspond à un code de contrôle et le curseur de fenêtre après des écritures absolues. Il s’agit de tests sur émulateur, pas sur matériel physique.


Commande de compilation
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-disasmImplémentation et source
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
Affiche une valeur non signée sur 16 bits en décimal à partir de la position de tuile indiquée. La sortie occupe une à cinq cases, sans zéro initial. Utilisez-la pour un score ou un nombre d’objets pouvant dépasser 255.
Syntaxe
void text_print_u16(u8 x, u8 y, u16 value);Paramètres
xColonne de départ, en cases de 8×8 de la carte du fond. Toute la sortie doit tenir dans les colonnes 0–31. Sans défilement du fond, les colonnes visibles sont 0–19.
yLigne de départ, de 0 à 31, en cases de 8×8 de la carte du fond. Sans défilement, les lignes 0–17 sont visibles. Un rectangle doit aussi tenir verticalement dans la carte.
valueValeur non signée de 0 à 65535.
Valeur renvoyée
Aucune valeur de retour. La fonction écrit les cases de la carte avant de rendre la main ; elle ne renvoie ni nombre de caractères ni code d’état.
Conditions et limites
Ces fonctions écrivent dans la carte BG sélectionnée par le bit 3 de LCDC. La fenêtre de texte est une zone logicielle sur cette carte, et non le plan Window matériel. Gardez VBK à 0 sur CGB pour écrire les numéros de tuiles ; ces appels ne règlent ni attributs de couleur, ni palettes, ni défilement.
Chargez la police et les graphismes du cadre avant de dessiner. Les ID de cadre par défaut vont de 1 à 6, la tuile de remplissage vaut 0 et les chiffres commencent à ASCII 0 (tuile 48). Le signe moins utilise ASCII - (tuile 45). L’exemple fournit six tuiles de cadre et la police du manuel, dont les ID de glyphes correspondent à l’ASCII.
Gardez rectangles et texte dans la carte de 32×32. Le remplissage ne réduit pas la largeur ou la hauteur aux limites de la carte. Une largeur ou une hauteur nulle ne remplit rien ; text_window enregistre néanmoins une zone ouverte, sans intérieur utilisable.
Les fonctions numériques publiques utilisent exactement la largeur du nouveau nombre. Elles n’effacent pas les cases restantes à droite. Écrire 7 sur 12345 au même endroit affiche 72345. Pour n’obtenir que 7, effacez d’abord le champ réservé de cinq cases avec text_clear_rect. Réservez six cases pour un entier signé sur 16 bits.
Les intrinsèques d’écriture vérifient l’état du LCD : éteint, elles écrivent immédiatement ; allumé, elles attendent un mode autorisant l’écriture et encadrent celle-ci par DI/EI. Ce chemin peut réactiver les interruptions au retour ; ne supposez donc pas qu’il préserve leur désactivation. Ici, les exemples et tests octet par octet écrivent avec le LCD éteint.
L’exemple complet inclut text.c une seule fois pour compiler l’implémentation avec le programme. Ne passez pas également lib/text.c comme entrée séparée. Pour personnaliser les constantes de tuiles TEXT_*, définissez-les avant d’inclure rpg.h et l’implémentation ; utilisez les mêmes définitions partout où la bibliothèque est compilée.
Exemple d’utilisation
text_print_u16(11,10,65535);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
La ligne U16 affiche 65535 en (11,10), sur cinq cases, en bleu sur CGB. OVERWRITE affiche 72345 après l’écriture de 7 sur 12345 sans effacement préalable du champ de cinq cases.
La vérification compare chaque pixel visible et les 1024 octets de la carte BG dans les deux écrans d’exemple. Des ROM DMG/CGB distinctes testent les 256 valeurs d’octet non signé, les changements de nombre de chiffres et les extrêmes signés, en conservant des points sentinelles à côté de chaque nombre. Les contrôles de placement couvrent les rectangles vides ou étroits, les bords de carte, les octets de tuiles dont la valeur correspond à un code de contrôle et le curseur de fenêtre après des écritures absolues. Il s’agit de tests sur émulateur, pas sur matériel physique.


Commande de compilation
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-disasmImplémentation et source
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
Affiche une valeur non signée sur 8 bits en décimal à partir de la position de tuile indiquée. Elle occupe une à trois cases, sans zéro initial ; zéro occupe une case. Convient aux petits compteurs, comme les vies ou les munitions.
Syntaxe
void text_print_u8(u8 x, u8 y, u8 value);Paramètres
xColonne de départ, en cases de 8×8 de la carte du fond. Toute la sortie doit tenir dans les colonnes 0–31. Sans défilement du fond, les colonnes visibles sont 0–19.
yLigne de départ, de 0 à 31, en cases de 8×8 de la carte du fond. Sans défilement, les lignes 0–17 sont visibles. Un rectangle doit aussi tenir verticalement dans la carte.
valueValeur non signée de 0 à 255. Les expressions de type plus large sont converties en u8 par le paramètre de la fonction.
Valeur renvoyée
Aucune valeur de retour. La fonction écrit les cases de la carte avant de rendre la main ; elle ne renvoie ni nombre de caractères ni code d’état.
Conditions et limites
Ces fonctions écrivent dans la carte BG sélectionnée par le bit 3 de LCDC. La fenêtre de texte est une zone logicielle sur cette carte, et non le plan Window matériel. Gardez VBK à 0 sur CGB pour écrire les numéros de tuiles ; ces appels ne règlent ni attributs de couleur, ni palettes, ni défilement.
Chargez la police et les graphismes du cadre avant de dessiner. Les ID de cadre par défaut vont de 1 à 6, la tuile de remplissage vaut 0 et les chiffres commencent à ASCII 0 (tuile 48). Le signe moins utilise ASCII - (tuile 45). L’exemple fournit six tuiles de cadre et la police du manuel, dont les ID de glyphes correspondent à l’ASCII.
Gardez rectangles et texte dans la carte de 32×32. Le remplissage ne réduit pas la largeur ou la hauteur aux limites de la carte. Une largeur ou une hauteur nulle ne remplit rien ; text_window enregistre néanmoins une zone ouverte, sans intérieur utilisable.
Les fonctions numériques publiques utilisent exactement la largeur du nouveau nombre. Elles n’effacent pas les cases restantes à droite. Écrire 7 sur 12345 au même endroit affiche 72345. Pour n’obtenir que 7, effacez d’abord le champ réservé de cinq cases avec text_clear_rect. Réservez six cases pour un entier signé sur 16 bits.
Les intrinsèques d’écriture vérifient l’état du LCD : éteint, elles écrivent immédiatement ; allumé, elles attendent un mode autorisant l’écriture et encadrent celle-ci par DI/EI. Ce chemin peut réactiver les interruptions au retour ; ne supposez donc pas qu’il préserve leur désactivation. Ici, les exemples et tests octet par octet écrivent avec le LCD éteint.
L’exemple complet inclut text.c une seule fois pour compiler l’implémentation avec le programme. Ne passez pas également lib/text.c comme entrée séparée. Pour personnaliser les constantes de tuiles TEXT_*, définissez-les avant d’inclure rpg.h et l’implémentation ; utilisez les mêmes définitions partout où la bibliothèque est compilée.
Exemple d’utilisation
text_print_u8(11,8,255);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
La ligne U8 affiche 255 à partir de (11,8), sur exactement trois cases, en bleu sur CGB. Les lignes OVERWRITE et CLEAN montrent pourquoi il faut effacer explicitement le champ lorsqu’on remplace un nombre par un autre plus court.
La vérification compare chaque pixel visible et les 1024 octets de la carte BG dans les deux écrans d’exemple. Des ROM DMG/CGB distinctes testent les 256 valeurs d’octet non signé, les changements de nombre de chiffres et les extrêmes signés, en conservant des points sentinelles à côté de chaque nombre. Les contrôles de placement couvrent les rectangles vides ou étroits, les bords de carte, les octets de tuiles dont la valeur correspond à un code de contrôle et le curseur de fenêtre après des écritures absolues. Il s’agit de tests sur émulateur, pas sur matériel physique.


Commande de compilation
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-disasmImplémentation et source
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
Dessine horizontalement une suite de numéros de tuiles terminée par zéro, à partir d’une position absolue sur la carte du fond. Ce chemin n’applique ni découpage à la fenêtre, ni retour automatique à la ligne, ni interprétation des codes de contrôle, ni délai entre caractères. Le curseur de text_print ne bouge pas.
Syntaxe
void text_print_xy(u8 x, u8 y, const u8* str);Paramètres
xColonne de départ, en cases de 8×8 de la carte du fond. Toute la sortie doit tenir dans les colonnes 0–31. Sans défilement du fond, les colonnes visibles sont 0–19.
yLigne de départ, de 0 à 31, en cases de 8×8 de la carte du fond. Sans défilement, les lignes 0–17 sont visibles. Un rectangle doit aussi tenir verticalement dans la carte.
strPointeur lisible vers des octets de tuiles terminés par 0. Chaque octet sert directement de numéro de tuile. Une chaîne ASCII ne s’affiche comme du texte que si les glyphes correspondants occupent les bons ID de tuiles. La source doit rester mappée et lisible jusqu’au retour. Ces fonctions ne décodent pas l’UTF-8 et ne chargent pas de glyphes. Un texte multioctet nécessite au préalable un encodage défini par le jeu et les tuiles correspondantes.
Valeur renvoyée
Aucune valeur de retour. La fonction écrit les cases de la carte avant de rendre la main ; elle ne renvoie ni nombre de caractères ni code d’état.
Conditions et limites
Ces fonctions écrivent dans la carte BG sélectionnée par le bit 3 de LCDC. La fenêtre de texte est une zone logicielle sur cette carte, et non le plan Window matériel. Gardez VBK à 0 sur CGB pour écrire les numéros de tuiles ; ces appels ne règlent ni attributs de couleur, ni palettes, ni défilement.
Chargez la police et les graphismes du cadre avant de dessiner. Les ID de cadre par défaut vont de 1 à 6, la tuile de remplissage vaut 0 et les chiffres commencent à ASCII 0 (tuile 48). Le signe moins utilise ASCII - (tuile 45). L’exemple fournit six tuiles de cadre et la police du manuel, dont les ID de glyphes correspondent à l’ASCII.
Gardez rectangles et texte dans la carte de 32×32. Le remplissage ne réduit pas la largeur ou la hauteur aux limites de la carte. Une largeur ou une hauteur nulle ne remplit rien ; text_window enregistre néanmoins une zone ouverte, sans intérieur utilisable.
Les intrinsèques d’écriture vérifient l’état du LCD : éteint, elles écrivent immédiatement ; allumé, elles attendent un mode autorisant l’écriture et encadrent celle-ci par DI/EI. Ce chemin peut réactiver les interruptions au retour ; ne supposez donc pas qu’il préserve leur désactivation. Ici, les exemples et tests octet par octet écrivent avec le LCD éteint.
L’exemple complet inclut text.c une seule fois pour compiler l’implémentation avec le programme. Ne passez pas également lib/text.c comme entrée séparée. Pour personnaliser les constantes de tuiles TEXT_*, définissez-les avant d’inclure rpg.h et l’implémentation ; utilisez les mêmes définitions partout où la bibliothèque est compilée.
Exemple d’utilisation
text_print_xy(2,3,"HELLO!");Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
HELLO! commence à la tuile (2,3), soit au pixel (16,24), dans le cadre rouge sur CGB. La position est absolue sur la carte BG : ouvrir la zone de texte n’ajoute aucun décalage à x ou y.
La vérification compare chaque pixel visible et les 1024 octets de la carte BG dans les deux écrans d’exemple. Des ROM DMG/CGB distinctes testent les 256 valeurs d’octet non signé, les changements de nombre de chiffres et les extrêmes signés, en conservant des points sentinelles à côté de chaque nombre. Les contrôles de placement couvrent les rectangles vides ou étroits, les bords de carte, les octets de tuiles dont la valeur correspond à un code de contrôle et le curseur de fenêtre après des écritures absolues. Il s’agit de tests sur émulateur, pas sur matériel physique.


Commande de compilation
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-disasmImplémentation et source
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
Définit le nombre d’attentes VBlank après chaque caractère ordinaire écrit par text_print ou text_print_far. Zéro supprime ces attentes par caractère. Ouvrir ou fermer une zone ne réinitialise pas ce réglage. Les commandes WAIT explicites attendent même si la vitesse des caractères vaut zéro.
Syntaxe
void text_set_speed(u8 speed);Paramètres
speedNombre d’attentes VBlank après chaque caractère, de 0 à 255. C’est un nombre d’attentes, pas des millisecondes. Ce réglage n’affecte ni text_print_xy, ni les fonctions numériques, ni la liste de choix.
Valeur renvoyée
Aucune valeur de retour. Le dessin et les attentes bloquantes ont lieu avant le retour.
Conditions et limites
Utilisez un rectangle BG valide et chargez d’abord les tuiles de police et de cadre. La zone logicielle utilise la carte BG choisie par le bit 3 de LCDC, sans activer la couche Window matérielle. Sur CGB, utilisez VBK 0 pour les numéros et réglez les couleurs séparément. Les exemples fournissent la police mappée en ASCII et les tuiles de cadre, curseur et indicateur de page. Dialogues et choix utilisent des ID de tuile d’un octet, sans décodage UTF-8. Pour d’autres caractères, fournissez leurs glyphes et encodez le texte avec ces ID, en réservant les octets de contrôle du dialogue.
Ces fonctions sont bloquantes : pendant l’attente, elles n’appellent ni mise à jour du jeu, ni service musical, ni boucle de rendu. LCD éteint, __wait_vblank revient immédiatement ; vitesse des caractères et WAIT ne créent donc pas de délais en trames. Gardez le LCD actif pour le dialogue temporisé et les entrées cadencées par trame. Utilisez une machine à états côté jeu si d’autres tâches doivent avancer pendant la conversation.
Les écritures de tuiles sûres sous-jacentes attendent un mode LCD accessible et encadrent l’écriture par DI/EI. Elles peuvent activer les interruptions au lieu de préserver un état initialement désactivé. Ne les appelez pas depuis un gestionnaire d’interruption et ne comptez pas sur elles pour préserver cet état.
Chaque exemple complet inclut text.c une fois. Compilez avec les répertoires d’inclusion de la bibliothèque et des exemples du manuel ; n’ajoutez pas aussi lib/text.c comme source séparée. L’exemple de flux distant utilise MBC5 et une ROM de 64 Kio pour contenir les données de banque 2.
Exemple d’utilisation
text_set_speed(2);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple de flux utilise la vitesse 2 pour les dialogues ordinaires et bancarisés, avec un opérande WAIT de 12. L’image finale montre le texte après ces attentes ; une trace de trames distincte vérifie vitesse 3, cinq attentes explicites et quatre attentes zone fermée. La capture finale seule ne valide pas le timing.
Les tests sur émulateur comparent tout le contenu BG et les quatre images d’exemple. D’autres exécutions couvrent ouverture/fermeture, flux ordinaires et bancarisés, temporisations, pages explicites et automatiques, avances A/B/START, boutons tenus, choix circulaires, listes vides et priorités simultanées. Des points de contrôle avant et après l’entrée scriptée vérifient le blocage réel des pages. Matériel physique et concurrence des interruptions ne sont pas testés.


Commande de compilation
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-disasmImplémentation et source
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
Dessine une zone de texte encadrée sur la carte de tuiles du fond et en fait la zone active pour l’écriture dans une fenêtre. Cet alias de text_open ramène le curseur à la première case intérieure, redessine le cadre et efface l’intérieur. Le délai actuel entre caractères est conservé.
Syntaxe
void text_window(u8 x, u8 y, u8 w, u8 h);Paramètres
xColonne de départ, en cases de 8×8 de la carte du fond. Toute la sortie doit tenir dans les colonnes 0–31. Sans défilement du fond, les colonnes visibles sont 0–19.
yLigne de départ, de 0 à 31, en cases de 8×8 de la carte du fond. Sans défilement, les lignes 0–17 sont visibles. Un rectangle doit aussi tenir verticalement dans la carte.
wLargeur en cases. Pour text_window, elle comprend les deux colonnes du cadre, laissant max(w−2, 0) colonnes intérieures. Pour text_clear_rect, c’est le nombre de cases à remplir sur chaque ligne.
hHauteur en cases. Pour text_window, elle comprend les bords supérieur et inférieur, laissant max(h−2, 0) lignes intérieures. Pour text_clear_rect, c’est le nombre de lignes à remplir.
Valeur renvoyée
Aucune valeur de retour. La fonction écrit les cases de la carte avant de rendre la main ; elle ne renvoie ni nombre de caractères ni code d’état.
Conditions et limites
Ces fonctions écrivent dans la carte BG sélectionnée par le bit 3 de LCDC. La fenêtre de texte est une zone logicielle sur cette carte, et non le plan Window matériel. Gardez VBK à 0 sur CGB pour écrire les numéros de tuiles ; ces appels ne règlent ni attributs de couleur, ni palettes, ni défilement.
Chargez la police et les graphismes du cadre avant de dessiner. Les ID de cadre par défaut vont de 1 à 6, la tuile de remplissage vaut 0 et les chiffres commencent à ASCII 0 (tuile 48). Le signe moins utilise ASCII - (tuile 45). L’exemple fournit six tuiles de cadre et la police du manuel, dont les ID de glyphes correspondent à l’ASCII.
Gardez rectangles et texte dans la carte de 32×32. Le remplissage ne réduit pas la largeur ou la hauteur aux limites de la carte. Une largeur ou une hauteur nulle ne remplit rien ; text_window enregistre néanmoins une zone ouverte, sans intérieur utilisable.
Les intrinsèques d’écriture vérifient l’état du LCD : éteint, elles écrivent immédiatement ; allumé, elles attendent un mode autorisant l’écriture et encadrent celle-ci par DI/EI. Ce chemin peut réactiver les interruptions au retour ; ne supposez donc pas qu’il préserve leur désactivation. Ici, les exemples et tests octet par octet écrivent avec le LCD éteint.
L’exemple complet inclut text.c une seule fois pour compiler l’implémentation avec le programme. Ne passez pas également lib/text.c comme entrée séparée. Pour personnaliser les constantes de tuiles TEXT_*, définissez-les avant d’inclure rpg.h et l’implémentation ; utilisez les mêmes définitions partout où la bibliothèque est compilée.
Exemple d’utilisation
text_window(1,2,18,5);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple ouvre une zone de 18×5 cases en (1,2), avec un intérieur de 16×3. Le cadre fourni a des traits d’un pixel ; ses lignes extérieures visibles s’étendent de x=11 à 147 et de y=19 à 51 pixels. Il est rouge sur CGB et noir sur DMG.
La vérification compare chaque pixel visible et les 1024 octets de la carte BG dans les deux écrans d’exemple. Des ROM DMG/CGB distinctes testent les 256 valeurs d’octet non signé, les changements de nombre de chiffres et les extrêmes signés, en conservant des points sentinelles à côté de chaque nombre. Les contrôles de placement couvrent les rectangles vides ou étroits, les bords de carte, les octets de tuiles dont la valeur correspond à un code de contrôle et le curseur de fenêtre après des écritures absolues. Il s’agit de tests sur émulateur, pas sur matériel physique.


Commande de compilation
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-disasmImplémentation et source
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
Marque les cases dont la distance de Manhattan est comprise entre atk_min et atk_max, bornes incluses.
Syntaxe
u8 unit_attack_range(unit_t* u, u8* out_mask);Paramètres
uunit_t valide : position en cases, move en pas, intervalle atk_min/atk_max inclusif, ainsi que hp et acted pour déterminer si l’action est possible.
out_maskwidth*height octets accessibles en écriture ; reçoit zéro ou un par case.
Valeur renvoyée
Renvoie 1 si la carte est disponible, 0 si ses dimensions sont nulles.
Conditions et limites
Les coordonnées désignent les cases de la carte active : 8×8 pixels pour les tuiles ordinaires, 16×16 pour les métatuiles.
Ignore les obstacles, la ligne de vue et les unités alliées. Limitez les distances évaluées à 255. Si la portée minimale dépasse la maximale, toutes les cases valent zéro.
Exemple d’utilisation
result[46]=unit_attack_range(&hero,mask);result[47]=mask[12];result[48]=mask[14];Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
La grille de gauche montre les coûts de déplacement en trois pas au plus ; celle de droite, un plus court chemin de S à G. Des astérisques verts tracent neuf pas autour d’un mur rouge de trois cases ; les chiffres bleus donnent les coûts. Le DMG utilise la même disposition en noir. Les contrôles RAM montrent aussi que le masque d’attaque ignore les murs.


Commande de compilation
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=noneImplémentation et source
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
Vérifie qu’une unité a encore des PV et n’a pas agi.
Syntaxe
u8 unit_can_act(const unit_t* u);Paramètres
uunit_t valide : position en cases, move en pas, intervalle atk_min/atk_max inclusif, ainsi que hp et acted pour déterminer si l’action est possible.
Valeur renvoyée
Renvoie 1 si hp est non nul et acted vaut zéro, sinon 0. Ne modifie pas l’unité.
Exemple d’utilisation
result[11]=unit_can_act(&hero);hero.acted=1;result[12]=unit_can_act(&hero);hero.acted=0;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
La grille de gauche montre les coûts de déplacement en trois pas au plus ; celle de droite, un plus court chemin de S à G. Des astérisques verts tracent neuf pas autour d’un mur rouge de trois cases ; les chiffres bleus donnent les coûts. Le DMG utilise la même disposition en noir. Les contrôles RAM montrent aussi que le masque d’attaque ignore les murs.


Commande de compilation
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=noneImplémentation et source
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
Construit le masque des cases atteignables dans la limite de déplacement de l’unité.
Syntaxe
u8 unit_move_range(unit_t* u, u8* out_mask);Paramètres
uunit_t valide : position en cases, move en pas, intervalle atk_min/atk_max inclusif, ainsi que hp et acted pour déterminer si l’action est possible.
out_maskwidth*height octets accessibles en écriture ; reçoit zéro ou un par case.
Valeur renvoyée
Renvoie 1 si la carte est disponible, 0 si ses dimensions sont nulles. L’origine de l’unité doit être dans les limites.
Conditions et limites
Les coordonnées désignent les cases de la carte active : 8×8 pixels pour les tuiles ordinaires, 16×16 pour les métatuiles.
La recherche utilise environ 4 Kio d’espace de travail partagé non réentrant. Limitez les cartes à 1024 cases et les distances explorées à 254. La distance 0xFF signifie « non atteint » : un trajet de 255 pas n’est donc pas représentable. Les sorties de coût et de masque nécessitent width*height octets accessibles en écriture.
L’origine est marquée comme atteignable même si elle est bloquée. Les PV, acted et les autres unités n’influencent pas le masque de déplacement.
Exemple d’utilisation
result[43]=unit_move_range(&hero,mask);result[44]=mask[12];result[45]=mask[14];Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
La grille de gauche montre les coûts de déplacement en trois pas au plus ; celle de droite, un plus court chemin de S à G. Des astérisques verts tracent neuf pas autour d’un mur rouge de trois cases ; les chiffres bleus donnent les coûts. Le DMG utilise la même disposition en noir. Les contrôles RAM montrent aussi que le masque d’attaque ignore les murs.


Commande de compilation
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=noneImplémentation et source
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
Choisit un indice dans une liste de poids relatifs sur un octet. La fonction additionne les poids, réduit un tirage rng16 modulo ce total, puis trouve le premier intervalle cumulé contenant le résultat. Avec [1, 3, 6], les indices 0, 1 et 2 possèdent les intervalles 0, 1–3 et 4–9.
Syntaxe
u8 weighted_choice(const u8* weights, u8 count);Paramètres
weightsPointeur vers count poids u8 lisibles. Le tableau n’est pas modifié. Les poids nuls sont ignorés si le total est positif. Avec count == 0, le pointeur n’est pas lu et peut être nul ; sinon, fournissez un tableau valide.
countNombre de poids, de 0 à 255. Au maximum, 255 poids de 255 totalisent 65025, ce qui tient dans l’accumulateur u16. La fonction parcourt d’abord la liste pour sommer les poids, puis la reparcourt jusqu’à l’intervalle choisi.
Valeur renvoyée
Si le total est positif, un indice de 0 à count−1 après deux tirages d’octet. Si count ou tous les poids sont nuls, renvoie zéro sans tirage. Ce repli est indiscernable d’une sélection valide de l’indice 0 ; vérifiez donc vous-même les listes vides ou entièrement nulles si cette distinction importe.
Conditions et limites
Les poids définissent des tailles d’intervalles relatives, pas des pourcentages observés garantis. La distribution de rng16 et la réduction modulo le total influencent toutes deux les fréquences réelles. Un total positif consomme toujours deux tirages d’octet, même si un seul élément a un poids non nul.
Ces appels partagent un état persistant. La reproduction exige la même cible, la même graine et le même ordre d’appels, y compris ceux des autres fonctions auxiliaires. Gardez réglage de graine et tirages dans un même contexte d’exécution ; ces vérifications ne prouvent pas la sûreté d’un accès concurrent depuis une interruption.
GB et FC utilisent des algorithmes différents et ne garantissent pas la même suite avec la même graine. Ce sont des générateurs déterministes pour le jeu, pas des sources d’aléa cryptographique. Les tests vérifient le comportement de l’implémentation, pas sa qualité statistique ni sa période.
Incluez rpg.h et compilez lib/rng.c avec le jeu pour utiliser les fonctions de bibliothèque. Les intrinsèques __rng_seed et __rng8 sont émises par le compilateur ; un programme limité à ces deux fonctions n’a pas besoin d’objet rng.c.
Exemple d’utilisation
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.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple donne les poids 1, 3 et 6 à trois éléments. Le mot 546 issu de la graine donne un reste de 6, dans l’intervalle 4–9 de l’indice 2 ; WEIGHT INDEX affiche 00002. EMPTY LIST affiche 00000 comme valeur de repli d’une liste vide, pas comme sélection réussie de l’élément 0.
Le programme complet affiche les résultats décimaux sur fond blanc : texte noir sur DMG, bleu sur CGB. FAILED doit indiquer 00000. Les images montrent la sortie réelle de cet exemple dans l’émulateur.
La validation a comparé, pour chaque cas, 32 sorties et huit tirages d’octet suivants à un modèle hôte indépendant : 93 cas GB et 18 cas FC, avec graines constantes ou calculées à l’exécution et limites GB de plage, chance et poids. Les écrans pédagogiques ont été contrôlés après 240 images émulées. Le matériel réel et la qualité statistique n’ont pas été testés.


Commande de compilation
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-disasmImplémentation et source
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 — Enregistrement, changement et mise à jour des scènes
Appelle les gestionnaires enter, update, draw et exit d’une table de scènes pour passer entre des écrans tels que le titre et la partie.
scene_change
Quitte la scène active, s’il y en a une, puis entre dans la scène demandée.
Syntaxe
void scene_change(u8 scene_id);Paramètres
scene_idIndice de la scène à activer, de 0 à count−1.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Les identifiants hors limites sont ignorés. Une transition valide exécute exit, enregistre le nouvel identifiant et le drapeau de transition, puis exécute enter. Choisir le même identifiant exécute tout de même exit et enter. La table de scènes appartient à l’appelant. Gardez cette table et les cibles de ses pointeurs de fonction ordinaires valides pendant toute son utilisation. Les fonctions de rappel nulles sont ignorées. Ne déclenchez pas de transition récursive et ne remplacez pas la table depuis les fonctions de rappel enter ou exit.
Compilez cet exemple complet avec l’ABI Legacy par défaut. Ses rappels utilisent des appels par pointeur de fonction, non pris en charge et refusés par le compilateur avec --abi=stack. La même restriction s’applique aux alias.
Exemple d’utilisation
scene_change(0);scene_change(9);result[11]=events;result[12]=scene_was_changed();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le programme active la scène 0, ignore l’identifiant invalide 9, effectue la transition 0→1 puis une nouvelle entrée 1→1, et vérifie l’ordre des fonctions de rappel.


Commande de compilation
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=64kImplémentation et source
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
Appelle une fois la fonction de rappel draw de la scène active.
Syntaxe
void scene_draw();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Sans scène active ou avec une fonction de rappel draw nulle, cet appel est sans effet. Il n’efface pas le drapeau de transition. Organisez les transferts d’affichage et la synchronisation des trames dans la fonction de rappel ou dans la boucle de jeu qui l’entoure. La table de scènes appartient à l’appelant. Gardez cette table et les cibles de ses pointeurs de fonction ordinaires valides pendant toute son utilisation. Les fonctions de rappel nulles sont ignorées. Ne déclenchez pas de transition récursive et ne remplacez pas la table depuis les fonctions de rappel enter ou exit.
Compilez cet exemple complet avec l’ABI Legacy par défaut. Ses rappels utilisent des appels par pointeur de fonction, non pris en charge et refusés par le compilateur avec --abi=stack. La même restriction s’applique aux alias.
Exemple d’utilisation
scene_draw();result[15]=events;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
La séquence contient l’événement 12 produit par draw dans la scène 0 et l’événement 22 produit par draw dans la scène 1.


Commande de compilation
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=64kImplémentation et source
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
Lit l’identifiant de scène courant enregistré.
Syntaxe
u8 scene_get_current();Valeur renvoyée
Renvoie l’identifiant enregistré sur huit bits ; l’initialisation le met également à zéro.
Conditions et limites
Une valeur de retour de zéro ne suffit pas à prouver que la scène 0 est active. Suivez séparément si le premier appel à scene_change() a eu lieu après l’initialisation.
Compilez cet exemple complet avec l’ABI Legacy par défaut. Ses rappels utilisent des appels par pointeur de fonction, non pris en charge et refusés par le compilateur avec --abi=stack. La même restriction s’applique aux alias.
Exemple d’utilisation
result[16]=scene_get_current();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple lit zéro après l’activation de la scène 0, puis un après le passage à la scène 1.


Commande de compilation
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=64kImplémentation et source
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
Enregistre une table de scènes sans en activer aucune.
Syntaxe
void scene_init(const SceneDef* scenes, u8 count);Paramètres
scenesTableau d’entrées
SceneDefcontenant les fonctions de rappel enter, update, draw et exit.countNombre d’entrées ; zéro signifie qu’aucun identifiant de scène n’est valide.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Remet l’identifiant enregistré et le drapeau de transition à zéro. N’appelle pas enter ; utilisez scene_change() pour activer une scène. La table de scènes appartient à l’appelant. Gardez cette table et les cibles de ses pointeurs de fonction ordinaires valides pendant toute son utilisation. Les fonctions de rappel nulles sont ignorées. Ne déclenchez pas de transition récursive et ne remplacez pas la table depuis les fonctions de rappel enter ou exit.
Compilez cet exemple complet avec l’ABI Legacy par défaut. Ses rappels utilisent des appels par pointeur de fonction, non pris en charge et refusés par le compilateur avec --abi=stack. La même restriction s’applique aux alias.
Exemple d’utilisation
scene_init(scenes,2);scene_update();scene_draw();result[9]=events;result[10]=scene_was_changed();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple enregistre deux scènes et vérifie que les appels à update et draw avant activation ne produisent aucun événement.


Commande de compilation
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=64kImplémentation et source
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
Remplace la table de scènes et désactive toute scène active.
Syntaxe
void scene_set_table(const SceneDef* scenes, u8 count);Paramètres
scenesTableau d’entrées
SceneDefcontenant les fonctions de rappel enter, update, draw et exit.countNombre d’entrées ; zéro signifie qu’aucun identifiant de scène n’est valide.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Réinitialise l’état comme scene_init(), sans appeler ni l’ancienne fonction de rappel exit ni une nouvelle fonction de rappel enter. La table de scènes appartient à l’appelant. Gardez cette table et les cibles de ses pointeurs de fonction ordinaires valides pendant toute son utilisation. Les fonctions de rappel nulles sont ignorées. Ne déclenchez pas de transition récursive et ne remplacez pas la table depuis les fonctions de rappel enter ou exit.
Compilez cet exemple complet avec l’ABI Legacy par défaut. Ses rappels utilisent des appels par pointeur de fonction, non pris en charge et refusés par le compilateur avec --abi=stack. La même restriction s’applique aux alias.
Exemple d’utilisation
scene_set_table(scenes,2);result[23]=events;result[24]=scene_was_changed();scene_draw();result[25]=events;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le remplacement de la table après neuf événements laisse le compteur à neuf, remet le drapeau de transition à zéro et rend l’appel suivant à draw sans effet.


Commande de compilation
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=64kImplémentation et source
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
Appelle une fois la fonction de rappel update de la scène active.
Syntaxe
void scene_update();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Sans scène active, cet appel est sans effet. Sinon, il efface le drapeau de transition avant l’appel de la fonction de rappel : une transition effectuée dans update reste ainsi détectable après son retour. La table de scènes appartient à l’appelant. Gardez cette table et les cibles de ses pointeurs de fonction ordinaires valides pendant toute son utilisation. Les fonctions de rappel nulles sont ignorées. Ne déclenchez pas de transition récursive et ne remplacez pas la table depuis les fonctions de rappel enter ou exit.
Compilez cet exemple complet avec l’ABI Legacy par défaut. Ses rappels utilisent des appels par pointeur de fonction, non pris en charge et refusés par le compilateur avec --abi=stack. La même restriction s’applique aux alias.
Exemple d’utilisation
scene_update();result[13]=events;result[14]=scene_was_changed();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
La fonction update de la scène 0 enregistre l’événement 11. Le drapeau de transition, auparavant à un, passe à zéro après cette mise à jour ordinaire.


Commande de compilation
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=64kImplémentation et source
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
Indique si une transition de scène est actuellement enregistrée.
Syntaxe
u8 scene_was_changed();Valeur renvoyée
Renvoie 1 si le drapeau de transition est activé, sinon 0.
Conditions et limites
La lecture n’efface pas le drapeau. L’initialisation, le remplacement de la table et le début d’une mise à jour de scène active l’effacent. Un identifiant de scène invalide ne le modifie pas.
Compilez cet exemple complet avec l’ABI Legacy par défaut. Ses rappels utilisent des appels par pointeur de fonction, non pris en charge et refusés par le compilateur avec --abi=stack. La même restriction s’applique aux alias.
Exemple d’utilisation
result[17]=scene_was_changed();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Les vérifications attendent un juste après une transition, zéro après une mise à jour ordinaire et zéro après le remplacement de la table.


Commande de compilation
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=64kImplémentation et source
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 — Arrière-plan, fenêtre et défilement fractionné
Contrôle le défilement immédiat ou en tampon du fond et de la fenêtre, ainsi que jusqu’à huit coupures raster. Distinguez les valeurs courantes suivies par les accesseurs, les registres matériels réels et les valeurs en attente.
Scroll_BgAdd
Ajoute des déplacements signés aux coordonnées suivies du fond et les applique immédiatement.
Syntaxe
void Scroll_BgAdd(s8 dx, s8 dy);Paramètres
dxDéplacement horizontal signé en pixels, de −128 à 127.
dyDéplacement vertical signé en pixels, de −128 à 127.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Aucune attente n’est effectuée. Les réglages et additions immédiats synchronisent la paire de coordonnées en attente concernée avec les valeurs courantes et effacent son drapeau de modification. Même le réglage immédiat d’un seul axe annule la valeur en attente de l’autre axe de la même paire. Les résultats rebouclent modulo 256. Les additions partent des valeurs courantes suivies, pas des valeurs en attente ni des valeurs temporaires des registres raster. Cette fonction enveloppe __scroll_bg_add.
Exemple d’utilisation
Scroll_BgAdd(-20,3);result[22]=M_SCX;result[23]=M_SCY;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Utilisez les fonctions Scroll pour découvrir les mises à jour immédiates, la préparation, l’application, l’addition et la visibilité. L’application fait passer BG X de 250 à 16 et WX de 23 à 39. Le bit de fenêtre vaut 32 après affichage et 0 après masquage.


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Applique les coordonnées modifiées du fond et de la fenêtre à l’état suivi et au matériel, puis efface leurs drapeaux d’attente.
Syntaxe
void Scroll_Flush();Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Une paire de coordonnées inchangée est laissée intacte. Aucune interruption n’est masquée et aucune attente VBlank n’est effectuée ; l’appelant doit prévoir le moment approprié. Cette fonction enveloppe __scroll_flush.
Exemple d’utilisation
Scroll_Flush();result[18]=M_SCX;result[19]=M_SCY;result[20]=M_WX;result[21]=M_WY;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Utilisez les fonctions Scroll pour découvrir les mises à jour immédiates, la préparation, l’application, l’addition et la visibilité. L’application fait passer BG X de 250 à 16 et WX de 23 à 39. Le bit de fenêtre vaut 32 après affichage et 0 après masquage.


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Lit la valeur courante suivie du défilement horizontal du fond.
Syntaxe
u8 Scroll_GetBgX();Valeur renvoyée
Renvoie l’octet courant suivi, de 0 à 255. WX comprend son décalage matériel de sept pixels.
Conditions et limites
Ce n’est pas une lecture de registre matériel. Les valeurs en tampon encore en attente, les écritures directes dans les registres et les valeurs temporaires des coupures raster en sont exclues. Cette fonction enveloppe __scroll_bg_x_get.
Exemple d’utilisation
result[6]=Scroll_GetBgX();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Utilisez les fonctions Scroll pour découvrir les mises à jour immédiates, la préparation, l’application, l’addition et la visibilité. L’application fait passer BG X de 250 à 16 et WX de 23 à 39. Le bit de fenêtre vaut 32 après affichage et 0 après masquage.


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Lit la valeur courante suivie du défilement vertical du fond.
Syntaxe
u8 Scroll_GetBgY();Valeur renvoyée
Renvoie l’octet courant suivi, de 0 à 255. WX comprend son décalage matériel de sept pixels.
Conditions et limites
Ce n’est pas une lecture de registre matériel. Les valeurs en tampon encore en attente, les écritures directes dans les registres et les valeurs temporaires des coupures raster en sont exclues. Cette fonction enveloppe __scroll_bg_y_get.
Exemple d’utilisation
result[7]=Scroll_GetBgY();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Utilisez les fonctions Scroll pour découvrir les mises à jour immédiates, la préparation, l’application, l’addition et la visibilité. L’application fait passer BG X de 250 à 16 et WX de 23 à 39. Le bit de fenêtre vaut 32 après affichage et 0 après masquage.


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Lit la valeur WX courante suivie de la fenêtre.
Syntaxe
u8 Scroll_GetWindowX();Valeur renvoyée
Renvoie l’octet courant suivi, de 0 à 255. WX comprend son décalage matériel de sept pixels.
Conditions et limites
Ce n’est pas une lecture de registre matériel. Les valeurs en tampon encore en attente, les écritures directes dans les registres et les valeurs temporaires des coupures raster en sont exclues. Cette fonction enveloppe __scroll_win_x_get.
Exemple d’utilisation
result[12]=Scroll_GetWindowX();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Utilisez les fonctions Scroll pour découvrir les mises à jour immédiates, la préparation, l’application, l’addition et la visibilité. L’application fait passer BG X de 250 à 16 et WX de 23 à 39. Le bit de fenêtre vaut 32 après affichage et 0 après masquage.


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Lit la valeur WY courante suivie de la fenêtre.
Syntaxe
u8 Scroll_GetWindowY();Valeur renvoyée
Renvoie l’octet courant suivi, de 0 à 255. WX comprend son décalage matériel de sept pixels.
Conditions et limites
Ce n’est pas une lecture de registre matériel. Les valeurs en tampon encore en attente, les écritures directes dans les registres et les valeurs temporaires des coupures raster en sont exclues. Cette fonction enveloppe __scroll_win_y_get.
Exemple d’utilisation
result[13]=Scroll_GetWindowY();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Utilisez les fonctions Scroll pour découvrir les mises à jour immédiates, la préparation, l’application, l’addition et la visibilité. L’application fait passer BG X de 250 à 16 et WX de 23 à 39. Le bit de fenêtre vaut 32 après affichage et 0 après masquage.


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Initialise le défilement du fond à (0,0) et la position de la fenêtre à WX=7, WY=0.
Syntaxe
void Scroll_Init();Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Synchronise les coordonnées courantes et en attente ; ne réinitialise ni la visibilité de la fenêtre ni la table de coupures.
Exemple d’utilisation
Scroll_Init();result[0]=M_SCX;result[1]=M_SCY;result[2]=M_WX;result[3]=M_WY;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Utilisez les fonctions Scroll pour découvrir les mises à jour immédiates, la préparation, l’application, l’addition et la visibilité. L’application fait passer BG X de 250 à 16 et WX de 23 à 39. Le bit de fenêtre vaut 32 après affichage et 0 après masquage.


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Règle immédiatement les deux coordonnées de défilement du fond.
Syntaxe
void Scroll_SetBg(u8 scx, u8 scy);Paramètres
scxDéfilement horizontal du fond, de 0 à 255 pixels ; l’augmenter déplace le fond vers la gauche.
scyDéfilement vertical du fond, de 0 à 255 pixels ; l’augmenter déplace le fond vers le haut.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Enveloppe __scroll_bg_set : synchronise les valeurs courantes, en attente et matérielles, puis efface le drapeau de modification BG, sans attendre VBlank.
Exemple d’utilisation
Scroll_SetBg(8,16);result[28]=M_SCX;result[29]=M_SCY;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Utilisez les fonctions Scroll pour découvrir les mises à jour immédiates, la préparation, l’application, l’addition et la visibilité. L’application fait passer BG X de 250 à 16 et WX de 23 à 39. Le bit de fenêtre vaut 32 après affichage et 0 après masquage.


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Prépare les deux coordonnées de défilement du fond pour une application ultérieure.
Syntaxe
void Scroll_SetBgBuffered(u8 scx, u8 scy);Paramètres
scxDéfilement horizontal du fond, de 0 à 255 pixels ; l’augmenter déplace le fond vers la gauche.
scyDéfilement vertical du fond, de 0 à 255 pixels ; l’augmenter déplace le fond vers le haut.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Ne modifie ni les valeurs courantes suivies ni les registres. Appliquez-les avec __scroll_flush ou Scroll_Flush ; la mise en attente n’attend pas VBlank. Cette fonction enveloppe __scroll_bg_set_buffered.
Exemple d’utilisation
Scroll_SetBgBuffered(16,24);result[14]=M_SCX;result[15]=Scroll_GetBgX();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Utilisez les fonctions Scroll pour découvrir les mises à jour immédiates, la préparation, l’application, l’addition et la visibilité. L’application fait passer BG X de 250 à 16 et WX de 23 à 39. Le bit de fenêtre vaut 32 après affichage et 0 après masquage.


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Règle immédiatement le défilement horizontal du fond.
Syntaxe
void Scroll_SetBgX(u8 scx);Paramètres
scxDéfilement horizontal du fond, de 0 à 255 pixels ; l’augmenter déplace le fond vers la gauche.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Aucune attente n’est effectuée. Les réglages et additions immédiats synchronisent la paire de coordonnées en attente concernée avec les valeurs courantes et effacent son drapeau de modification. Même le réglage immédiat d’un seul axe annule la valeur en attente de l’autre axe de la même paire. Cette fonction enveloppe __scroll_bg_x_set.
Exemple d’utilisation
Scroll_SetBgX(250);result[4]=M_SCX;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Utilisez les fonctions Scroll pour découvrir les mises à jour immédiates, la préparation, l’application, l’addition et la visibilité. L’application fait passer BG X de 250 à 16 et WX de 23 à 39. Le bit de fenêtre vaut 32 après affichage et 0 après masquage.


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Règle immédiatement le défilement vertical du fond.
Syntaxe
void Scroll_SetBgY(u8 scy);Paramètres
scyDéfilement vertical du fond, de 0 à 255 pixels ; l’augmenter déplace le fond vers le haut.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Aucune attente n’est effectuée. Les réglages et additions immédiats synchronisent la paire de coordonnées en attente concernée avec les valeurs courantes et effacent son drapeau de modification. Même le réglage immédiat d’un seul axe annule la valeur en attente de l’autre axe de la même paire. Cette fonction enveloppe __scroll_bg_y_set.
Exemple d’utilisation
Scroll_SetBgY(2);result[5]=M_SCY;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Utilisez les fonctions Scroll pour découvrir les mises à jour immédiates, la préparation, l’application, l’addition et la visibilité. L’application fait passer BG X de 250 à 16 et WX de 23 à 39. Le bit de fenêtre vaut 32 après affichage et 0 après masquage.


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Règle immédiatement WX et WY de la fenêtre.
Syntaxe
void Scroll_SetWindow(u8 wx, u8 wy);Paramètres
wxOctet WX brut, de 0 à 255 : ajoutez 7 au X voulu à l’écran ; le bord gauche utilise 7.
wyHaut de la fenêtre en pixels Y de l’écran, de 0 à 255 ; les lignes visibles vont de 0 à 143.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Aucune attente n’est effectuée. Les réglages et additions immédiats synchronisent la paire de coordonnées en attente concernée avec les valeurs courantes et effacent son drapeau de modification. Même le réglage immédiat d’un seul axe annule la valeur en attente de l’autre axe de la même paire. Cette fonction enveloppe __scroll_win_set.
Exemple d’utilisation
Scroll_SetWindow(15,8);result[8]=M_WX;result[9]=M_WY;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Utilisez les fonctions Scroll pour découvrir les mises à jour immédiates, la préparation, l’application, l’addition et la visibilité. L’application fait passer BG X de 250 à 16 et WX de 23 à 39. Le bit de fenêtre vaut 32 après affichage et 0 après masquage.


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Prépare les deux coordonnées de la fenêtre pour une application ultérieure.
Syntaxe
void Scroll_SetWindowBuffered(u8 wx, u8 wy);Paramètres
wxOctet WX brut, de 0 à 255 : ajoutez 7 au X voulu à l’écran ; le bord gauche utilise 7.
wyHaut de la fenêtre en pixels Y de l’écran, de 0 à 255 ; les lignes visibles vont de 0 à 143.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Ne modifie ni les valeurs courantes suivies ni les registres. Appliquez-les avec __scroll_flush ou Scroll_Flush ; la mise en attente n’attend pas VBlank. Cette fonction enveloppe __scroll_win_set_buffered.
Exemple d’utilisation
Scroll_SetWindowBuffered(39,32);result[16]=M_WX;result[17]=Scroll_GetWindowX();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Utilisez les fonctions Scroll pour découvrir les mises à jour immédiates, la préparation, l’application, l’addition et la visibilité. L’application fait passer BG X de 250 à 16 et WX de 23 à 39. Le bit de fenêtre vaut 32 après affichage et 0 après masquage.


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Règle immédiatement la seule coordonnée WX brute de la fenêtre.
Syntaxe
void Scroll_SetWindowX(u8 wx);Paramètres
wxOctet WX brut, de 0 à 255 : ajoutez 7 au X voulu à l’écran ; le bord gauche utilise 7.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Aucune attente n’est effectuée. Les réglages et additions immédiats synchronisent la paire de coordonnées en attente concernée avec les valeurs courantes et effacent son drapeau de modification. Même le réglage immédiat d’un seul axe annule la valeur en attente de l’autre axe de la même paire. Cette fonction enveloppe __scroll_win_x_set.
Exemple d’utilisation
Scroll_SetWindowX(23);result[10]=M_WX;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Utilisez les fonctions Scroll pour découvrir les mises à jour immédiates, la préparation, l’application, l’addition et la visibilité. L’application fait passer BG X de 250 à 16 et WX de 23 à 39. Le bit de fenêtre vaut 32 après affichage et 0 après masquage.


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Règle immédiatement la seule coordonnée WY de la fenêtre.
Syntaxe
void Scroll_SetWindowY(u8 wy);Paramètres
wyHaut de la fenêtre en pixels Y de l’écran, de 0 à 255 ; les lignes visibles vont de 0 à 143.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Aucune attente n’est effectuée. Les réglages et additions immédiats synchronisent la paire de coordonnées en attente concernée avec les valeurs courantes et effacent son drapeau de modification. Même le réglage immédiat d’un seul axe annule la valeur en attente de l’autre axe de la même paire. Cette fonction enveloppe __scroll_win_y_set.
Exemple d’utilisation
Scroll_SetWindowY(16);result[11]=M_WY;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Utilisez les fonctions Scroll pour découvrir les mises à jour immédiates, la préparation, l’application, l’addition et la visibilité. L’application fait passer BG X de 250 à 16 et WX de 23 à 39. Le bit de fenêtre vaut 32 après affichage et 0 après masquage.


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Mémorise la visibilité de base de la fenêtre et arme le premier événement de ligne de la table de coupures.
Syntaxe
void Scroll_SplitCommit();Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
La table partagée contient huit entrées. L’ajout ne les applique pas et ne les trie pas ; les entrées en excès sont ignorées. Reconstruisez-la avec reset→push→commit à une frontière de trame sûre et espacez assez les événements pour laisser le gestionnaire se terminer. La latence d’interruption peut décaler le premier pixel affecté par rapport à la ligne programmée. Une table non vide active VBlank/STAT dans IE et exécute EI. Une table vide désactive la source LYC, sans restaurer IE ni l’état des interruptions CPU. Cette fonction enveloppe __scroll_split_commit.
Exemple d’utilisation
Scroll_SplitCommit();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Utilisez les fonctions enveloppantes Scroll pour créer trois bandes de défilement du fond. Les événements à LY=64 et 104 changent X en 8 puis 16, plaçant les rectangles de 24×16 en (32,16), (24,80) et (16,112). L’image montre le décalage de chaque bande.


Commande de compilation
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=64kImplémentation et source
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
Ajoute une coupure qui modifie le défilement du fond lors de l’événement de ligne demandé.
Syntaxe
void Scroll_SplitPush(u8 ly, u8 scx, u8 scy);Paramètres
lyNuméro de ligne de l’événement ; utilisez 0–143 pour les événements visibles et ajoutez-les par ordre croissant. Une première entrée à zéro est appliquée pendant VBlank.
scxDéfilement horizontal du fond, de 0 à 255 pixels ; l’augmenter déplace le fond vers la gauche.
scyDéfilement vertical du fond, de 0 à 255 pixels ; l’augmenter déplace le fond vers le haut.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
La table partagée contient huit entrées. L’ajout ne les applique pas et ne les trie pas ; les entrées en excès sont ignorées. Reconstruisez-la avec reset→push→commit à une frontière de trame sûre et espacez assez les événements pour laisser le gestionnaire se terminer. La latence d’interruption peut décaler le premier pixel affecté par rapport à la ligne programmée. Cette fonction enveloppe __scroll_split_push.
Exemple d’utilisation
Scroll_SplitPush(64,8,0);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Utilisez les fonctions enveloppantes Scroll pour créer trois bandes de défilement du fond. Les événements à LY=64 et 104 changent X en 8 puis 16, plaçant les rectangles de 24×16 en (32,16), (24,80) et (16,112). L’image montre le décalage de chaque bande.


Commande de compilation
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=64kImplémentation et source
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
Ajoute un événement qui change la couleur zéro de la palette zéro du fond CGB.
Syntaxe
void Scroll_SplitPushBgColor0(u8 ly, u16 rgb15);Paramètres
lyNuméro de ligne de l’événement ; utilisez 0–143 pour les événements visibles et ajoutez-les par ordre croissant. Une première entrée à zéro est appliquée pendant VBlank.
rgb15Couleur RGB555 sur 15 bits : rouge aux bits 0–4, vert aux bits 5–9 et bleu aux bits 10–14.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
CGB uniquement. Utilise une entrée de la table à huit coupures via l’opération étendue. Les écritures de palette attendent un créneau accessible du PPU. Dans cet exemple CGB à vitesse normale, les événements LY=64/112 deviennent visibles aux lignes 66/114. Ne confondez pas la ligne de l’événement avec la première ligne affectée à l’écran.
Exemple d’utilisation
Scroll_SplitPushBgColor0(0,0x7C00);Scroll_SplitPushBgColor0(64,0x001F);Scroll_SplitPushBgColor0(112,0x03E0);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Changez la couleur zéro du fond CGB pendant la trame. À vitesse normale, cet exemple dessine les lignes 0–65 en bleu, 66–113 en rouge et 114–143 en vert. Les événements sont programmés à 0, 64 et 112 ; le traitement des interruptions et l’accès aux palettes ajoutent de la latence. Le DMG ne propose pas ces palettes de couleurs.

Commande de compilation
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=64kImplémentation et source
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
Ajoute une coupure dont les drapeaux choisissent les opérations sur le fond, la fenêtre, sa visibilité ou la couleur zéro du fond.
Syntaxe
void Scroll_SplitPushEx(u8 ly, u8 scx, u8 scy, u8 wx, u8 wy, u8 flags);Paramètres
lyNuméro de ligne de l’événement ; utilisez 0–143 pour les événements visibles et ajoutez-les par ordre croissant. Une première entrée à zéro est appliquée pendant VBlank.
scxDéfilement horizontal du fond, de 0 à 255 pixels ; l’augmenter déplace le fond vers la gauche.
scyDéfilement vertical du fond, de 0 à 255 pixels ; l’augmenter déplace le fond vers le haut.
wxOctet WX brut, de 0 à 255 : ajoutez 7 au X voulu à l’écran ; le bord gauche utilise 7.
wyHaut de la fenêtre en pixels Y de l’écran, de 0 à 255 ; les lignes visibles vont de 0 à 143.
flagsBits d’opération : BG=1, position de fenêtre=2, afficher=4, masquer=8, palette de fond CGB 0/couleur 0=16. Les bits inconnus sont ignorés. Le mode couleur zéro réutilise scx/scy comme octets faible/fort de RGB15.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
La table partagée contient huit entrées. L’ajout ne les applique pas et ne les trie pas ; les entrées en excès sont ignorées. Reconstruisez-la avec reset→push→commit à une frontière de trame sûre et espacez assez les événements pour laisser le gestionnaire se terminer. La latence d’interruption peut décaler le premier pixel affecté par rapport à la ligne programmée. Afficher est prioritaire si les deux bits de visibilité sont actifs. La couleur zéro est réservée au CGB ; la combiner au déplacement BG utilise les mêmes octets scx/scy pour les deux opérations. Cette fonction enveloppe __scroll_split_push_ex.
Exemple d’utilisation
Scroll_SplitPushEx(104,16,0,7,0,KQ_SCROLL_SPLIT_USE_BG|KQ_SCROLL_SPLIT_WIN_HIDE);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Utilisez les fonctions enveloppantes Scroll pour créer trois bandes de défilement du fond. Les événements à LY=64 et 104 changent X en 8 puis 16, plaçant les rectangles de 24×16 en (32,16), (24,80) et (16,112). L’image montre le décalage de chaque bande.


Commande de compilation
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=64kImplémentation et source
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
Remet à zéro le nombre et l’indice des coupures, désactive leur traitement et efface le bit d’activation de l’interruption LYC dans STAT.
Syntaxe
void Scroll_SplitReset();Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
La table partagée contient huit entrées. L’ajout ne les applique pas et ne les trie pas ; les entrées en excès sont ignorées. Reconstruisez-la avec reset→push→commit à une frontière de trame sûre et espacez assez les événements pour laisser le gestionnaire se terminer. La latence d’interruption peut décaler le premier pixel affecté par rapport à la ligne programmée. N’efface pas les octets de la table ni IE et ne désactive pas les interruptions du CPU. Cette fonction enveloppe __scroll_split_reset.
Exemple d’utilisation
Scroll_SplitReset();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Utilisez les fonctions enveloppantes Scroll pour créer trois bandes de défilement du fond. Les événements à LY=64 et 104 changent X en 8 puis 16, plaçant les rectangles de 24×16 en (32,16), (24,80) et (16,112). L’image montre le décalage de chaque bande.


Commande de compilation
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=64kImplémentation et source
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
Ajoute des déplacements signés aux coordonnées suivies de la fenêtre et les applique immédiatement.
Syntaxe
void Scroll_WindowAdd(s8 dx, s8 dy);Paramètres
dxDéplacement horizontal signé en pixels, de −128 à 127.
dyDéplacement vertical signé en pixels, de −128 à 127.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Aucune attente n’est effectuée. Les réglages et additions immédiats synchronisent la paire de coordonnées en attente concernée avec les valeurs courantes et effacent son drapeau de modification. Même le réglage immédiat d’un seul axe annule la valeur en attente de l’autre axe de la même paire. Les résultats rebouclent modulo 256. Les additions partent des valeurs courantes suivies, pas des valeurs en attente ni des valeurs temporaires des registres raster. Cette fonction enveloppe __scroll_win_add.
Exemple d’utilisation
Scroll_WindowAdd(4,-40);result[24]=M_WX;result[25]=M_WY;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Utilisez les fonctions Scroll pour découvrir les mises à jour immédiates, la préparation, l’application, l’addition et la visibilité. L’application fait passer BG X de 250 à 16 et WX de 23 à 39. Le bit de fenêtre vaut 32 après affichage et 0 après masquage.


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Efface le bit de fenêtre LCDC et l’état suivi de visibilité de la fenêtre.
Syntaxe
void Scroll_WindowHide();Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Ne modifie ni les coordonnées ni le choix de la carte. Pour être visible, la fenêtre exige aussi que le LCD et les fonctions fond/fenêtre soient activés et qu’elle se trouve dans la zone visible. Cette fonction enveloppe __scroll_win_hide.
Exemple d’utilisation
Scroll_WindowHide();result[27]=M_LCDC&32;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Utilisez les fonctions Scroll pour découvrir les mises à jour immédiates, la préparation, l’application, l’addition et la visibilité. L’application fait passer BG X de 250 à 16 et WX de 23 à 39. Le bit de fenêtre vaut 32 après affichage et 0 après masquage.


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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
Active le bit de fenêtre LCDC et l’état suivi de visibilité de la fenêtre.
Syntaxe
void Scroll_WindowShow();Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Ne modifie ni les coordonnées ni le choix de la carte. Pour être visible, la fenêtre exige aussi que le LCD et les fonctions fond/fenêtre soient activés et qu’elle se trouve dans la zone visible. Cette fonction enveloppe __scroll_win_show.
Exemple d’utilisation
Scroll_WindowShow();result[26]=M_LCDC&32;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Utilisez les fonctions Scroll pour découvrir les mises à jour immédiates, la préparation, l’application, l’addition et la visibilité. L’application fait passer BG X de 250 à 16 et WX de 23 à 39. Le bit de fenêtre vaut 32 après affichage et 0 après masquage.


Commande de compilation
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=64kExemple d’utilisation
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec la caméra en (8,16), le rectangle rouge de 32×24 apparaît à l’écran en (24,16). La fenêtre montre un cadre bleu de 64×64 en (96,80) et un carré vert de 16×16 en (112,96). Toutes les formes sont noires sur DMG.


Commande de compilation
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=64kImplémentation et source
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 — Plateaux, listes de coups et annulation
Fournit un plateau à valeurs d’un octet, une liste de coups de capacité limitée et une pile d’annulations. Le jeu combine ces opérations pour appliquer les coups ou les annulations au plateau.
slg_board_clear
Remplit toutes les cases du plateau avec la valeur demandée.
Syntaxe
void slg_board_clear(SLGBoard* board, u8 value);Paramètres
boardSLGBoardà utiliser ; l’initialisation exige un stockage non NULL.valueValeur d’octet à stocker ; le jeu en définit le sens, par exemple un type de pièce ou de terrain.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Le stockage est fourni par l’appelant. L’initialisation ne l’alloue pas et ne l’efface pas. Les coordonnées du plateau sont exprimées en cases.
Exemple d’utilisation
slg_board_clear(&board,0);result[1]=cells[0];result[2]=cells[11];Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple distingue plateau, liste de coups et enregistrements d’annulation. L’initialisation du plateau conserve 9 ; un troisième ajout à une liste de capacité deux renvoie 0. Dépiler seul laisse le plateau à 8 ; appliquer explicitement l’enregistrement récupéré rétablit 7.


Commande de compilation
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=64kImplémentation et source
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
Lit une case ; renvoie zéro pour un plateau NULL ou des coordonnées hors limites.
Syntaxe
u8 slg_board_get(const SLGBoard* board, u8 x, u8 y);Paramètres
boardSLGBoardà utiliser ; l’initialisation exige un stockage non NULL.xColonne de la case depuis la gauche, à partir de zéro ; enregistrer un coup ne vérifie pas les limites du plateau.
yLigne de la case depuis le haut, à partir de zéro ; enregistrer un coup ne vérifie pas les limites du plateau.
Valeur renvoyée
Octet de la case, ou zéro si la lecture est invalide. Zéro seul ne distingue pas une case vide de coordonnées invalides.
Conditions et limites
Le stockage est fourni par l’appelant. L’initialisation ne l’alloue pas et ne l’efface pas. Les coordonnées du plateau sont exprimées en cases.
Exemple d’utilisation
result[3]=slg_board_get(&board,1,1);result[4]=slg_board_get(&board,4,1);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple distingue plateau, liste de coups et enregistrements d’annulation. L’initialisation du plateau conserve 9 ; un troisième ajout à une liste de capacité deux renvoie 0. Dépiler seul laisse le plateau à 8 ; appliquer explicitement l’enregistrement récupéré rétablit 7.


Commande de compilation
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=64kImplémentation et source
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
Associe les dimensions d’un plateau à un tableau de cases en conservant son contenu existant.
Syntaxe
void slg_board_init(SLGBoard* board, u8 width, u8 height, u8* cells);Paramètres
boardSLGBoardà utiliser ; l’initialisation exige un stockage non NULL.widthLargeur du plateau en cases, également utilisée comme pas entre les lignes.
heightNombre de lignes du plateau.
cellsTableau accessible en écriture, rangé ligne par ligne, d’au moins
width*heightoctets de cases.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Le stockage est fourni par l’appelant. L’initialisation ne l’alloue pas et ne l’efface pas. Les coordonnées du plateau sont exprimées en cases.
Exemple d’utilisation
cells[0]=9;slg_board_init(&board,4,3,cells);result[0]=slg_board_get(&board,0,0);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple distingue plateau, liste de coups et enregistrements d’annulation. L’initialisation du plateau conserve 9 ; un troisième ajout à une liste de capacité deux renvoie 0. Dépiler seul laisse le plateau à 8 ; appliquer explicitement l’enregistrement récupéré rétablit 7.


Commande de compilation
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=64kImplémentation et source
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
Écrit dans une case valide du plateau ; ignore un plateau NULL ou des coordonnées hors limites.
Syntaxe
void slg_board_set(SLGBoard* board, u8 x, u8 y, u8 value);Paramètres
boardSLGBoardà utiliser ; l’initialisation exige un stockage non NULL.xColonne de la case depuis la gauche, à partir de zéro ; enregistrer un coup ne vérifie pas les limites du plateau.
yLigne de la case depuis le haut, à partir de zéro ; enregistrer un coup ne vérifie pas les limites du plateau.
valueValeur d’octet à stocker ; le jeu en définit le sens, par exemple un type de pièce ou de terrain.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Le stockage est fourni par l’appelant. L’initialisation ne l’alloue pas et ne l’efface pas. Les coordonnées du plateau sont exprimées en cases.
Exemple d’utilisation
slg_board_set(&board,1,1,7);slg_board_set(&board,4,1,9);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple distingue plateau, liste de coups et enregistrements d’annulation. L’initialisation du plateau conserve 9 ; un troisième ajout à une liste de capacité deux renvoie 0. Dépiler seul laisse le plateau à 8 ; appliquer explicitement l’enregistrement récupéré rétablit 7.


Commande de compilation
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=64kImplémentation et source
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
Réinitialise le nombre de coups sans effacer les enregistrements stockés.
Syntaxe
void slg_move_list_clear(SLGMoveList* list);Paramètres
listListe de coups à utiliser ; l’initialisation exige un pointeur non NULL.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Le stockage est fourni par l’appelant. L’initialisation ne l’alloue pas et ne l’efface pas. Les coordonnées du plateau sont exprimées en cases.
Exemple d’utilisation
slg_move_list_clear(&moves);result[10]=moves.count;result[11]=move_data[0].value;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple distingue plateau, liste de coups et enregistrements d’annulation. L’initialisation du plateau conserve 9 ; un troisième ajout à une liste de capacité deux renvoie 0. Dépiler seul laisse le plateau à 8 ; appliquer explicitement l’enregistrement récupéré rétablit 7.


Commande de compilation
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=64kImplémentation et source
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
Associe un espace de stockage de coups et sa capacité, puis met le compteur à zéro.
Syntaxe
void slg_move_list_init(SLGMoveList* list, SLGMove* items, u8 capacity);Paramètres
listListe de coups à utiliser ; l’initialisation exige un pointeur non NULL.
itemsTableau détenu par l’appelant, capable de contenir au moins
capacityenregistrementsSLGMove.capacityNombre maximal d’enregistrements ; zéro interdit tout ajout. Chaque enregistrement contient trois octets : x, y et valeur.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Le stockage est fourni par l’appelant. L’initialisation ne l’alloue pas et ne l’efface pas. Les coordonnées du plateau sont exprimées en cases.
Exemple d’utilisation
slg_move_list_init(&moves,move_data,2);result[5]=moves.count;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple distingue plateau, liste de coups et enregistrements d’annulation. L’initialisation du plateau conserve 9 ; un troisième ajout à une liste de capacité deux renvoie 0. Dépiler seul laisse le plateau à 8 ; appliquer explicitement l’enregistrement récupéré rétablit 7.


Commande de compilation
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=64kImplémentation et source
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
Ajoute des coordonnées et une valeur à la liste de coups sans modifier le plateau.
Syntaxe
u8 slg_move_list_push(SLGMoveList* list, u8 x, u8 y, u8 value);Paramètres
listListe de coups à utiliser ; l’initialisation exige un pointeur non NULL.
xColonne de la case depuis la gauche, à partir de zéro ; enregistrer un coup ne vérifie pas les limites du plateau.
yLigne de la case depuis le haut, à partir de zéro ; enregistrer un coup ne vérifie pas les limites du plateau.
valueValeur d’octet à stocker ; le jeu en définit le sens, par exemple un type de pièce ou de terrain.
Valeur renvoyée
1 si l’ajout réussit, 0 pour NULL ou un stockage plein ; en cas d’échec, le compteur et les enregistrements existants sont conservés.
Conditions et limites
Le stockage est fourni par l’appelant. L’initialisation ne l’alloue pas et ne l’efface pas. Les coordonnées du plateau sont exprimées en cases.
Exemple d’utilisation
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;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple distingue plateau, liste de coups et enregistrements d’annulation. L’initialisation du plateau conserve 9 ; un troisième ajout à une liste de capacité deux renvoie 0. Dépiler seul laisse le plateau à 8 ; appliquer explicitement l’enregistrement récupéré rétablit 7.


Commande de compilation
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=64kImplémentation et source
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
Associe un espace de stockage d’annulations et sa capacité, avec une pile initialement vide.
Syntaxe
void slg_undo_init(SLGUndoStack* stack, SLGMove* items, u8 capacity);Paramètres
stackPile d’annulation à utiliser ; l’initialisation exige un pointeur non NULL.
itemsTableau détenu par l’appelant, capable de contenir au moins
capacityenregistrementsSLGMove.capacityNombre maximal d’enregistrements ; zéro interdit tout ajout. Chaque enregistrement contient trois octets : x, y et valeur.
Valeur renvoyée
Aucune valeur de retour. L’état modifié et le moment de sa prise d’effet sont décrits dans cette entrée.
Conditions et limites
Le stockage est fourni par l’appelant. L’initialisation ne l’alloue pas et ne l’efface pas. Les coordonnées du plateau sont exprimées en cases.
Exemple d’utilisation
slg_undo_init(&undo,undo_data,2);result[12]=undo.count;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple distingue plateau, liste de coups et enregistrements d’annulation. L’initialisation du plateau conserve 9 ; un troisième ajout à une liste de capacité deux renvoie 0. Dépiler seul laisse le plateau à 8 ; appliquer explicitement l’enregistrement récupéré rétablit 7.


Commande de compilation
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=64kImplémentation et source
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
Retire et récupère le dernier enregistrement d’annulation ; l’appelant l’applique au plateau.
Syntaxe
u8 slg_undo_pop(SLGUndoStack* stack, SLGMove* out_move);Paramètres
stackPile d’annulation à utiliser ; l’initialisation exige un pointeur non NULL.
out_moveDestination de l’enregistrement retiré ; NULL le supprime sans le copier.
Valeur renvoyée
1 si un enregistrement a été retiré, 0 pour une pile NULL ou vide ; une pile vide laisse la sortie inchangée.
Conditions et limites
Le stockage est fourni par l’appelant. L’initialisation ne l’alloue pas et ne l’efface pas. Les coordonnées du plateau sont exprimées en cases.
Exemple d’utilisation
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);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple distingue plateau, liste de coups et enregistrements d’annulation. L’initialisation du plateau conserve 9 ; un troisième ajout à une liste de capacité deux renvoie 0. Dépiler seul laisse le plateau à 8 ; appliquer explicitement l’enregistrement récupéré rétablit 7.


Commande de compilation
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=64kImplémentation et source
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
Empile l’ancienne valeur d’une case dans la pile d’annulation sans modifier le plateau.
Syntaxe
u8 slg_undo_push(SLGUndoStack* stack, u8 x, u8 y, u8 old_value);Paramètres
stackPile d’annulation à utiliser ; l’initialisation exige un pointeur non NULL.
xColonne de la case depuis la gauche, à partir de zéro ; enregistrer un coup ne vérifie pas les limites du plateau.
yLigne de la case depuis le haut, à partir de zéro ; enregistrer un coup ne vérifie pas les limites du plateau.
old_valueAncien octet de la case ; la fonction ne le lit pas automatiquement dans le plateau.
Valeur renvoyée
1 si l’ajout réussit, 0 pour NULL ou un stockage plein ; en cas d’échec, le compteur et les enregistrements existants sont conservés.
Conditions et limites
Le stockage est fourni par l’appelant. L’initialisation ne l’alloue pas et ne l’efface pas. Les coordonnées du plateau sont exprimées en cases.
Exemple d’utilisation
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);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cet exemple distingue plateau, liste de coups et enregistrements d’annulation. L’initialisation du plateau conserve 9 ; un troisième ajout à une liste de capacité deux renvoie 0. Dépiler seul laisse le plateau à 8 ; appliquer explicitement l’enregistrement récupéré rétablit 7.


Commande de compilation
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=64kImplémentation et source
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 — Allocation d'OBJ, placement, métasprites et animation
Les sprites sont des objets matériels mobiles, généralement de 8×8 ou 8×16 pixels, décrits dans l’OAM, la mémoire des attributs d’objets. Réservez des entrées, préparez position, tuile et attributs dans la copie de l’OAM, puis transférez-la. Un métasprite réunit plusieurs entrées en un objet. Le GB offre 40 entrées avec une limite de 10 par ligne ; le FC, 64 avec une limite de 8 par ligne.
Attributs GB : le bit 4 sélectionne OBP1 sur DMG ; 5/6 retournent X/Y ; 7 place le sprite derrière les pixels de fond d’indice non nul. Sur CGB, 0..2 choisissent la palette d’objets et 3 la banque VRAM des tuiles ; le bit de palette DMG ne choisit pas les couleurs natives CGB.
L’exemple utilise la bibliothèque GB complète. KQ_SPRITE_MINIMAL_RUNTIME retire de sprite.c sprite_free, sprite_set_pos, sprite_count_used, les deux requêtes de lignes, metasprite_draw et anim_update. Ne le définissez pas si vous utilisez ces fonctions.
anim_update
Avance le compteur SpriteAnim et renvoie la tuile sélectionnée. Toutes les ticks_per_frame invocations, il passe à la tuile consécutive suivante et revient à la première après frame_count images. Appliquez le résultat avec sprite_set_tile.
Syntaxe
u8 anim_update(SpriteAnim* anim);Paramètres
animÉtat SpriteAnim modifiable contenant first_tile, frame_count, frame, ticks et ticks_per_frame. Pour des limites non nulles, gardez frame inférieur à frame_count et ticks inférieur à ticks_per_frame.
Valeur renvoyée
Numéro de tuile sur 8 bits ; 0 si le pointeur d’état est nul. La fonction n’écrit pas dans l’OAM.
Conditions et limites
frame_count=0 renvoie first_tile sans avancer ; ticks_per_frame=0 fige l’image courante. Le compteur avance par appel, pas par image vidéo. Les numéros rebouclent après 255 et avancent de un même en mode 8×16.
L’exemple utilise la bibliothèque GB complète. KQ_SPRITE_MINIMAL_RUNTIME retire de sprite.c sprite_free, sprite_set_pos, sprite_count_used, les deux requêtes de lignes, metasprite_draw et anim_update. Ne le définissez pas si vous utilisez ces fonctions.
Exemple d’utilisation
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);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec first_tile=128, deux images et deux appels par image, la première mise à jour renvoie la flèche 128 et la seconde le carré 129. Le carré près d’ANIMATION confirme l’application du résultat à l’OAM.
Ce programme présente allocation, positionnement, retournements, objets composés, superposition, animation et limite par ligne. Les deux chiffres en haut à droite doivent être 00 : toutes les vérifications internes ont réussi. Chaque flèche et carré occupe une tuile de 8×8.
NORMAL montre une flèche vers la droite en (88,16). FLIP X pointe à gauche en (88,32) ; FLIP Y retourne la flèche verticalement en (88,48). META place deux flèches en (88,64) et (96,64). OVERLAP place la flèche de (88,80) devant le carré de (92,80), visible à travers les pixels transparents. ANIMATION montre le carré en (88,96). Les zones (120,16) et (120,32) restent vides après masquage et libération de leurs entrées.
Sur CGB et FC, la flèche a une tige verte, un contour rouge et des détails bleus à la pointe ; le carré est vert. La transparence révèle le fond blanc du GB ou noir du FC. Le DMG remplace rouge, vert et bleu par gris clair, gris foncé et noir.
La rangée sous SCAN LIMIT commence en (8,128). Le programme soumet 11 sprites sur GB ou 9 sur FC, soit un de trop volontairement. Attendez 10 flèches visibles sur GB et 8 sur FC ; la dernière soumise est absente. Les vérifications du maximum logiciel et de l’avertissement doivent donner 11/9 et 1.


Commande de compilation
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-disasmImplémentation et source
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
Consultez les changements et vérifications du 2026-10-03 pour les différences locales de cette API.
Place un tableau de parties de sprite dans des entrées consécutives. Chaque partie fournit un décalage signé, une tuile et des attributs. La routine active les entrées libres, remplace les actives et s’arrête à la limite des entrées.
Syntaxe
u8 metasprite_draw(u8 first_id, u8 x, u8 y, const MetaSpritePart* parts, u8 count);Paramètres
first_idIdentifiant entre 0 et SPRITE_MAX-1 : par défaut 0..39 sur GB, 0..63 sur FC. Les identifiants hors limites sont ignorés.
xPosition horizontale en pixels, sous forme d’octet non signé ; ce n’est pas une coordonnée de tuile.
yCoordonnée Y écran en pixels. La fonction GB ajoute 16 avant de la stocker dans l’OAM.
partsTableau lisible d’au moins count enregistrements MetaSpritePart. Chaque enregistrement de quatre octets contient dx/dy signés, tuile et attributs, sans marqueur de fin.
countNombre de parties sous forme d’octet non signé. Zéro n’écrit rien. Si les entrées consécutives atteignent SPRITE_MAX, seules les parties qui tiennent sont écrites.
Valeur renvoyée
Nombre de parties écrites, entre 0 et count. Vérifiez ce résultat pour détecter une troncature à la limite des entrées.
Conditions et limites
Position, tuile, attributs et masquage modifient la copie de travail. Ils ne réservent aucune entrée et ne mettent pas immédiatement l’OAM à jour ; transférez l’image préparée avec sprite_flush_oam.
Les décalages sont des octets signés ajoutés à l’origine, avec rebouclage sur huit bits. Le tableau doit rester lisible pendant l’appel. Les entrées actives sont remplacées ; celles d’autres objets ne sont pas protégées.
L’exemple utilise la bibliothèque GB complète. KQ_SPRITE_MINIMAL_RUNTIME retire de sprite.c sprite_free, sprite_set_pos, sprite_count_used, les deux requêtes de lignes, metasprite_draw et anim_update. Ne le définissez pas si vous utilisez ces fonctions.
Exemple d’utilisation
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.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’initialisation donne zéro réservation. Huit allocations renvoient 0..7. Masquer l’entrée 6 conserve 8 ; libérer deux fois la 7 laisse 7. Placer la paire en 10 et 11 porte le total à 9.
Ce programme présente allocation, positionnement, retournements, objets composés, superposition, animation et limite par ligne. Les deux chiffres en haut à droite doivent être 00 : toutes les vérifications internes ont réussi. Chaque flèche et carré occupe une tuile de 8×8.
NORMAL montre une flèche vers la droite en (88,16). FLIP X pointe à gauche en (88,32) ; FLIP Y retourne la flèche verticalement en (88,48). META place deux flèches en (88,64) et (96,64). OVERLAP place la flèche de (88,80) devant le carré de (92,80), visible à travers les pixels transparents. ANIMATION montre le carré en (88,96). Les zones (120,16) et (120,32) restent vides après masquage et libération de leurs entrées.
Sur CGB et FC, la flèche a une tige verte, un contour rouge et des détails bleus à la pointe ; le carré est vert. La transparence révèle le fond blanc du GB ou noir du FC. Le DMG remplace rouge, vert et bleu par gris clair, gris foncé et noir.
La rangée sous SCAN LIMIT commence en (8,128). Le programme soumet 11 sprites sur GB ou 9 sur FC, soit un de trop volontairement. Attendez 10 flèches visibles sur GB et 8 sur FC ; la dernière soumise est absente. Les vérifications du maximum logiciel et de l’avertissement doivent donner 11/9 et 1.


Commande de compilation
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-disasmImplémentation et source
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
Réserve la première entrée libre et la masque jusqu’à ce que vous la positionniez. Une entrée masquée reste réservée ; définissez sa tuile et ses attributs avant de l’afficher.
Syntaxe
u8 sprite_alloc();Valeur renvoyée
Identifiant réservé, ou 0xFF si toutes les entrées sont actives.
Conditions et limites
Position, tuile, attributs et masquage modifient la copie de travail. Ils ne réservent aucune entrée et ne mettent pas immédiatement l’OAM à jour ; transférez l’image préparée avec sprite_flush_oam.
L’exemple utilise la bibliothèque GB complète. KQ_SPRITE_MINIMAL_RUNTIME retire de sprite.c sprite_free, sprite_set_pos, sprite_count_used, les deux requêtes de lignes, metasprite_draw et anim_update. Ne le définissez pas si vous utilisez ces fonctions.
Exemple d’utilisation
for(i=0;i<8;i++) sprite_example_expect(sprite_alloc()==i);
sprite_example_expect(sprite_count_used()==8);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’initialisation donne zéro réservation. Huit allocations renvoient 0..7. Masquer l’entrée 6 conserve 8 ; libérer deux fois la 7 laisse 7. Placer la paire en 10 et 11 porte le total à 9.
Ce programme présente allocation, positionnement, retournements, objets composés, superposition, animation et limite par ligne. Les deux chiffres en haut à droite doivent être 00 : toutes les vérifications internes ont réussi. Chaque flèche et carré occupe une tuile de 8×8.
NORMAL montre une flèche vers la droite en (88,16). FLIP X pointe à gauche en (88,32) ; FLIP Y retourne la flèche verticalement en (88,48). META place deux flèches en (88,64) et (96,64). OVERLAP place la flèche de (88,80) devant le carré de (92,80), visible à travers les pixels transparents. ANIMATION montre le carré en (88,96). Les zones (120,16) et (120,32) restent vides après masquage et libération de leurs entrées.
Sur CGB et FC, la flèche a une tige verte, un contour rouge et des détails bleus à la pointe ; le carré est vert. La transparence révèle le fond blanc du GB ou noir du FC. Le DMG remplace rouge, vert et bleu par gris clair, gris foncé et noir.
La rangée sous SCAN LIMIT commence en (8,128). Le programme soumet 11 sprites sur GB ou 9 sur FC, soit un de trop volontairement. Attendez 10 flèches visibles sur GB et 8 sur FC ; la dernière soumise est absente. Les vérifications du maximum logiciel et de l’avertissement doivent donner 11/9 et 1.


Commande de compilation
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-disasmImplémentation et source
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
Renvoie le nombre d’entrées réservées, y compris les sprites masqués et les entrées activées par metasprite_draw. Il s’agit des réservations, pas des sprites visibles.
Syntaxe
u8 sprite_count_used();Valeur renvoyée
Octet non signé entre 0 et SPRITE_MAX.
Conditions et limites
L’exemple utilise la bibliothèque GB complète. KQ_SPRITE_MINIMAL_RUNTIME retire de sprite.c sprite_free, sprite_set_pos, sprite_count_used, les deux requêtes de lignes, metasprite_draw et anim_update. Ne le définissez pas si vous utilisez ces fonctions.
Exemple d’utilisation
sprite_example_expect(sprite_count_used()==9); // After hiding, freeing and drawing the pair.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’initialisation donne zéro réservation. Huit allocations renvoient 0..7. Masquer l’entrée 6 conserve 8 ; libérer deux fois la 7 laisse 7. Placer la paire en 10 et 11 porte le total à 9.
Ce programme présente allocation, positionnement, retournements, objets composés, superposition, animation et limite par ligne. Les deux chiffres en haut à droite doivent être 00 : toutes les vérifications internes ont réussi. Chaque flèche et carré occupe une tuile de 8×8.
NORMAL montre une flèche vers la droite en (88,16). FLIP X pointe à gauche en (88,32) ; FLIP Y retourne la flèche verticalement en (88,48). META place deux flèches en (88,64) et (96,64). OVERLAP place la flèche de (88,80) devant le carré de (92,80), visible à travers les pixels transparents. ANIMATION montre le carré en (88,96). Les zones (120,16) et (120,32) restent vides après masquage et libération de leurs entrées.
Sur CGB et FC, la flèche a une tige verte, un contour rouge et des détails bleus à la pointe ; le carré est vert. La transparence révèle le fond blanc du GB ou noir du FC. Le DMG remplace rouge, vert et bleu par gris clair, gris foncé et noir.
La rangée sous SCAN LIMIT commence en (8,128). Le programme soumet 11 sprites sur GB ou 9 sur FC, soit un de trop volontairement. Attendez 10 flèches visibles sur GB et 8 sur FC ; la dernière soumise est absente. Les vérifications du maximum logiciel et de l’avertissement doivent donner 11/9 et 1.


Commande de compilation
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-disasmImplémentation et source
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
Attend le VBlank, puis transfère la copie de l’OAM avec sprite_flush_oam_now.
Syntaxe
void sprite_flush_oam();Valeur renvoyée
Aucune (void).
Conditions et limites
La routine GB exécute le DMA depuis la HRAM et copie les 160 octets de l’OAM alignée. Elle désactive les interruptions pendant le transfert et les réactive toujours ensuite, sans restaurer un éventuel état désactivé à l’entrée.
L’exemple utilise la bibliothèque GB complète. KQ_SPRITE_MINIMAL_RUNTIME retire de sprite.c sprite_free, sprite_set_pos, sprite_count_used, les deux requêtes de lignes, metasprite_draw et anim_update. Ne le définissez pas si vous utilisez ces fonctions.
Exemple d’utilisation
while(1) { sprite_flush_oam(); } // Transfer prepared sprites at the next frame boundary.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
NORMAL montre une flèche vers la droite en (88,16). FLIP X pointe à gauche en (88,32) ; FLIP Y retourne la flèche verticalement en (88,48). META place deux flèches en (88,64) et (96,64). OVERLAP place la flèche de (88,80) devant le carré de (92,80), visible à travers les pixels transparents. ANIMATION montre le carré en (88,96). Les zones (120,16) et (120,32) restent vides après masquage et libération de leurs entrées.
Ce programme présente allocation, positionnement, retournements, objets composés, superposition, animation et limite par ligne. Les deux chiffres en haut à droite doivent être 00 : toutes les vérifications internes ont réussi. Chaque flèche et carré occupe une tuile de 8×8.
Sur CGB et FC, la flèche a une tige verte, un contour rouge et des détails bleus à la pointe ; le carré est vert. La transparence révèle le fond blanc du GB ou noir du FC. Le DMG remplace rouge, vert et bleu par gris clair, gris foncé et noir.
La rangée sous SCAN LIMIT commence en (8,128). Le programme soumet 11 sprites sur GB ou 9 sur FC, soit un de trop volontairement. Attendez 10 flèches visibles sur GB et 8 sur FC ; la dernière soumise est absente. Les vérifications du maximum logiciel et de l’avertissement doivent donner 11/9 et 1.


Commande de compilation
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-disasmImplémentation et source
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
Transfère immédiatement la copie de l’OAM vers le matériel. La routine n’attend pas une période d’affichage sûre ; le code appelant choisit le moment de l’exécuter.
Syntaxe
void sprite_flush_oam_now();Valeur renvoyée
Aucune (void).
Conditions et limites
La routine GB exécute le DMA depuis la HRAM et copie les 160 octets de l’OAM alignée. Elle désactive les interruptions pendant le transfert et les réactive toujours ensuite, sans restaurer un éventuel état désactivé à l’entrée.
L’exemple utilise la bibliothèque GB complète. KQ_SPRITE_MINIMAL_RUNTIME retire de sprite.c sprite_free, sprite_set_pos, sprite_count_used, les deux requêtes de lignes, metasprite_draw et anim_update. Ne le définissez pas si vous utilisez ces fonctions.
Exemple d’utilisation
// Rendering is disabled here; all shadow entries have been prepared.
sprite_flush_oam_now();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
NORMAL montre une flèche vers la droite en (88,16). FLIP X pointe à gauche en (88,32) ; FLIP Y retourne la flèche verticalement en (88,48). META place deux flèches en (88,64) et (96,64). OVERLAP place la flèche de (88,80) devant le carré de (92,80), visible à travers les pixels transparents. ANIMATION montre le carré en (88,96). Les zones (120,16) et (120,32) restent vides après masquage et libération de leurs entrées.
Ce programme présente allocation, positionnement, retournements, objets composés, superposition, animation et limite par ligne. Les deux chiffres en haut à droite doivent être 00 : toutes les vérifications internes ont réussi. Chaque flèche et carré occupe une tuile de 8×8.
Sur CGB et FC, la flèche a une tige verte, un contour rouge et des détails bleus à la pointe ; le carré est vert. La transparence révèle le fond blanc du GB ou noir du FC. Le DMG remplace rouge, vert et bleu par gris clair, gris foncé et noir.
La rangée sous SCAN LIMIT commence en (8,128). Le programme soumet 11 sprites sur GB ou 9 sur FC, soit un de trop volontairement. Attendez 10 flèches visibles sur GB et 8 sur FC ; la dernière soumise est absente. Les vérifications du maximum logiciel et de l’avertissement doivent donner 11/9 et 1.


Commande de compilation
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-disasmImplémentation et source
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
Libère une entrée réservée, la masque et diminue le nombre d’entrées actives d’une unité. Un identifiant hors limites ou une entrée déjà libre ne produit aucun changement.
Syntaxe
void sprite_free(u8 id);Paramètres
idIdentifiant entre 0 et SPRITE_MAX-1 : par défaut 0..39 sur GB, 0..63 sur FC. Les identifiants hors limites sont ignorés.
Valeur renvoyée
Aucune (void).
Conditions et limites
Position, tuile, attributs et masquage modifient la copie de travail. Ils ne réservent aucune entrée et ne mettent pas immédiatement l’OAM à jour ; transférez l’image préparée avec sprite_flush_oam.
L’exemple utilise la bibliothèque GB complète. KQ_SPRITE_MINIMAL_RUNTIME retire de sprite.c sprite_free, sprite_set_pos, sprite_count_used, les deux requêtes de lignes, metasprite_draw et anim_update. Ne le définissez pas si vous utilisez ces fonctions.
Exemple d’utilisation
sprite_free(7);sprite_free(7);
sprite_example_expect(sprite_count_used()==7); // Repeated release is ignored.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’initialisation donne zéro réservation. Huit allocations renvoient 0..7. Masquer l’entrée 6 conserve 8 ; libérer deux fois la 7 laisse 7. Placer la paire en 10 et 11 porte le total à 9.
Ce programme présente allocation, positionnement, retournements, objets composés, superposition, animation et limite par ligne. Les deux chiffres en haut à droite doivent être 00 : toutes les vérifications internes ont réussi. Chaque flèche et carré occupe une tuile de 8×8.
NORMAL montre une flèche vers la droite en (88,16). FLIP X pointe à gauche en (88,32) ; FLIP Y retourne la flèche verticalement en (88,48). META place deux flèches en (88,64) et (96,64). OVERLAP place la flèche de (88,80) devant le carré de (92,80), visible à travers les pixels transparents. ANIMATION montre le carré en (88,96). Les zones (120,16) et (120,32) restent vides après masquage et libération de leurs entrées.
Sur CGB et FC, la flèche a une tige verte, un contour rouge et des détails bleus à la pointe ; le carré est vert. La transparence révèle le fond blanc du GB ou noir du FC. Le DMG remplace rouge, vert et bleu par gris clair, gris foncé et noir.
La rangée sous SCAN LIMIT commence en (8,128). Le programme soumet 11 sprites sur GB ou 9 sur FC, soit un de trop volontairement. Attendez 10 flèches visibles sur GB et 8 sur FC ; la dernière soumise est absente. Les vérifications du maximum logiciel et de l’avertissement doivent donner 11/9 et 1.


Commande de compilation
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-disasmImplémentation et source
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
Masque un sprite en modifiant sa position dans la copie de l’OAM. La réservation, la tuile et les attributs sont conservés ; une position visible suffit pour le réafficher.
Syntaxe
void sprite_hide(u8 id);Paramètres
idIdentifiant entre 0 et SPRITE_MAX-1 : par défaut 0..39 sur GB, 0..63 sur FC. Les identifiants hors limites sont ignorés.
Valeur renvoyée
Aucune (void).
Conditions et limites
Position, tuile, attributs et masquage modifient la copie de travail. Ils ne réservent aucune entrée et ne mettent pas immédiatement l’OAM à jour ; transférez l’image préparée avec sprite_flush_oam.
L’exemple utilise la bibliothèque GB complète. KQ_SPRITE_MINIMAL_RUNTIME retire de sprite.c sprite_free, sprite_set_pos, sprite_count_used, les deux requêtes de lignes, metasprite_draw et anim_update. Ne le définissez pas si vous utilisez ces fonctions.
Exemple d’utilisation
sprite_hide(6);
sprite_example_expect(sprite_count_used()==8); // Hiding retains allocation.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’initialisation donne zéro réservation. Huit allocations renvoient 0..7. Masquer l’entrée 6 conserve 8 ; libérer deux fois la 7 laisse 7. Placer la paire en 10 et 11 porte le total à 9.
Ce programme présente allocation, positionnement, retournements, objets composés, superposition, animation et limite par ligne. Les deux chiffres en haut à droite doivent être 00 : toutes les vérifications internes ont réussi. Chaque flèche et carré occupe une tuile de 8×8.
NORMAL montre une flèche vers la droite en (88,16). FLIP X pointe à gauche en (88,32) ; FLIP Y retourne la flèche verticalement en (88,48). META place deux flèches en (88,64) et (96,64). OVERLAP place la flèche de (88,80) devant le carré de (92,80), visible à travers les pixels transparents. ANIMATION montre le carré en (88,96). Les zones (120,16) et (120,32) restent vides après masquage et libération de leurs entrées.
Sur CGB et FC, la flèche a une tige verte, un contour rouge et des détails bleus à la pointe ; le carré est vert. La transparence révèle le fond blanc du GB ou noir du FC. Le DMG remplace rouge, vert et bleu par gris clair, gris foncé et noir.
La rangée sous SCAN LIMIT commence en (8,128). Le programme soumet 11 sprites sur GB ou 9 sur FC, soit un de trop volontairement. Attendez 10 flèches visibles sur GB et 8 sur FC ; la dernière soumise est absente. Les vérifications du maximum logiciel et de l’avertissement doivent donner 11/9 et 1.


Commande de compilation
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-disasmImplémentation et source
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
Réinitialise l’allocation des sprites et masque toutes les entrées dans la copie de travail de l’OAM. La hauteur logicielle passe à 8 pixels ; la taille matérielle et le transfert vers l’OAM se règlent séparément.
Syntaxe
void sprite_init();Valeur renvoyée
Aucune (void).
Conditions et limites
Sur GB, l’initialisation efface les quatre octets de chaque entrée et réinitialise l’installation de la routine DMA en HRAM. Gardez SPRITE_MAX=40, sauf si votre source DMA personnalisée fournit bien les 160 octets.
L’exemple utilise la bibliothèque GB complète. KQ_SPRITE_MINIMAL_RUNTIME retire de sprite.c sprite_free, sprite_set_pos, sprite_count_used, les deux requêtes de lignes, metasprite_draw et anim_update. Ne le définissez pas si vous utilisez ces fonctions.
Exemple d’utilisation
sprite_init();
sprite_example_expect(sprite_count_used()==0);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’initialisation donne zéro réservation. Huit allocations renvoient 0..7. Masquer l’entrée 6 conserve 8 ; libérer deux fois la 7 laisse 7. Placer la paire en 10 et 11 porte le total à 9.
Ce programme présente allocation, positionnement, retournements, objets composés, superposition, animation et limite par ligne. Les deux chiffres en haut à droite doivent être 00 : toutes les vérifications internes ont réussi. Chaque flèche et carré occupe une tuile de 8×8.
NORMAL montre une flèche vers la droite en (88,16). FLIP X pointe à gauche en (88,32) ; FLIP Y retourne la flèche verticalement en (88,48). META place deux flèches en (88,64) et (96,64). OVERLAP place la flèche de (88,80) devant le carré de (92,80), visible à travers les pixels transparents. ANIMATION montre le carré en (88,96). Les zones (120,16) et (120,32) restent vides après masquage et libération de leurs entrées.
Sur CGB et FC, la flèche a une tige verte, un contour rouge et des détails bleus à la pointe ; le carré est vert. La transparence révèle le fond blanc du GB ou noir du FC. Le DMG remplace rouge, vert et bleu par gris clair, gris foncé et noir.
La rangée sous SCAN LIMIT commence en (8,128). Le programme soumet 11 sprites sur GB ou 9 sur FC, soit un de trop volontairement. Attendez 10 flèches visibles sur GB et 8 sur FC ; la dernière soumise est absente. Les vérifications du maximum logiciel et de l’avertissement doivent donner 11/9 et 1.


Commande de compilation
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-disasmImplémentation et source
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
Estime le nombre maximal de sprites actifs présents sur une même ligne visible à partir des positions verticales suivies et de kq_sprite_height.
Syntaxe
u8 sprite_max_scanline_count();Valeur renvoyée
Octet non signé entre 0 et SPRITE_MAX.
Conditions et limites
Réglez kq_sprite_height sur la hauteur matérielle, 8 ou 16. L’estimation ignore transparence, visibilité horizontale et priorité. Sur FC, elle lit les coordonnées de la bibliothèque ; les modifications directes par les intrinsèques OAM n’y figurent pas.
L’exemple utilise la bibliothèque GB complète. KQ_SPRITE_MINIMAL_RUNTIME retire de sprite.c sprite_free, sprite_set_pos, sprite_count_used, les deux requêtes de lignes, metasprite_draw et anim_update. Ne le définissez pas si vous utilisez ces fonctions.
Exemple d’utilisation
sprite_example_expect(sprite_max_scanline_count()==SPRITE_EXAMPLE_LINE_COUNT);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
La rangée sous SCAN LIMIT commence en (8,128). Le programme soumet 11 sprites sur GB ou 9 sur FC, soit un de trop volontairement. Attendez 10 flèches visibles sur GB et 8 sur FC ; la dernière soumise est absente. Les vérifications du maximum logiciel et de l’avertissement doivent donner 11/9 et 1.
Ce programme présente allocation, positionnement, retournements, objets composés, superposition, animation et limite par ligne. Les deux chiffres en haut à droite doivent être 00 : toutes les vérifications internes ont réussi. Chaque flèche et carré occupe une tuile de 8×8.
NORMAL montre une flèche vers la droite en (88,16). FLIP X pointe à gauche en (88,32) ; FLIP Y retourne la flèche verticalement en (88,48). META place deux flèches en (88,64) et (96,64). OVERLAP place la flèche de (88,80) devant le carré de (92,80), visible à travers les pixels transparents. ANIMATION montre le carré en (88,96). Les zones (120,16) et (120,32) restent vides après masquage et libération de leurs entrées.
Sur CGB et FC, la flèche a une tige verte, un contour rouge et des détails bleus à la pointe ; le carré est vert. La transparence révèle le fond blanc du GB ou noir du FC. Le DMG remplace rouge, vert et bleu par gris clair, gris foncé et noir.


Commande de compilation
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-disasmImplémentation et source
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
Remplace tout l’octet d’attributs. Combinez les constantes de la plateforme pour choisir les retournements, la palette et la priorité par rapport au fond ; les bits absents sont remis à zéro.
Syntaxe
void sprite_set_flags(u8 id, u8 flags);Paramètres
idIdentifiant entre 0 et SPRITE_MAX-1 : par défaut 0..39 sur GB, 0..63 sur FC. Les identifiants hors limites sont ignorés.
flagsOctet complet d’attributs, construit avec les constantes SPRITE_FLAG_* de la plateforme. Combinez les indicateurs avec le OU binaire (|).
Valeur renvoyée
Aucune (void).
Conditions et limites
Position, tuile, attributs et masquage modifient la copie de travail. Ils ne réservent aucune entrée et ne mettent pas immédiatement l’OAM à jour ; transférez l’image préparée avec sprite_flush_oam.
Attributs GB : le bit 4 sélectionne OBP1 sur DMG ; 5/6 retournent X/Y ; 7 place le sprite derrière les pixels de fond d’indice non nul. Sur CGB, 0..2 choisissent la palette d’objets et 3 la banque VRAM des tuiles ; le bit de palette DMG ne choisit pas les couleurs natives CGB.
L’exemple utilise la bibliothèque GB complète. KQ_SPRITE_MINIMAL_RUNTIME retire de sprite.c sprite_free, sprite_set_pos, sprite_count_used, les deux requêtes de lignes, metasprite_draw et anim_update. Ne le définissez pas si vous utilisez ces fonctions.
Exemple d’utilisation
sprite_set_flags(1,SPRITE_FLAG_XFLIP);
sprite_set_flags(2,SPRITE_FLAG_YFLIP);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
NORMAL montre une flèche vers la droite en (88,16). FLIP X pointe à gauche en (88,32) ; FLIP Y retourne la flèche verticalement en (88,48). META place deux flèches en (88,64) et (96,64). OVERLAP place la flèche de (88,80) devant le carré de (92,80), visible à travers les pixels transparents. ANIMATION montre le carré en (88,96). Les zones (120,16) et (120,32) restent vides après masquage et libération de leurs entrées.
Ce programme présente allocation, positionnement, retournements, objets composés, superposition, animation et limite par ligne. Les deux chiffres en haut à droite doivent être 00 : toutes les vérifications internes ont réussi. Chaque flèche et carré occupe une tuile de 8×8.
Sur CGB et FC, la flèche a une tige verte, un contour rouge et des détails bleus à la pointe ; le carré est vert. La transparence révèle le fond blanc du GB ou noir du FC. Le DMG remplace rouge, vert et bleu par gris clair, gris foncé et noir.
La rangée sous SCAN LIMIT commence en (8,128). Le programme soumet 11 sprites sur GB ou 9 sur FC, soit un de trop volontairement. Attendez 10 flèches visibles sur GB et 8 sur FC ; la dernière soumise est absente. Les vérifications du maximum logiciel et de l’avertissement doivent donner 11/9 et 1.


Commande de compilation
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-disasmImplémentation et source
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
Déplace un sprite GB dans la copie de l’OAM à partir de coordonnées écran en pixels. La fonction ajoute les décalages matériels : 8 à X et 16 à Y.
Syntaxe
void sprite_set_pos(u8 id, u8 x, u8 y);Paramètres
idIdentifiant entre 0 et SPRITE_MAX-1 : par défaut 0..39 sur GB, 0..63 sur FC. Les identifiants hors limites sont ignorés.
xPosition horizontale en pixels, sous forme d’octet non signé ; ce n’est pas une coordonnée de tuile.
yCoordonnée Y écran en pixels. La fonction GB ajoute 16 avant de la stocker dans l’OAM.
Valeur renvoyée
Aucune (void).
Conditions et limites
Position, tuile, attributs et masquage modifient la copie de travail. Ils ne réservent aucune entrée et ne mettent pas immédiatement l’OAM à jour ; transférez l’image préparée avec sprite_flush_oam.
Les additions de coordonnées se font sur huit bits et rebouclent modulo 256, sans découpage aux limites de l’écran. Une entrée valide peut être modifiée même sans réservation.
L’exemple utilise la bibliothèque GB complète. KQ_SPRITE_MINIMAL_RUNTIME retire de sprite.c sprite_free, sprite_set_pos, sprite_count_used, les deux requêtes de lignes, metasprite_draw et anim_update. Ne le définissez pas si vous utilisez ces fonctions.
Exemple d’utilisation
sprite_set_pos(0,88,SPRITE_EXAMPLE_Y(16)); // Visible top-left: (88,16).Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
NORMAL montre une flèche vers la droite en (88,16). FLIP X pointe à gauche en (88,32) ; FLIP Y retourne la flèche verticalement en (88,48). META place deux flèches en (88,64) et (96,64). OVERLAP place la flèche de (88,80) devant le carré de (92,80), visible à travers les pixels transparents. ANIMATION montre le carré en (88,96). Les zones (120,16) et (120,32) restent vides après masquage et libération de leurs entrées.
Ce programme présente allocation, positionnement, retournements, objets composés, superposition, animation et limite par ligne. Les deux chiffres en haut à droite doivent être 00 : toutes les vérifications internes ont réussi. Chaque flèche et carré occupe une tuile de 8×8.
Sur CGB et FC, la flèche a une tige verte, un contour rouge et des détails bleus à la pointe ; le carré est vert. La transparence révèle le fond blanc du GB ou noir du FC. Le DMG remplace rouge, vert et bleu par gris clair, gris foncé et noir.
La rangée sous SCAN LIMIT commence en (8,128). Le programme soumet 11 sprites sur GB ou 9 sur FC, soit un de trop volontairement. Attendez 10 flèches visibles sur GB et 8 sur FC ; la dernière soumise est absente. Les vérifications du maximum logiciel et de l’avertissement doivent donner 11/9 et 1.


Commande de compilation
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-disasmImplémentation et source
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
Remplace le numéro de tuile d’une entrée OAM. Cette opération sélectionne un graphisme déjà présent en mémoire ; elle ne transfère aucun graphisme et ne réserve aucun sprite.
Syntaxe
void sprite_set_tile(u8 id, u8 tile);Paramètres
idIdentifiant entre 0 et SPRITE_MAX-1 : par défaut 0..39 sur GB, 0..63 sur FC. Les identifiants hors limites sont ignorés.
tileNuméro de tuile sur 8 bits. Chargez d’abord les graphismes. Les règles matérielles du mode 8×16 s’appliquent ; aucun ajustement pour les paires de tuiles n’est effectué.
Valeur renvoyée
Aucune (void).
Conditions et limites
Position, tuile, attributs et masquage modifient la copie de travail. Ils ne réservent aucune entrée et ne mettent pas immédiatement l’OAM à jour ; transférez l’image préparée avec sprite_flush_oam.
L’exemple utilise la bibliothèque GB complète. KQ_SPRITE_MINIMAL_RUNTIME retire de sprite.c sprite_free, sprite_set_pos, sprite_count_used, les deux requêtes de lignes, metasprite_draw et anim_update. Ne le définissez pas si vous utilisez ces fonctions.
Exemple d’utilisation
sprite_set_tile(5,129); // Select the green square beside ANIMATION.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Avec first_tile=128, deux images et deux appels par image, la première mise à jour renvoie la flèche 128 et la seconde le carré 129. Le carré près d’ANIMATION confirme l’application du résultat à l’OAM.
Ce programme présente allocation, positionnement, retournements, objets composés, superposition, animation et limite par ligne. Les deux chiffres en haut à droite doivent être 00 : toutes les vérifications internes ont réussi. Chaque flèche et carré occupe une tuile de 8×8.
NORMAL montre une flèche vers la droite en (88,16). FLIP X pointe à gauche en (88,32) ; FLIP Y retourne la flèche verticalement en (88,48). META place deux flèches en (88,64) et (96,64). OVERLAP place la flèche de (88,80) devant le carré de (92,80), visible à travers les pixels transparents. ANIMATION montre le carré en (88,96). Les zones (120,16) et (120,32) restent vides après masquage et libération de leurs entrées.
Sur CGB et FC, la flèche a une tige verte, un contour rouge et des détails bleus à la pointe ; le carré est vert. La transparence révèle le fond blanc du GB ou noir du FC. Le DMG remplace rouge, vert et bleu par gris clair, gris foncé et noir.
La rangée sous SCAN LIMIT commence en (8,128). Le programme soumet 11 sprites sur GB ou 9 sur FC, soit un de trop volontairement. Attendez 10 flèches visibles sur GB et 8 sur FC ; la dernière soumise est absente. Les vérifications du maximum logiciel et de l’avertissement doivent donner 11/9 et 1.


Commande de compilation
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-disasmImplémentation et source
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
Compare sprite_max_scanline_count à la limite par ligne : 10 sprites sur GB et 8 sur FC. C’est une estimation logicielle, sans lecture de l’indicateur matériel de dépassement.
Syntaxe
u8 sprite_warn_scanline_overflow();Valeur renvoyée
1 si l’estimation dépasse la limite par ligne, sinon 0.
Conditions et limites
Réglez kq_sprite_height sur la hauteur matérielle, 8 ou 16. L’estimation ignore transparence, visibilité horizontale et priorité. Sur FC, elle lit les coordonnées de la bibliothèque ; les modifications directes par les intrinsèques OAM n’y figurent pas.
L’exemple utilise la bibliothèque GB complète. KQ_SPRITE_MINIMAL_RUNTIME retire de sprite.c sprite_free, sprite_set_pos, sprite_count_used, les deux requêtes de lignes, metasprite_draw et anim_update. Ne le définissez pas si vous utilisez ces fonctions.
Exemple d’utilisation
sprite_example_expect(sprite_warn_scanline_overflow()==1);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
La rangée sous SCAN LIMIT commence en (8,128). Le programme soumet 11 sprites sur GB ou 9 sur FC, soit un de trop volontairement. Attendez 10 flèches visibles sur GB et 8 sur FC ; la dernière soumise est absente. Les vérifications du maximum logiciel et de l’avertissement doivent donner 11/9 et 1.
Ce programme présente allocation, positionnement, retournements, objets composés, superposition, animation et limite par ligne. Les deux chiffres en haut à droite doivent être 00 : toutes les vérifications internes ont réussi. Chaque flèche et carré occupe une tuile de 8×8.
NORMAL montre une flèche vers la droite en (88,16). FLIP X pointe à gauche en (88,32) ; FLIP Y retourne la flèche verticalement en (88,48). META place deux flèches en (88,64) et (96,64). OVERLAP place la flèche de (88,80) devant le carré de (92,80), visible à travers les pixels transparents. ANIMATION montre le carré en (88,96). Les zones (120,16) et (120,32) restent vides après masquage et libération de leurs entrées.
Sur CGB et FC, la flèche a une tige verte, un contour rouge et des détails bleus à la pointe ; le carré est vert. La transparence révèle le fond blanc du GB ou noir du FC. Le DMG remplace rouge, vert et bleu par gris clair, gris foncé et noir.


Commande de compilation
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-disasmImplémentation et source
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 — Sélection des sprites par priorité et rotation
sprite_order place les objets importants en premier et fait tourner l’ordre OAM à priorité égale. Il produit jusqu’à 40 objets parmi 255 candidats au plus, pour gérer la limite de dix par ligne. La bibliothèque sprite gère allocation et DMA ; sprite_order gère l’ordre de sélection.
Incluez sprite_order.h et compilez sprite_order.c une seule fois. Après initialisation, appelez chaque image begin, puis push pour chaque candidat, puis build. La bibliothèque d’ordre seule ne nécessite ni sprite.c ni définitions de variables globales.
Le matériel sélectionne les dix premiers objets croisant chaque ligne, dans l’ordre OAM. Placer d’abord les petites valeurs de priorité protège les objets importants sur une ligne chargée. La rotation ne garantit pas une fréquence d’affichage égale dans un même niveau. Si les objets prioritaires occupent les dix places, les autres restent invisibles sur cette ligne.
SpriteOrderOamEntry contient quatre octets : Y, X, tile et flags. Pour utiliser l’OAM en RAM de sprite.h, écrivez vers (SpriteOrderOamEntry*)kq_sprite_oam. Gardez SPRITE_MAX à 40 et ne mélangez pas les identités d’emplacement de l’allocateur avec la sortie réordonnée : build ne met pas ses comptes à jour.
sprite_order_begin
Vide le compteur de candidats pour une nouvelle image, en gardant stockage, hauteur et phase. Contrairement à une réinitialisation à chaque image, cela préserve la rotation.
Syntaxe
void sprite_order_begin(SpriteOrder* order);Paramètres
orderAdresse d’un
SpriteOrderappartenant à l’appelant. Initialisez-le avant utilisation et mettez-le à jour depuis le code principal.
Valeur renvoyée
Aucune valeur de retour. Un order nul est ignoré. Les anciens octets et l’OAM déjà construit ne sont pas effacés.
Conditions et limites
Incluez sprite_order.h et compilez sprite_order.c une seule fois. Après initialisation, appelez chaque image begin, puis push pour chaque candidat, puis build. La bibliothèque d’ordre seule ne nécessite ni sprite.c ni définitions de variables globales.
Le matériel sélectionne les dix premiers objets croisant chaque ligne, dans l’ordre OAM. Placer d’abord les petites valeurs de priorité protège les objets importants sur une ligne chargée. La rotation ne garantit pas une fréquence d’affichage égale dans un même niveau. Si les objets prioritaires occupent les dix places, les autres restent invisibles sur cette ligne.
Exemple d’utilisation
sprite_order_begin(&order_demo);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cette leçon place quatorze objets sur une ligne. Les deux losanges sous HIGH sont prioritaires ; les douze carrés sous NORMAL sont ordinaires. Sur CGB, les losanges sont rouges et les carrés bleus ; sur DMG, gris et noirs. Les deux losanges restent visibles, mais seulement huit carrés apparaissent. 0..B repère les positions : PHASE 04 montre 4..B ; PHASE 08 montre 8..B et 0..3. La version normale avance PHASE toutes les 60 attentes d’image. Les captures fixent la phase du même programme ; la version animée a aussi été vérifiée.



Commande de compilation
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-disasmImplémentation et source
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
Construit 160 octets d’OAM en RAM selon priorité et ordre cyclique. Cache les places inutilisées en les mettant à zéro, puis avance la phase suivante. Le stockage des candidats n’est pas réordonné.
Syntaxe
u8 sprite_order_build(SpriteOrder* order, SpriteOrderOamEntry* output, u8 limit);Paramètres
orderAdresse d’un
SpriteOrderappartenant à l’appelant. Initialisez-le avant utilisation et mettez-le à jour depuis le code principal.outputTableau inscriptible de 40
SpriteOrderOamEntry. La fonction écrit les 160 octets même si limit vaut zéro ou moins de 40.limitNombre maximal produit, de 0 à 40 ; au-delà, limité à 40. Limite l’OAM entier, pas chaque ligne.
Valeur renvoyée
Renvoie le nombre produit, de 0 à 40. Une file vide valide efface toutes les places et fixe phase=0. Sinon, normalise phase modulo count, utilise ce départ cyclique dans chaque niveau de priorité croissant, puis incrémente et reboucle phase. Une limite nulle avance encore la phase. order/output nul, état désactivé, hauteur invalide ou count>capacity renvoie zéro sans modifier sortie ni phase.
Conditions et limites
Le matériel sélectionne les dix premiers objets croisant chaque ligne, dans l’ordre OAM. Placer d’abord les petites valeurs de priorité protège les objets importants sur une ligne chargée. La rotation ne garantit pas une fréquence d’affichage égale dans un même niveau. Si les objets prioritaires occupent les dix places, les autres restent invisibles sur cette ligne.
L’argument priority règle l’ordre de sélection indépendamment de l’attribut derrière le fond. Sur DMG, les objets sélectionnés qui se chevauchent favorisent le plus petit X, puis l’ordre OAM en cas d’égalité. Le mode couleur CGB normal utilise OAM, mais une configuration de type DMG via OPRI reste applicable. La bibliothèque ne change pas ces règles matérielles.
SpriteOrderOamEntry contient quatre octets : Y, X, tile et flags. Pour utiliser l’OAM en RAM de sprite.h, écrivez vers (SpriteOrderOamEntry*)kq_sprite_oam. Gardez SPRITE_MAX à 40 et ne mélangez pas les identités d’emplacement de l’allocateur avec la sortie réordonnée : build ne met pas ses comptes à jour.
build écrit seulement en RAM. Fournissez un tableau de sortie de 160 octets sans chevauchement avec l’état ou les candidats. Un tampon DMA OAM doit commencer sur une frontière de 256 octets. Terminez la construction avant le transfert VBlank ; une interruption ne doit pas transférer un tampon incomplet. L’exemple utilise sprite_flush_oam.
Chaque ajout a un coût borné. La construction efface 160 octets d’OAM en RAM et parcourt le tableau de candidats au plus quatre fois, sans le trier ni utiliser de tampon de tri. Cela ne garantit pas que 255 candidats tiennent dans le budget d’une image ; ne soumettez que ceux nécessaires à la scène.
Exemple d’utilisation
order_demo_state[1]=sprite_order_build(&order_demo,(SpriteOrderOamEntry*)kq_sprite_oam,40);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cette leçon place quatorze objets sur une ligne. Les deux losanges sous HIGH sont prioritaires ; les douze carrés sous NORMAL sont ordinaires. Sur CGB, les losanges sont rouges et les carrés bleus ; sur DMG, gris et noirs. Les deux losanges restent visibles, mais seulement huit carrés apparaissent. 0..B repère les positions : PHASE 04 montre 4..B ; PHASE 08 montre 8..B et 0..3. La version normale avance PHASE toutes les 60 attentes d’image. Les captures fixent la phase du même programme ; la version animée a aussi été vérifiée.



Commande de compilation
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-disasmImplémentation et source
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
Associe le stockage des candidats à l’état d’ordre et remet à zéro compteur et phase de rotation. À utiliser au début d’une scène ou lors d’un changement de stockage.
Syntaxe
u8 sprite_order_init(SpriteOrder* order, SpriteOrderItem* items, u8 capacity, u8 height);Paramètres
orderAdresse d’un
SpriteOrderappartenant à l’appelant. Initialisez-le avant utilisation et mettez-le à jour depuis le code principal.itemsTableau
SpriteOrderIteminscriptible, cinq octets par entrée. Allouez capacity entrées et gardez le stockage valide pendant l’utilisation.capacityCapacité du tableau, de 1 à 255 entrées ; ni un nombre d’octets ni le nombre de places matérielles.
heightLa hauteur est commune à tous les objets. Passez 8 ou 16 selon le mode LCDC 8×8/8×16 ; la bibliothèque ne règle pas LCDC. En mode 8×16, le matériel ignore le bit bas du numéro de tuile.
Valeur renvoyée
Renvoie 1 en cas de succès, 0 si items est nul, capacité nulle, hauteur autre que 8/16 ou order nul. Si order existe, l’échec le désactive : items=NULL, capacity=count=phase=0, height=8. Le tableau reste intact.
Conditions et limites
Incluez sprite_order.h et compilez sprite_order.c une seule fois. Après initialisation, appelez chaque image begin, puis push pour chaque candidat, puis build. La bibliothèque d’ordre seule ne nécessite ni sprite.c ni définitions de variables globales.
Exemple d’utilisation
sprite_init();sprite_order_init(&order_demo,order_demo_items,14,8);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cette leçon place quatorze objets sur une ligne. Les deux losanges sous HIGH sont prioritaires ; les douze carrés sous NORMAL sont ordinaires. Sur CGB, les losanges sont rouges et les carrés bleus ; sur DMG, gris et noirs. Les deux losanges restent visibles, mais seulement huit carrés apparaissent. 0..B repère les positions : PHASE 04 montre 4..B ; PHASE 08 montre 8..B et 0..3. La version normale avance PHASE toutes les 60 attentes d’image. Les captures fixent la phase du même programme ; la version animée a aussi été vérifiée.



Commande de compilation
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-disasmImplémentation et source
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
Soumet un sprite croisant l’écran visible d’au moins un pixel. Les candidats entièrement hors écran sont rejetés avant de consommer une place OAM.
Syntaxe
u8 sprite_order_push(SpriteOrder* order, s16 x, s16 y, u8 tile, u8 flags, u8 priority);Paramètres
orderAdresse d’un
SpriteOrderappartenant à l’appelant. Initialisez-le avant utilisation et mettez-le à jour depuis le code principal.xX écran signé depuis le coin supérieur gauche. Les bords gauches −7..159 sont acceptés ; ≤−8 ou ≥160 est entièrement hors écran. Le stockage ajoute 8 pour les coordonnées OAM.
yY écran signé depuis le coin supérieur gauche. Plage acceptée : −7..143 pour hauteur 8, −15..143 pour hauteur 16. Le stockage ajoute 16 pour OAM.
tileNuméro de tuile de 0 à 255, stocké tel quel. Voir les notes de hauteur pour le mode 8×16.
flagsOctet d’attribut matériel stocké tel quel : retournements, priorité derrière le fond, palette DMG/CGB et banque VRAM CGB gardent leur sens matériel habituel.
priorityPriorité logicielle de sélection de 0 à 3, zéro en premier. À partir de quatre, la valeur est rejetée. Distincte de l’octet matériel flags.
Valeur renvoyée
Renvoie 1 et incrémente count si accepté. État nul/désactivé, hauteur invalide, stockage plein, priorité invalide ou objet entièrement hors écran : renvoie 0 sans changer items ni count.
Conditions et limites
La hauteur est commune à tous les objets. Passez 8 ou 16 selon le mode LCDC 8×8/8×16 ; la bibliothèque ne règle pas LCDC. En mode 8×16, le matériel ignore le bit bas du numéro de tuile.
Le matériel sélectionne les dix premiers objets croisant chaque ligne, dans l’ordre OAM. Placer d’abord les petites valeurs de priorité protège les objets importants sur une ligne chargée. La rotation ne garantit pas une fréquence d’affichage égale dans un même niveau. Si les objets prioritaires occupent les dix places, les autres restent invisibles sur cette ligne.
L’argument priority règle l’ordre de sélection indépendamment de l’attribut derrière le fond. Sur DMG, les objets sélectionnés qui se chevauchent favorisent le plus petit X, puis l’ordre OAM en cas d’égalité. Le mode couleur CGB normal utilise OAM, mais une configuration de type DMG via OPRI reste applicable. La bibliothèque ne change pas ces règles matérielles.
Exemple d’utilisation
sprite_order_push(&order_demo,8,64,128,0,0);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Cette leçon place quatorze objets sur une ligne. Les deux losanges sous HIGH sont prioritaires ; les douze carrés sous NORMAL sont ordinaires. Sur CGB, les losanges sont rouges et les carrés bleus ; sur DMG, gris et noirs. Les deux losanges restent visibles, mais seulement huit carrés apparaissent. 0..B repère les positions : PHASE 04 montre 4..B ; PHASE 08 montre 8..B et 0..3. La version normale avance PHASE toutes les 60 attentes d’image. Les captures fixent la phase du même programme ; la version animée a aussi été vérifiée.



Commande de compilation
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-disasmImplémentation et source
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 — Démarrage, compteurs d'images, attentes et interruptions
Gère le nombre d’attentes de trame, les fonctions de rappel après attente et les interruptions CPU masquables.
gb_disable_interrupts
gb_disable_interrupts est un alias de system_disable_interrupts. Désactive les interruptions CPU sur GB.
Désactive les interruptions masquables du processeur.
Syntaxe
void gb_disable_interrupts();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
L’en-tête définit une macro objet qui se développe en nom d’implémentation. Arguments, résultats et accès à l’état sont identiques à ceux de la cible ; l’alias n’ajoute aucun état ni traitement distinct. Utilisez input.h/input.c pour les entrées ou system.h/system.c pour les services d’images, comme dans l’exemple complet et sa commande de compilation.
Gardez les mises à jour protégées aussi courtes que possible et rétablissez ensuite les interruptions de manière appropriée. Le masquage des interruptions est distinct des conditions requises par une routine d’attente de trame.
Sur GB, l’attente se termine immédiatement si le LCD est éteint, mais la fonction enveloppante incrémente tout de même son compteur et appelle sa fonction de rappel. L’initialisation seule ne configure ni le LCD ni les sources d’interruption.
Compilez cet exemple complet avec l’ABI Legacy par défaut. Ses rappels utilisent des appels par pointeur de fonction, non pris en charge et refusés par le compilateur avec --abi=stack. La même restriction s’applique aux alias.
Exemple d’utilisation
gb_disable_interrupts();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple associe désactivation et réactivation. Des programmes de vérification dédiés examinent aussi l’état des interruptions du processeur.


Commande de compilation
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=64kImplémentation et source
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 est un alias de system_enable_interrupts. Active les interruptions CPU sur GB.
Active les interruptions masquables du processeur.
Syntaxe
void gb_enable_interrupts();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
L’en-tête définit une macro objet qui se développe en nom d’implémentation. Arguments, résultats et accès à l’état sont identiques à ceux de la cible ; l’alias n’ajoute aucun état ni traitement distinct. Utilisez input.h/input.c pour les entrées ou system.h/system.c pour les services d’images, comme dans l’exemple complet et sa commande de compilation.
Préparez les sources d’interruption et leurs gestionnaires avant de les activer. Sur FC, cette opération est indépendante de l’activation ou de la désactivation de la NMI.
Sur GB, l’attente se termine immédiatement si le LCD est éteint, mais la fonction enveloppante incrémente tout de même son compteur et appelle sa fonction de rappel. L’initialisation seule ne configure ni le LCD ni les sources d’interruption.
Compilez cet exemple complet avec l’ABI Legacy par défaut. Ses rappels utilisent des appels par pointeur de fonction, non pris en charge et refusés par le compilateur avec --abi=stack. La même restriction s’applique aux alias.
Exemple d’utilisation
gb_enable_interrupts();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple rétablit les interruptions. Le programme FC désactive d’abord les sources IRQ de trame APU et DMC pour éviter de traiter en boucle une IRQ non acquittée.


Commande de compilation
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=64kImplémentation et source
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 est un alias de system_get_frame. Lit le compteur logiciel 16 bits des attentes terminées par la fonction d’encapsulation.
Lit le compteur sur 16 bits de la fonction d’attente de trame.
Syntaxe
u16 gb_frame_count();Valeur renvoyée
Renvoie la valeur courante du compteur, de 0 à 65535.
Conditions et limites
L’en-tête définit une macro objet qui se développe en nom d’implémentation. Arguments, résultats et accès à l’état sont identiques à ceux de la cible ; l’alias n’ajoute aucun état ni traitement distinct. Utilisez input.h/input.c pour les entrées ou system.h/system.c pour les services d’images, comme dans l’exemple complet et sa commande de compilation.
Le compteur dénombre les attentes effectuées par cette fonction d’encapsulation ; il ne mesure pas automatiquement les trames réellement écoulées sur le matériel. Il revient à zéro après débordement sur 16 bits.
Sur GB, l’attente se termine immédiatement si le LCD est éteint, mais la fonction enveloppante incrémente tout de même son compteur et appelle sa fonction de rappel. L’initialisation seule ne configure ni le LCD ni les sources d’interruption.
Compilez cet exemple complet avec l’ABI Legacy par défaut. Ses rappels utilisent des appels par pointeur de fonction, non pris en charge et refusés par le compilateur avec --abi=stack. La même restriction s’applique aux alias.
Exemple d’utilisation
result[3]=gb_frame_count();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple lit trois après trois attentes. Pour tester le rebouclage, il fixe explicitement le compteur à 65535 et vérifie qu’il vaut zéro après l’attente suivante.


Commande de compilation
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=64kImplémentation et source
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 est un alias de system_init. Réinitialise le compteur logiciel d’images et l’enregistrement du rappel.
Initialise la gestion des trames en remettant le compteur à zéro et en supprimant la fonction de rappel enregistrée.
Syntaxe
void gb_init();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
L’en-tête définit une macro objet qui se développe en nom d’implémentation. Arguments, résultats et accès à l’état sont identiques à ceux de la cible ; l’alias n’ajoute aucun état ni traitement distinct. Utilisez input.h/input.c pour les entrées ou system.h/system.c pour les services d’images, comme dans l’exemple complet et sa commande de compilation.
Le compteur dénombre les attentes effectuées par cette fonction d’encapsulation ; il ne mesure pas automatiquement les trames réellement écoulées sur le matériel. Il revient à zéro après débordement sur 16 bits.
Sur GB, l’attente se termine immédiatement si le LCD est éteint, mais la fonction enveloppante incrémente tout de même son compteur et appelle sa fonction de rappel. L’initialisation seule ne configure ni le LCD ni les sources d’interruption.
Compilez cet exemple complet avec l’ABI Legacy par défaut. Ses rappels utilisent des appels par pointeur de fonction, non pris en charge et refusés par le compilateur avec --abi=stack. La même restriction s’applique aux alias.
Exemple d’utilisation
gb_init();result[0]=gb_frame_count();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple vérifie que le numéro de trame initial est nul avant d’enregistrer sa fonction de rappel.


Commande de compilation
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=64kImplémentation et source
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 est un alias de system_set_vblank_callback. Enregistre ou supprime le rappel exécuté de manière synchrone après une attente d’image.
Enregistre, remplace ou supprime la fonction appelée après une attente de trame.
Syntaxe
void gb_set_vblank_callback(SystemCallback callback);Paramètres
callbackFonction à appeler ; 0 supprime le rappel.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
L’en-tête définit une macro objet qui se développe en nom d’implémentation. Arguments, résultats et accès à l’état sont identiques à ceux de la cible ; l’alias n’ajoute aucun état ni traitement distinct. Utilisez input.h/input.c pour les entrées ou system.h/system.c pour les services d’images, comme dans l’exemple complet et sa commande de compilation.
Il s’agit d’un pointeur ordinaire vers une fonction sans argument ni valeur de retour. Il ne contient pas de numéro de banque ; le code cible doit rester mappé tant qu’un appel est possible.
Sur GB, l’attente se termine immédiatement si le LCD est éteint, mais la fonction enveloppante incrémente tout de même son compteur et appelle sa fonction de rappel. L’initialisation seule ne configure ni le LCD ni les sources d’interruption.
Compilez cet exemple complet avec l’ABI Legacy par défaut. Ses rappels utilisent des appels par pointeur de fonction, non pris en charge et refusés par le compilateur avec --abi=stack. La même restriction s’applique aux alias.
Exemple d’utilisation
gb_set_vblank_callback(on_frame);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Après trois appels du rappel, enregistrer 0 le désactive. L’attente suivante porte le compteur de trames à quatre, tandis que le nombre d’appels reste trois.


Commande de compilation
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=64kImplémentation et source
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 est un alias de system_wait_vblank. Attend la limite d’image, incrémente le compteur logiciel et appelle le rappel enregistré.
Attend la trame suivante, incrémente le compteur, puis appelle la fonction de rappel enregistrée.
Syntaxe
void gb_wait_vblank();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
L’en-tête définit une macro objet qui se développe en nom d’implémentation. Arguments, résultats et accès à l’état sont identiques à ceux de la cible ; l’alias n’ajoute aucun état ni traitement distinct. Utilisez input.h/input.c pour les entrées ou system.h/system.c pour les services d’images, comme dans l’exemple complet et sa commande de compilation.
Le rappel s’exécute de manière synchrone à l’intérieur de cette fonction ; son enregistrement n’installe pas de gestionnaire d’interruption. Le compteur dénombre les attentes effectuées par cette fonction d’encapsulation, sans mesurer automatiquement les trames matérielles écoulées. Il revient à zéro après débordement sur 16 bits.
Sur GB, l’attente se termine immédiatement si le LCD est éteint, mais la fonction enveloppante incrémente tout de même son compteur et appelle sa fonction de rappel. L’initialisation seule ne configure ni le LCD ni les sources d’interruption.
Compilez cet exemple complet avec l’ABI Legacy par défaut. Ses rappels utilisent des appels par pointeur de fonction, non pris en charge et refusés par le compilateur avec --abi=stack. La même restriction s’applique aux alias.
Exemple d’utilisation
gb_wait_vblank();gb_wait_vblank();gb_wait_vblank();result[1]=frame_calls;result[2]=frame_seen;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Trois attentes déclenchent trois appels du rappel, et la dernière valeur du compteur observée dans celui-ci est trois.


Commande de compilation
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=64kImplémentation et source
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
Désactive les interruptions masquables du processeur.
Syntaxe
void system_disable_interrupts();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Gardez les mises à jour protégées aussi courtes que possible et rétablissez ensuite les interruptions de manière appropriée. Le masquage des interruptions est distinct des conditions requises par une routine d’attente de trame.
Sur GB, l’attente se termine immédiatement si le LCD est éteint, mais la fonction enveloppante incrémente tout de même son compteur et appelle sa fonction de rappel. L’initialisation seule ne configure ni le LCD ni les sources d’interruption.
Compilez cet exemple complet avec l’ABI Legacy par défaut. Ses rappels utilisent des appels par pointeur de fonction, non pris en charge et refusés par le compilateur avec --abi=stack. La même restriction s’applique aux alias.
Exemple d’utilisation
system_disable_interrupts();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple associe désactivation et réactivation. Des programmes de vérification dédiés examinent aussi l’état des interruptions du processeur.


Commande de compilation
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=64kImplémentation et source
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
Active les interruptions masquables du processeur.
Syntaxe
void system_enable_interrupts();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Préparez les sources d’interruption et leurs gestionnaires avant de les activer. Sur FC, cette opération est indépendante de l’activation ou de la désactivation de la NMI.
Sur GB, l’attente se termine immédiatement si le LCD est éteint, mais la fonction enveloppante incrémente tout de même son compteur et appelle sa fonction de rappel. L’initialisation seule ne configure ni le LCD ni les sources d’interruption.
Compilez cet exemple complet avec l’ABI Legacy par défaut. Ses rappels utilisent des appels par pointeur de fonction, non pris en charge et refusés par le compilateur avec --abi=stack. La même restriction s’applique aux alias.
Exemple d’utilisation
system_enable_interrupts();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple rétablit les interruptions. Le programme FC désactive d’abord les sources IRQ de trame APU et DMC pour éviter de traiter en boucle une IRQ non acquittée.


Commande de compilation
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=64kImplémentation et source
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
Lit le compteur sur 16 bits de la fonction d’attente de trame.
Syntaxe
u16 system_get_frame();Valeur renvoyée
Renvoie la valeur courante du compteur, de 0 à 65535.
Conditions et limites
Le compteur dénombre les attentes effectuées par cette fonction d’encapsulation ; il ne mesure pas automatiquement les trames réellement écoulées sur le matériel. Il revient à zéro après débordement sur 16 bits.
Sur GB, l’attente se termine immédiatement si le LCD est éteint, mais la fonction enveloppante incrémente tout de même son compteur et appelle sa fonction de rappel. L’initialisation seule ne configure ni le LCD ni les sources d’interruption.
Compilez cet exemple complet avec l’ABI Legacy par défaut. Ses rappels utilisent des appels par pointeur de fonction, non pris en charge et refusés par le compilateur avec --abi=stack. La même restriction s’applique aux alias.
Exemple d’utilisation
result[3]=system_get_frame();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple lit trois après trois attentes. Pour tester le rebouclage, il fixe explicitement le compteur à 65535 et vérifie qu’il vaut zéro après l’attente suivante.


Commande de compilation
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=64kImplémentation et source
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
Lit les huit bits de poids faible du compteur de trames pour gérer de courts intervalles répétitifs.
Syntaxe
u8 system_get_frame8();Valeur renvoyée
Renvoie l’octet de poids faible, de 0 à 255.
Conditions et limites
Le compteur dénombre les attentes effectuées par cette fonction d’encapsulation ; il ne mesure pas automatiquement les trames réellement écoulées sur le matériel. Il revient à zéro après débordement sur 16 bits.
Sur GB, l’attente se termine immédiatement si le LCD est éteint, mais la fonction enveloppante incrémente tout de même son compteur et appelle sa fonction de rappel. L’initialisation seule ne configure ni le LCD ni les sources d’interruption.
Compilez cet exemple complet avec l’ABI Legacy par défaut. Ses rappels utilisent des appels par pointeur de fonction, non pris en charge et refusés par le compilateur avec --abi=stack. La même restriction s’applique aux alias.
Exemple d’utilisation
result[4]=system_get_frame8();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple lit trois après trois attentes, puis zéro lorsque le compteur sur 16 bits revient à zéro.


Commande de compilation
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=64kImplémentation et source
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
Initialise la gestion des trames en remettant le compteur à zéro et en supprimant la fonction de rappel enregistrée.
Syntaxe
void system_init();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Le compteur dénombre les attentes effectuées par cette fonction d’encapsulation ; il ne mesure pas automatiquement les trames réellement écoulées sur le matériel. Il revient à zéro après débordement sur 16 bits.
Sur GB, l’attente se termine immédiatement si le LCD est éteint, mais la fonction enveloppante incrémente tout de même son compteur et appelle sa fonction de rappel. L’initialisation seule ne configure ni le LCD ni les sources d’interruption.
Compilez cet exemple complet avec l’ABI Legacy par défaut. Ses rappels utilisent des appels par pointeur de fonction, non pris en charge et refusés par le compilateur avec --abi=stack. La même restriction s’applique aux alias.
Exemple d’utilisation
system_init();result[0]=system_get_frame();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
L’exemple vérifie que le numéro de trame initial est nul avant d’enregistrer sa fonction de rappel.


Commande de compilation
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=64kImplémentation et source
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
Enregistre, remplace ou supprime la fonction appelée après une attente de trame.
Syntaxe
void system_set_vblank_callback(SystemCallback callback);Paramètres
callbackFonction à appeler ; 0 supprime le rappel.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Il s’agit d’un pointeur ordinaire vers une fonction sans argument ni valeur de retour. Il ne contient pas de numéro de banque ; le code cible doit rester mappé tant qu’un appel est possible.
Sur GB, l’attente se termine immédiatement si le LCD est éteint, mais la fonction enveloppante incrémente tout de même son compteur et appelle sa fonction de rappel. L’initialisation seule ne configure ni le LCD ni les sources d’interruption.
Compilez cet exemple complet avec l’ABI Legacy par défaut. Ses rappels utilisent des appels par pointeur de fonction, non pris en charge et refusés par le compilateur avec --abi=stack. La même restriction s’applique aux alias.
Exemple d’utilisation
system_set_vblank_callback(on_frame);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Après trois appels du rappel, enregistrer 0 le désactive. L’attente suivante porte le compteur de trames à quatre, tandis que le nombre d’appels reste trois.


Commande de compilation
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=64kImplémentation et source
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
Attend la trame suivante, incrémente le compteur, puis appelle la fonction de rappel enregistrée.
Syntaxe
void system_wait_vblank();Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Le rappel s’exécute de manière synchrone à l’intérieur de cette fonction ; son enregistrement n’installe pas de gestionnaire d’interruption. Le compteur dénombre les attentes effectuées par cette fonction d’encapsulation, sans mesurer automatiquement les trames matérielles écoulées. Il revient à zéro après débordement sur 16 bits.
Sur GB, l’attente se termine immédiatement si le LCD est éteint, mais la fonction enveloppante incrémente tout de même son compteur et appelle sa fonction de rappel. L’initialisation seule ne configure ni le LCD ni les sources d’interruption.
Compilez cet exemple complet avec l’ABI Legacy par défaut. Ses rappels utilisent des appels par pointeur de fonction, non pris en charge et refusés par le compilateur avec --abi=stack. La même restriction s’applique aux alias.
Exemple d’utilisation
system_wait_vblank();system_wait_vblank();system_wait_vblank();result[1]=frame_calls;result[2]=frame_seen;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Trois attentes déclenchent trois appels du rappel, et la dernière valeur du compteur observée dans celui-ci est trois.


Commande de compilation
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=64kImplémentation et source
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 — Mises à jour et transferts VRAM en file
Initialise à vide la file des écritures VRAM différées et efface son indicateur de débordement. Ne vide pas l’écran, ne charge pas de graphismes et n’alloue pas de VRAM physique.
GB compte des emplacements d’ordre : la capacité par défaut est 32. Chaque fonction d’ajout en utilise un, même pour un transfert long ou nul. Définissez VRAM_QUEUE_MAX uniformément dans toutes les unités, entre 1 et 255. Une file vide a used=0 et free=capacity.
Attend avec __wait_vblank, puis appelle vram_flush_now. Convient à un lot modéré de changements d’écran. Une seule attente n’impose pas de budget de transfert et ne garantit pas la fin de tout le lot dans un VBlank.
Coordonnez la construction et la consommation de la file. N’ajoutez rien pendant son exécution par une interruption, ne modifiez pas directement ses compteurs et n’écrasez pas involontairement les sources conservées. Ces API n’offrent ni verrouillage ni double tampon. La capacité concerne le tampon d’ordres, pas les octets libres de VRAM physique.
vram_clear_queue
Abandonne les commandes VRAM en attente et efface le débordement sans effectuer les écritures.
Syntaxe
void vram_clear_queue();Valeur renvoyée
Aucune (void).
Conditions et limites
GB compte des emplacements d’ordre : la capacité par défaut est 32. Chaque fonction d’ajout en utilise un, même pour un transfert long ou nul. Définissez VRAM_QUEUE_MAX uniformément dans toutes les unités, entre 1 et 255. Une file vide a used=0 et free=capacity.
Coordonnez la construction et la consommation de la file. N’ajoutez rien pendant son exécution par une interruption, ne modifiez pas directement ses compteurs et n’écrasez pas involontairement les sources conservées. Ces API n’offrent ni verrouillage ni double tampon. La capacité concerne le tampon d’ordres, pas les octets libres de VRAM physique.
Exemple d’utilisation
vram_clear_queue();
if (vram_get_queue_used()!=0 || vram_get_overflowed()!=0) failures++;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le programme complet présente les écritures différées, le suivi de capacité et la reprise après débordement. Sept appels de dessin occupent 7 des 32 emplacements sur GB, ou 52 des 128 octets sur FC : CAPACITY/USED/FREE affiche 032/007/025 ou 128/052/076. AFTER FLUSH et FAILED CHECKS doivent valoir 000, et OVERFLOW SEEN, 001. Un ajout volontaire à une file pleine teste l’indicateur : ni la lecture ni l’exécution ne l’effacent, contrairement à la remise à zéro de la file. Sur FC, l’exécution directe sans validation doit laisser la file intacte.
Les coordonnées sont en pixels depuis le coin supérieur gauche. On attend des carrés pleins de 8 × 8 en (16,16) et (32,16), un rectangle plein de 32 × 24 en (16,32) et une barre horizontale de 40 × 8 en (80,64). L’écriture finale en VBlank ajoute un carré de 8 × 8 en (144,80). L’écriture annulée en (144,24) doit laisser cette case vide. Le DMG affiche des formes noires sur blanc, le CGB des formes rouges, bleues et vertes sur blanc, et le FC des formes rouges, bleues et vertes sur noir. Ces images d’émulateur ne constituent pas une validation sur matériel réel.
Trois motifs originaux de 8 × 8 distinguent les copies : le 1 est plein, le 2 remplit les quatre colonnes de gauche et le 3 est un triangle aligné à gauche, large d’un pixel en haut et de huit en bas. Le bloc de 3 × 2 tuiles en (80,32) doit afficher [1,2,3] / [3,0,2], où 0 est vide. Son premier octet change après l’ajout ; la tuile pleine en haut à gauche prouve que le pointeur est conservé. La copie en (16,64) affiche [1,2,3] ; l’alias tiles en (48,64), [2,3]. Leurs tailles respectives sont de 24 × 16, 24 × 8 et 16 × 8 pixels.
Sur CGB, les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank sont rouges. Le rectangle de 32 × 24 et la copie de deux motifs sont bleus. Le bloc de 3 × 2 tuiles et la barre de 40 × 8 sont verts. Le texte reste noir sur blanc. La couleur de chaque pixel dessiné est vérifiée en plus de la géométrie.


Commande de compilation
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-disasmImplémentation et source
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
Attend avec __wait_vblank, puis appelle vram_flush_now. Convient à un lot modéré de changements d’écran. Une seule attente n’impose pas de budget de transfert et ne garantit pas la fin de tout le lot dans un VBlank.
Syntaxe
void vram_flush();Valeur renvoyée
Aucune (void).
Conditions et limites
GB compte des emplacements d’ordre : la capacité par défaut est 32. Chaque fonction d’ajout en utilise un, même pour un transfert long ou nul. Définissez VRAM_QUEUE_MAX uniformément dans toutes les unités, entre 1 et 255. Une file vide a used=0 et free=capacity.
Coordonnez la construction et la consommation de la file. N’ajoutez rien pendant son exécution par une interruption, ne modifiez pas directement ses compteurs et n’écrasez pas involontairement les sources conservées. Ces API n’offrent ni verrouillage ni double tampon. La capacité concerne le tampon d’ordres, pas les octets libres de VRAM physique.
Adresse de destination en octets dans la VRAM (0x8000–0x9FFF), dans la banque sélectionnée à l’exécution. Le transfert est contigu, sans saut de ligne. Toute la plage doit être valide. LCD actif, les chemins d’écriture sûrs peuvent activer les interruptions ; ils ne préservent pas un état d’appel où elles étaient désactivées.
Exemple d’utilisation
vram_flush(); // One small write through the VBlank/NMI path.
if (vram_get_queue_used()!=0) failures++;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le programme complet présente les écritures différées, le suivi de capacité et la reprise après débordement. Sept appels de dessin occupent 7 des 32 emplacements sur GB, ou 52 des 128 octets sur FC : CAPACITY/USED/FREE affiche 032/007/025 ou 128/052/076. AFTER FLUSH et FAILED CHECKS doivent valoir 000, et OVERFLOW SEEN, 001. Un ajout volontaire à une file pleine teste l’indicateur : ni la lecture ni l’exécution ne l’effacent, contrairement à la remise à zéro de la file. Sur FC, l’exécution directe sans validation doit laisser la file intacte.
Les coordonnées sont en pixels depuis le coin supérieur gauche. On attend des carrés pleins de 8 × 8 en (16,16) et (32,16), un rectangle plein de 32 × 24 en (16,32) et une barre horizontale de 40 × 8 en (80,64). L’écriture finale en VBlank ajoute un carré de 8 × 8 en (144,80). L’écriture annulée en (144,24) doit laisser cette case vide. Le DMG affiche des formes noires sur blanc, le CGB des formes rouges, bleues et vertes sur blanc, et le FC des formes rouges, bleues et vertes sur noir. Ces images d’émulateur ne constituent pas une validation sur matériel réel.
Trois motifs originaux de 8 × 8 distinguent les copies : le 1 est plein, le 2 remplit les quatre colonnes de gauche et le 3 est un triangle aligné à gauche, large d’un pixel en haut et de huit en bas. Le bloc de 3 × 2 tuiles en (80,32) doit afficher [1,2,3] / [3,0,2], où 0 est vide. Son premier octet change après l’ajout ; la tuile pleine en haut à gauche prouve que le pointeur est conservé. La copie en (16,64) affiche [1,2,3] ; l’alias tiles en (48,64), [2,3]. Leurs tailles respectives sont de 24 × 16, 24 × 8 et 16 × 8 pixels.
Sur CGB, les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank sont rouges. Le rectangle de 32 × 24 et la copie de deux motifs sont bleus. Le bloc de 3 × 2 tuiles et la barre de 40 × 8 sont verts. Le texte reste noir sur blanc. La couleur de chaque pixel dessiné est vérifiée en plus de la géométrie.


Commande de compilation
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-disasmImplémentation et source
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
Exécute tous les ordres dans leur ordre d’ajout, puis remet le nombre utilisé à zéro. N’attend pas elle-même le VBlank. LCD actif, les fonctions intrinsèques sûres attendent les périodes d’écriture, mais une grande file peut s’étendre sur plusieurs lignes ou images. L’indicateur de débordement reste mémorisé.
Syntaxe
void vram_flush_now();Valeur renvoyée
Aucune (void).
Conditions et limites
GB compte des emplacements d’ordre : la capacité par défaut est 32. Chaque fonction d’ajout en utilise un, même pour un transfert long ou nul. Définissez VRAM_QUEUE_MAX uniformément dans toutes les unités, entre 1 et 255. Une file vide a used=0 et free=capacity.
Coordonnez la construction et la consommation de la file. N’ajoutez rien pendant son exécution par une interruption, ne modifiez pas directement ses compteurs et n’écrasez pas involontairement les sources conservées. Ces API n’offrent ni verrouillage ni double tampon. La capacité concerne le tampon d’ordres, pas les octets libres de VRAM physique.
Adresse de destination en octets dans la VRAM (0x8000–0x9FFF), dans la banque sélectionnée à l’exécution. Le transfert est contigu, sans saut de ligne. Toute la plage doit être valide. LCD actif, les chemins d’écriture sûrs peuvent activer les interruptions ; ils ne préservent pas un état d’appel où elles étaient désactivées.
Exemple d’utilisation
// 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++;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le programme complet présente les écritures différées, le suivi de capacité et la reprise après débordement. Sept appels de dessin occupent 7 des 32 emplacements sur GB, ou 52 des 128 octets sur FC : CAPACITY/USED/FREE affiche 032/007/025 ou 128/052/076. AFTER FLUSH et FAILED CHECKS doivent valoir 000, et OVERFLOW SEEN, 001. Un ajout volontaire à une file pleine teste l’indicateur : ni la lecture ni l’exécution ne l’effacent, contrairement à la remise à zéro de la file. Sur FC, l’exécution directe sans validation doit laisser la file intacte.
Les coordonnées sont en pixels depuis le coin supérieur gauche. On attend des carrés pleins de 8 × 8 en (16,16) et (32,16), un rectangle plein de 32 × 24 en (16,32) et une barre horizontale de 40 × 8 en (80,64). L’écriture finale en VBlank ajoute un carré de 8 × 8 en (144,80). L’écriture annulée en (144,24) doit laisser cette case vide. Le DMG affiche des formes noires sur blanc, le CGB des formes rouges, bleues et vertes sur blanc, et le FC des formes rouges, bleues et vertes sur noir. Ces images d’émulateur ne constituent pas une validation sur matériel réel.
Trois motifs originaux de 8 × 8 distinguent les copies : le 1 est plein, le 2 remplit les quatre colonnes de gauche et le 3 est un triangle aligné à gauche, large d’un pixel en haut et de huit en bas. Le bloc de 3 × 2 tuiles en (80,32) doit afficher [1,2,3] / [3,0,2], où 0 est vide. Son premier octet change après l’ajout ; la tuile pleine en haut à gauche prouve que le pointeur est conservé. La copie en (16,64) affiche [1,2,3] ; l’alias tiles en (48,64), [2,3]. Leurs tailles respectives sont de 24 × 16, 24 × 8 et 16 × 8 pixels.
Sur CGB, les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank sont rouges. Le rectangle de 32 × 24 et la copie de deux motifs sont bleus. Le bloc de 3 × 2 tuiles et la barre de 40 × 8 sont verts. Le texte reste noir sur blanc. La couleur de chaque pixel dessiné est vérifiée en plus de la géométrie.


Commande de compilation
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-disasmImplémentation et source
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
Lit le drapeau de débordement sans l’effacer ; il peut conserver un échec antérieur.
Syntaxe
u8 vram_get_overflowed();Valeur renvoyée
0 si aucun débordement n’est mémorisé ; 1 après un ajout rejeté, jusqu’à une remise à zéro explicite. L’exécution de la file ne l’efface pas.
Conditions et limites
GB compte des emplacements d’ordre : la capacité par défaut est 32. Chaque fonction d’ajout en utilise un, même pour un transfert long ou nul. Définissez VRAM_QUEUE_MAX uniformément dans toutes les unités, entre 1 et 255. Une file vide a used=0 et free=capacity.
Coordonnez la construction et la consommation de la file. N’ajoutez rien pendant son exécution par une interruption, ne modifiez pas directement ses compteurs et n’écrasez pas involontairement les sources conservées. Ces API n’offrent ni verrouillage ni double tampon. La capacité concerne le tampon d’ordres, pas les octets libres de VRAM physique.
Exemple d’utilisation
overflow_seen=vram_get_overflowed();
if (overflow_seen!=1) failures++;
// Reading the latch again does not clear it.
if (vram_get_overflowed()!=1) failures++;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le programme complet présente les écritures différées, le suivi de capacité et la reprise après débordement. Sept appels de dessin occupent 7 des 32 emplacements sur GB, ou 52 des 128 octets sur FC : CAPACITY/USED/FREE affiche 032/007/025 ou 128/052/076. AFTER FLUSH et FAILED CHECKS doivent valoir 000, et OVERFLOW SEEN, 001. Un ajout volontaire à une file pleine teste l’indicateur : ni la lecture ni l’exécution ne l’effacent, contrairement à la remise à zéro de la file. Sur FC, l’exécution directe sans validation doit laisser la file intacte.
Les coordonnées sont en pixels depuis le coin supérieur gauche. On attend des carrés pleins de 8 × 8 en (16,16) et (32,16), un rectangle plein de 32 × 24 en (16,32) et une barre horizontale de 40 × 8 en (80,64). L’écriture finale en VBlank ajoute un carré de 8 × 8 en (144,80). L’écriture annulée en (144,24) doit laisser cette case vide. Le DMG affiche des formes noires sur blanc, le CGB des formes rouges, bleues et vertes sur blanc, et le FC des formes rouges, bleues et vertes sur noir. Ces images d’émulateur ne constituent pas une validation sur matériel réel.
Trois motifs originaux de 8 × 8 distinguent les copies : le 1 est plein, le 2 remplit les quatre colonnes de gauche et le 3 est un triangle aligné à gauche, large d’un pixel en haut et de huit en bas. Le bloc de 3 × 2 tuiles en (80,32) doit afficher [1,2,3] / [3,0,2], où 0 est vide. Son premier octet change après l’ajout ; la tuile pleine en haut à gauche prouve que le pointeur est conservé. La copie en (16,64) affiche [1,2,3] ; l’alias tiles en (48,64), [2,3]. Leurs tailles respectives sont de 24 × 16, 24 × 8 et 16 × 8 pixels.
Sur CGB, les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank sont rouges. Le rectangle de 32 × 24 et la copie de deux motifs sont bleus. Le bloc de 3 × 2 tuiles et la barre de 40 × 8 sont verts. Le texte reste noir sur blanc. La couleur de chaque pixel dessiné est vérifiée en plus de la géométrie.


Commande de compilation
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-disasmImplémentation et source
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
Consultez les changements et vérifications du 2026-10-03 pour les différences locales de cette API.
Renvoie la capacité totale du tampon d’ordres, quelle que soit son occupation actuelle.
Syntaxe
u8 vram_get_queue_capacity();Valeur renvoyée
Un octet non signé dans les unités propres à la plateforme décrites ici. Sa lecture ne modifie ni n’exécute la file.
Conditions et limites
GB compte des emplacements d’ordre : la capacité par défaut est 32. Chaque fonction d’ajout en utilise un, même pour un transfert long ou nul. Définissez VRAM_QUEUE_MAX uniformément dans toutes les unités, entre 1 et 255. Une file vide a used=0 et free=capacity.
Coordonnez la construction et la consommation de la file. N’ajoutez rien pendant son exécution par une interruption, ne modifiez pas directement ses compteurs et n’écrasez pas involontairement les sources conservées. Ces API n’offrent ni verrouillage ni double tampon. La capacité concerne le tampon d’ordres, pas les octets libres de VRAM physique.
Exemple d’utilisation
capacity=vram_get_queue_capacity();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le programme complet présente les écritures différées, le suivi de capacité et la reprise après débordement. Sept appels de dessin occupent 7 des 32 emplacements sur GB, ou 52 des 128 octets sur FC : CAPACITY/USED/FREE affiche 032/007/025 ou 128/052/076. AFTER FLUSH et FAILED CHECKS doivent valoir 000, et OVERFLOW SEEN, 001. Un ajout volontaire à une file pleine teste l’indicateur : ni la lecture ni l’exécution ne l’effacent, contrairement à la remise à zéro de la file. Sur FC, l’exécution directe sans validation doit laisser la file intacte.
Les coordonnées sont en pixels depuis le coin supérieur gauche. On attend des carrés pleins de 8 × 8 en (16,16) et (32,16), un rectangle plein de 32 × 24 en (16,32) et une barre horizontale de 40 × 8 en (80,64). L’écriture finale en VBlank ajoute un carré de 8 × 8 en (144,80). L’écriture annulée en (144,24) doit laisser cette case vide. Le DMG affiche des formes noires sur blanc, le CGB des formes rouges, bleues et vertes sur blanc, et le FC des formes rouges, bleues et vertes sur noir. Ces images d’émulateur ne constituent pas une validation sur matériel réel.
Trois motifs originaux de 8 × 8 distinguent les copies : le 1 est plein, le 2 remplit les quatre colonnes de gauche et le 3 est un triangle aligné à gauche, large d’un pixel en haut et de huit en bas. Le bloc de 3 × 2 tuiles en (80,32) doit afficher [1,2,3] / [3,0,2], où 0 est vide. Son premier octet change après l’ajout ; la tuile pleine en haut à gauche prouve que le pointeur est conservé. La copie en (16,64) affiche [1,2,3] ; l’alias tiles en (48,64), [2,3]. Leurs tailles respectives sont de 24 × 16, 24 × 8 et 16 × 8 pixels.
Sur CGB, les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank sont rouges. Le rectangle de 32 × 24 et la copie de deux motifs sont bleus. Le bloc de 3 × 2 tuiles et la barre de 40 × 8 sont verts. Le texte reste noir sur blanc. La couleur de chaque pixel dessiné est vérifiée en plus de la géométrie.


Commande de compilation
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-disasmImplémentation et source
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
Renvoie la capacité totale moins l’occupation actuelle. Vérifiez avant l’ajout que le prochain enregistrement ou lot tient entièrement ; cette lecture ne réserve aucune place.
Syntaxe
u8 vram_get_queue_free();Valeur renvoyée
Un octet non signé dans les unités propres à la plateforme décrites ici. Sa lecture ne modifie ni n’exécute la file.
Conditions et limites
GB compte des emplacements d’ordre : la capacité par défaut est 32. Chaque fonction d’ajout en utilise un, même pour un transfert long ou nul. Définissez VRAM_QUEUE_MAX uniformément dans toutes les unités, entre 1 et 255. Une file vide a used=0 et free=capacity.
Coordonnez la construction et la consommation de la file. N’ajoutez rien pendant son exécution par une interruption, ne modifiez pas directement ses compteurs et n’écrasez pas involontairement les sources conservées. Ces API n’offrent ni verrouillage ni double tampon. La capacité concerne le tampon d’ordres, pas les octets libres de VRAM physique.
Exemple d’utilisation
available=vram_get_queue_free();
if (used+available!=capacity) failures++;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le programme complet présente les écritures différées, le suivi de capacité et la reprise après débordement. Sept appels de dessin occupent 7 des 32 emplacements sur GB, ou 52 des 128 octets sur FC : CAPACITY/USED/FREE affiche 032/007/025 ou 128/052/076. AFTER FLUSH et FAILED CHECKS doivent valoir 000, et OVERFLOW SEEN, 001. Un ajout volontaire à une file pleine teste l’indicateur : ni la lecture ni l’exécution ne l’effacent, contrairement à la remise à zéro de la file. Sur FC, l’exécution directe sans validation doit laisser la file intacte.
Les coordonnées sont en pixels depuis le coin supérieur gauche. On attend des carrés pleins de 8 × 8 en (16,16) et (32,16), un rectangle plein de 32 × 24 en (16,32) et une barre horizontale de 40 × 8 en (80,64). L’écriture finale en VBlank ajoute un carré de 8 × 8 en (144,80). L’écriture annulée en (144,24) doit laisser cette case vide. Le DMG affiche des formes noires sur blanc, le CGB des formes rouges, bleues et vertes sur blanc, et le FC des formes rouges, bleues et vertes sur noir. Ces images d’émulateur ne constituent pas une validation sur matériel réel.
Trois motifs originaux de 8 × 8 distinguent les copies : le 1 est plein, le 2 remplit les quatre colonnes de gauche et le 3 est un triangle aligné à gauche, large d’un pixel en haut et de huit en bas. Le bloc de 3 × 2 tuiles en (80,32) doit afficher [1,2,3] / [3,0,2], où 0 est vide. Son premier octet change après l’ajout ; la tuile pleine en haut à gauche prouve que le pointeur est conservé. La copie en (16,64) affiche [1,2,3] ; l’alias tiles en (48,64), [2,3]. Leurs tailles respectives sont de 24 × 16, 24 × 8 et 16 × 8 pixels.
Sur CGB, les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank sont rouges. Le rectangle de 32 × 24 et la copie de deux motifs sont bleus. Le bloc de 3 × 2 tuiles et la barre de 40 × 8 sont verts. Le texte reste noir sur blanc. La couleur de chaque pixel dessiné est vérifiée en plus de la géométrie.


Commande de compilation
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-disasmImplémentation et source
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
Renvoie l’espace du tampon occupé par les ordres en attente, pas le nombre d’octets qui seront écrits en mémoire vidéo.
Syntaxe
u8 vram_get_queue_used();Valeur renvoyée
Un octet non signé dans les unités propres à la plateforme décrites ici. Sa lecture ne modifie ni n’exécute la file.
Conditions et limites
GB compte des emplacements d’ordre : la capacité par défaut est 32. Chaque fonction d’ajout en utilise un, même pour un transfert long ou nul. Définissez VRAM_QUEUE_MAX uniformément dans toutes les unités, entre 1 et 255. Une file vide a used=0 et free=capacity.
Coordonnez la construction et la consommation de la file. N’ajoutez rien pendant son exécution par une interruption, ne modifiez pas directement ses compteurs et n’écrasez pas involontairement les sources conservées. Ces API n’offrent ni verrouillage ni double tampon. La capacité concerne le tampon d’ordres, pas les octets libres de VRAM physique.
Exemple d’utilisation
used=vram_get_queue_used();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le programme complet présente les écritures différées, le suivi de capacité et la reprise après débordement. Sept appels de dessin occupent 7 des 32 emplacements sur GB, ou 52 des 128 octets sur FC : CAPACITY/USED/FREE affiche 032/007/025 ou 128/052/076. AFTER FLUSH et FAILED CHECKS doivent valoir 000, et OVERFLOW SEEN, 001. Un ajout volontaire à une file pleine teste l’indicateur : ni la lecture ni l’exécution ne l’effacent, contrairement à la remise à zéro de la file. Sur FC, l’exécution directe sans validation doit laisser la file intacte.
Les coordonnées sont en pixels depuis le coin supérieur gauche. On attend des carrés pleins de 8 × 8 en (16,16) et (32,16), un rectangle plein de 32 × 24 en (16,32) et une barre horizontale de 40 × 8 en (80,64). L’écriture finale en VBlank ajoute un carré de 8 × 8 en (144,80). L’écriture annulée en (144,24) doit laisser cette case vide. Le DMG affiche des formes noires sur blanc, le CGB des formes rouges, bleues et vertes sur blanc, et le FC des formes rouges, bleues et vertes sur noir. Ces images d’émulateur ne constituent pas une validation sur matériel réel.
Trois motifs originaux de 8 × 8 distinguent les copies : le 1 est plein, le 2 remplit les quatre colonnes de gauche et le 3 est un triangle aligné à gauche, large d’un pixel en haut et de huit en bas. Le bloc de 3 × 2 tuiles en (80,32) doit afficher [1,2,3] / [3,0,2], où 0 est vide. Son premier octet change après l’ajout ; la tuile pleine en haut à gauche prouve que le pointeur est conservé. La copie en (16,64) affiche [1,2,3] ; l’alias tiles en (48,64), [2,3]. Leurs tailles respectives sont de 24 × 16, 24 × 8 et 16 × 8 pixels.
Sur CGB, les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank sont rouges. Le rectangle de 32 × 24 et la copie de deux motifs sont bleus. Le bloc de 3 × 2 tuiles et la barre de 40 × 8 sont verts. Le texte reste noir sur blanc. La couleur de chaque pixel dessiné est vérifiée en plus de la géométrie.


Commande de compilation
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-disasmImplémentation et source
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
Initialise à vide la file des écritures VRAM différées et efface son indicateur de débordement. Ne vide pas l’écran, ne charge pas de graphismes et n’alloue pas de VRAM physique.
Syntaxe
void vram_init();Valeur renvoyée
Aucune (void).
Conditions et limites
GB compte des emplacements d’ordre : la capacité par défaut est 32. Chaque fonction d’ajout en utilise un, même pour un transfert long ou nul. Définissez VRAM_QUEUE_MAX uniformément dans toutes les unités, entre 1 et 255. Une file vide a used=0 et free=capacity.
Coordonnez la construction et la consommation de la file. N’ajoutez rien pendant son exécution par une interruption, ne modifiez pas directement ses compteurs et n’écrasez pas involontairement les sources conservées. Ces API n’offrent ni verrouillage ni double tampon. La capacité concerne le tampon d’ordres, pas les octets libres de VRAM physique.
Exemple d’utilisation
vram_init();
if (vram_get_queue_used()!=0 || vram_get_overflowed()!=0) failures++;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le programme complet présente les écritures différées, le suivi de capacité et la reprise après débordement. Sept appels de dessin occupent 7 des 32 emplacements sur GB, ou 52 des 128 octets sur FC : CAPACITY/USED/FREE affiche 032/007/025 ou 128/052/076. AFTER FLUSH et FAILED CHECKS doivent valoir 000, et OVERFLOW SEEN, 001. Un ajout volontaire à une file pleine teste l’indicateur : ni la lecture ni l’exécution ne l’effacent, contrairement à la remise à zéro de la file. Sur FC, l’exécution directe sans validation doit laisser la file intacte.
Les coordonnées sont en pixels depuis le coin supérieur gauche. On attend des carrés pleins de 8 × 8 en (16,16) et (32,16), un rectangle plein de 32 × 24 en (16,32) et une barre horizontale de 40 × 8 en (80,64). L’écriture finale en VBlank ajoute un carré de 8 × 8 en (144,80). L’écriture annulée en (144,24) doit laisser cette case vide. Le DMG affiche des formes noires sur blanc, le CGB des formes rouges, bleues et vertes sur blanc, et le FC des formes rouges, bleues et vertes sur noir. Ces images d’émulateur ne constituent pas une validation sur matériel réel.
Trois motifs originaux de 8 × 8 distinguent les copies : le 1 est plein, le 2 remplit les quatre colonnes de gauche et le 3 est un triangle aligné à gauche, large d’un pixel en haut et de huit en bas. Le bloc de 3 × 2 tuiles en (80,32) doit afficher [1,2,3] / [3,0,2], où 0 est vide. Son premier octet change après l’ajout ; la tuile pleine en haut à gauche prouve que le pointeur est conservé. La copie en (16,64) affiche [1,2,3] ; l’alias tiles en (48,64), [2,3]. Leurs tailles respectives sont de 24 × 16, 24 × 8 et 16 × 8 pixels.
Sur CGB, les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank sont rouges. Le rectangle de 32 × 24 et la copie de deux motifs sont bleus. Le bloc de 3 × 2 tuiles et la barre de 40 × 8 sont verts. Le texte reste noir sur blanc. La couleur de chaque pixel dessiné est vérifiée en plus de la géométrie.


Commande de compilation
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-disasmImplémentation et source
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
Ajoute à la file un rectangle de w × h numéros de tuile de src vers la carte en base. Chaque ligne source contient w octets contigus ; les lignes de destination sont espacées de 32 octets. Le pointeur est conservé : modifier la source avant l’exécution change le bloc affiché.
Syntaxe
u8 vram_queue_bg_block(u16 base, u8 x, u8 y, u8 w, u8 h, const u8* src);Paramètres
baseLes ordres de tuile et de rectangle choisissent la carte de fond selon le bit 3 de LCDC à l’exécution. Sur CGB, utilisez la banque VRAM 0 pour les indices de tuile. Le bloc utilise la base indiquée, normalement
0x9800ou0x9C00. Le pas entre lignes est de 32 octets ; les coordonnées ne sont pas bornées automatiquement.x, yCoordonnées du coin supérieur gauche en tuiles de 8×8, pas en pixels. Aucun découpage. Gardez
x + w <= 32ety + h <= 32sur GB, ou<= 30dans la zone de tuiles d’une nametable FC. Une tuile seule a une largeur et une hauteur de 1.w, hLargeur et hauteur en tuiles, sur des octets non signés. Le bloc source contient
w * hoctets par lignes. Une dimension nulle ne produit aucune écriture visible, mais l’occupation de la file suit les règles de la plateforme.srcPointeur proche vers des octets lisibles, conservé jusqu’à l’exécution. Gardez les données vivantes et leur banque mémoire ou ROM accessible pendant tout le traitement ; aucun numéro de banque ni copie n’est mémorisé. Un transfert non vide exige une source valide. N’utilisez pas un tableau local dont la durée de vie est terminée.
Valeur renvoyée
1 si cet ordre a été ajouté, 0 si aucune place n’était libre. Un échec mémorise le débordement sans toucher aux ordres existants. Un débordement antérieur ne fait pas renvoyer 0 à un ajout ultérieur réussi.
Conditions et limites
GB compte des emplacements d’ordre : la capacité par défaut est 32. Chaque fonction d’ajout en utilise un, même pour un transfert long ou nul. Définissez VRAM_QUEUE_MAX uniformément dans toutes les unités, entre 1 et 255. Une file vide a used=0 et free=capacity.
Les ordres de tuile et de rectangle choisissent la carte de fond selon le bit 3 de LCDC à l’exécution. Sur CGB, utilisez la banque VRAM 0 pour les indices de tuile. Le bloc utilise la base indiquée, normalement 0x9800 ou 0x9C00. Le pas entre lignes est de 32 octets ; les coordonnées ne sont pas bornées automatiquement.
Coordonnez la construction et la consommation de la file. N’ajoutez rien pendant son exécution par une interruption, ne modifiez pas directement ses compteurs et n’écrasez pas involontairement les sources conservées. Ces API n’offrent ni verrouillage ni double tampon. La capacité concerne le tampon d’ordres, pas les octets libres de VRAM physique.
Exemple d’utilisation
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++;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le programme complet présente les écritures différées, le suivi de capacité et la reprise après débordement. Sept appels de dessin occupent 7 des 32 emplacements sur GB, ou 52 des 128 octets sur FC : CAPACITY/USED/FREE affiche 032/007/025 ou 128/052/076. AFTER FLUSH et FAILED CHECKS doivent valoir 000, et OVERFLOW SEEN, 001. Un ajout volontaire à une file pleine teste l’indicateur : ni la lecture ni l’exécution ne l’effacent, contrairement à la remise à zéro de la file. Sur FC, l’exécution directe sans validation doit laisser la file intacte.
Les coordonnées sont en pixels depuis le coin supérieur gauche. On attend des carrés pleins de 8 × 8 en (16,16) et (32,16), un rectangle plein de 32 × 24 en (16,32) et une barre horizontale de 40 × 8 en (80,64). L’écriture finale en VBlank ajoute un carré de 8 × 8 en (144,80). L’écriture annulée en (144,24) doit laisser cette case vide. Le DMG affiche des formes noires sur blanc, le CGB des formes rouges, bleues et vertes sur blanc, et le FC des formes rouges, bleues et vertes sur noir. Ces images d’émulateur ne constituent pas une validation sur matériel réel.
Trois motifs originaux de 8 × 8 distinguent les copies : le 1 est plein, le 2 remplit les quatre colonnes de gauche et le 3 est un triangle aligné à gauche, large d’un pixel en haut et de huit en bas. Le bloc de 3 × 2 tuiles en (80,32) doit afficher [1,2,3] / [3,0,2], où 0 est vide. Son premier octet change après l’ajout ; la tuile pleine en haut à gauche prouve que le pointeur est conservé. La copie en (16,64) affiche [1,2,3] ; l’alias tiles en (48,64), [2,3]. Leurs tailles respectives sont de 24 × 16, 24 × 8 et 16 × 8 pixels.
Sur CGB, les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank sont rouges. Le rectangle de 32 × 24 et la copie de deux motifs sont bleus. Le bloc de 3 × 2 tuiles et la barre de 40 × 8 sont verts. Le texte reste noir sur blanc. La couleur de chaque pixel dessiné est vérifiée en plus de la géométrie.


Commande de compilation
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-disasmImplémentation et source
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
Ajoute à la file un rectangle de carte de fond rempli du même numéro de tuile. Son coin supérieur gauche est (x, y) et sa taille est w × h tuiles. Une tuile unie forme un rectangle plein ; une tuile dessinée répète son motif dans chaque case.
Syntaxe
u8 vram_queue_bg_rect(u8 x, u8 y, u8 w, u8 h, u8 tile);Paramètres
x, yCoordonnées du coin supérieur gauche en tuiles de 8×8, pas en pixels. Aucun découpage. Gardez
x + w <= 32ety + h <= 32sur GB, ou<= 30dans la zone de tuiles d’une nametable FC. Une tuile seule a une largeur et une hauteur de 1.w, hLargeur et hauteur en tuiles, sur des octets non signés. Le bloc source contient
w * hoctets par lignes. Une dimension nulle ne produit aucune écriture visible, mais l’occupation de la file suit les règles de la plateforme.tileOctet de carte, de 0 à 255. Chargez le graphisme séparément et choisissez la table de motifs ou le mode d’adressage voulu. Ce numéro n’est ni un pointeur ni une couleur.
Valeur renvoyée
1 si cet ordre a été ajouté, 0 si aucune place n’était libre. Un échec mémorise le débordement sans toucher aux ordres existants. Un débordement antérieur ne fait pas renvoyer 0 à un ajout ultérieur réussi.
Conditions et limites
GB compte des emplacements d’ordre : la capacité par défaut est 32. Chaque fonction d’ajout en utilise un, même pour un transfert long ou nul. Définissez VRAM_QUEUE_MAX uniformément dans toutes les unités, entre 1 et 255. Une file vide a used=0 et free=capacity.
Les ordres de tuile et de rectangle choisissent la carte de fond selon le bit 3 de LCDC à l’exécution. Sur CGB, utilisez la banque VRAM 0 pour les indices de tuile. Le bloc utilise la base indiquée, normalement 0x9800 ou 0x9C00. Le pas entre lignes est de 32 octets ; les coordonnées ne sont pas bornées automatiquement.
Coordonnez la construction et la consommation de la file. N’ajoutez rien pendant son exécution par une interruption, ne modifiez pas directement ses compteurs et n’écrasez pas involontairement les sources conservées. Ces API n’offrent ni verrouillage ni double tampon. La capacité concerne le tampon d’ordres, pas les octets libres de VRAM physique.
Exemple d’utilisation
check_result=vram_queue_bg_rect(2,4,4,3,1); // A filled 32x24 rectangle at (16,32).
if (check_result!=1) failures++;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le programme complet présente les écritures différées, le suivi de capacité et la reprise après débordement. Sept appels de dessin occupent 7 des 32 emplacements sur GB, ou 52 des 128 octets sur FC : CAPACITY/USED/FREE affiche 032/007/025 ou 128/052/076. AFTER FLUSH et FAILED CHECKS doivent valoir 000, et OVERFLOW SEEN, 001. Un ajout volontaire à une file pleine teste l’indicateur : ni la lecture ni l’exécution ne l’effacent, contrairement à la remise à zéro de la file. Sur FC, l’exécution directe sans validation doit laisser la file intacte.
Les coordonnées sont en pixels depuis le coin supérieur gauche. On attend des carrés pleins de 8 × 8 en (16,16) et (32,16), un rectangle plein de 32 × 24 en (16,32) et une barre horizontale de 40 × 8 en (80,64). L’écriture finale en VBlank ajoute un carré de 8 × 8 en (144,80). L’écriture annulée en (144,24) doit laisser cette case vide. Le DMG affiche des formes noires sur blanc, le CGB des formes rouges, bleues et vertes sur blanc, et le FC des formes rouges, bleues et vertes sur noir. Ces images d’émulateur ne constituent pas une validation sur matériel réel.
Trois motifs originaux de 8 × 8 distinguent les copies : le 1 est plein, le 2 remplit les quatre colonnes de gauche et le 3 est un triangle aligné à gauche, large d’un pixel en haut et de huit en bas. Le bloc de 3 × 2 tuiles en (80,32) doit afficher [1,2,3] / [3,0,2], où 0 est vide. Son premier octet change après l’ajout ; la tuile pleine en haut à gauche prouve que le pointeur est conservé. La copie en (16,64) affiche [1,2,3] ; l’alias tiles en (48,64), [2,3]. Leurs tailles respectives sont de 24 × 16, 24 × 8 et 16 × 8 pixels.
Sur CGB, les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank sont rouges. Le rectangle de 32 × 24 et la copie de deux motifs sont bleus. Le bloc de 3 × 2 tuiles et la barre de 40 × 8 sont verts. Le texte reste noir sur blanc. La couleur de chaque pixel dessiné est vérifiée en plus de la géométrie.


Commande de compilation
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-disasmImplémentation et source
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
Ajoute à la file l’écriture d’un numéro de tuile de fond en (x, y). La modification devient visible à l’exécution de la file. Écrit une entrée de carte, sans charger les pixels de la tuile ni modifier ses attributs de palette.
Syntaxe
u8 vram_queue_bg_tile(u8 x, u8 y, u8 tile);Paramètres
x, yCoordonnées du coin supérieur gauche en tuiles de 8×8, pas en pixels. Aucun découpage. Gardez
x + w <= 32ety + h <= 32sur GB, ou<= 30dans la zone de tuiles d’une nametable FC. Une tuile seule a une largeur et une hauteur de 1.tileOctet de carte, de 0 à 255. Chargez le graphisme séparément et choisissez la table de motifs ou le mode d’adressage voulu. Ce numéro n’est ni un pointeur ni une couleur.
Valeur renvoyée
1 si cet ordre a été ajouté, 0 si aucune place n’était libre. Un échec mémorise le débordement sans toucher aux ordres existants. Un débordement antérieur ne fait pas renvoyer 0 à un ajout ultérieur réussi.
Conditions et limites
GB compte des emplacements d’ordre : la capacité par défaut est 32. Chaque fonction d’ajout en utilise un, même pour un transfert long ou nul. Définissez VRAM_QUEUE_MAX uniformément dans toutes les unités, entre 1 et 255. Une file vide a used=0 et free=capacity.
Les ordres de tuile et de rectangle choisissent la carte de fond selon le bit 3 de LCDC à l’exécution. Sur CGB, utilisez la banque VRAM 0 pour les indices de tuile. Le bloc utilise la base indiquée, normalement 0x9800 ou 0x9C00. Le pas entre lignes est de 32 octets ; les coordonnées ne sont pas bornées automatiquement.
Coordonnez la construction et la consommation de la file. N’ajoutez rien pendant son exécution par une interruption, ne modifiez pas directement ses compteurs et n’écrasez pas involontairement les sources conservées. Ces API n’offrent ni verrouillage ni double tampon. La capacité concerne le tampon d’ordres, pas les octets libres de VRAM physique.
Exemple d’utilisation
check_result=vram_queue_bg_tile(2,2,1); // A solid 8x8 tile at pixel (16,16).
if (check_result!=1) failures++;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le programme complet présente les écritures différées, le suivi de capacité et la reprise après débordement. Sept appels de dessin occupent 7 des 32 emplacements sur GB, ou 52 des 128 octets sur FC : CAPACITY/USED/FREE affiche 032/007/025 ou 128/052/076. AFTER FLUSH et FAILED CHECKS doivent valoir 000, et OVERFLOW SEEN, 001. Un ajout volontaire à une file pleine teste l’indicateur : ni la lecture ni l’exécution ne l’effacent, contrairement à la remise à zéro de la file. Sur FC, l’exécution directe sans validation doit laisser la file intacte.
Les coordonnées sont en pixels depuis le coin supérieur gauche. On attend des carrés pleins de 8 × 8 en (16,16) et (32,16), un rectangle plein de 32 × 24 en (16,32) et une barre horizontale de 40 × 8 en (80,64). L’écriture finale en VBlank ajoute un carré de 8 × 8 en (144,80). L’écriture annulée en (144,24) doit laisser cette case vide. Le DMG affiche des formes noires sur blanc, le CGB des formes rouges, bleues et vertes sur blanc, et le FC des formes rouges, bleues et vertes sur noir. Ces images d’émulateur ne constituent pas une validation sur matériel réel.
Trois motifs originaux de 8 × 8 distinguent les copies : le 1 est plein, le 2 remplit les quatre colonnes de gauche et le 3 est un triangle aligné à gauche, large d’un pixel en haut et de huit en bas. Le bloc de 3 × 2 tuiles en (80,32) doit afficher [1,2,3] / [3,0,2], où 0 est vide. Son premier octet change après l’ajout ; la tuile pleine en haut à gauche prouve que le pointeur est conservé. La copie en (16,64) affiche [1,2,3] ; l’alias tiles en (48,64), [2,3]. Leurs tailles respectives sont de 24 × 16, 24 × 8 et 16 × 8 pixels.
Sur CGB, les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank sont rouges. Le rectangle de 32 × 24 et la copie de deux motifs sont bleus. Le bloc de 3 × 2 tuiles et la barre de 40 × 8 sont verts. Le texte reste noir sur blanc. La couleur de chaque pixel dessiné est vérifiée en plus de la géométrie.


Commande de compilation
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-disasmImplémentation et source
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
Ajoute à la file une copie de len octets consécutifs de src vers dst. Les deux adresses avancent octet par octet, sans saut de ligne de tuiles. Peut transférer des octets de carte ou de motifs modifiables, sans conversion de format ni calcul du nombre d’octets d’une tuile.
Syntaxe
u8 vram_queue_memcpy(u16 dst, const void* src, u16 len);Paramètres
dstAdresse de destination en octets dans la VRAM (
0x8000–0x9FFF), dans la banque sélectionnée à l’exécution. Le transfert est contigu, sans saut de ligne. Toute la plage doit être valide. LCD actif, les chemins d’écriture sûrs peuvent activer les interruptions ; ils ne préservent pas un état d’appel où elles étaient désactivées.srcPointeur proche vers des octets lisibles, conservé jusqu’à l’exécution. Gardez les données vivantes et leur banque mémoire ou ROM accessible pendant tout le traitement ; aucun numéro de banque ni copie n’est mémorisé. Un transfert non vide exige une source valide. N’utilisez pas un tableau local dont la durée de vie est terminée.
lenNombre d’octets consécutifs, de 0 à 65535, pas de tuiles. Gardez toute la plage dans une source valide et une destination modifiable ; l’API ne vérifie pas les limites et n’empêche pas le bouclage d’adresse sur 16 bits.
Valeur renvoyée
1 si cet ordre a été ajouté, 0 si aucune place n’était libre. Un échec mémorise le débordement sans toucher aux ordres existants. Un débordement antérieur ne fait pas renvoyer 0 à un ajout ultérieur réussi.
Conditions et limites
GB compte des emplacements d’ordre : la capacité par défaut est 32. Chaque fonction d’ajout en utilise un, même pour un transfert long ou nul. Définissez VRAM_QUEUE_MAX uniformément dans toutes les unités, entre 1 et 255. Une file vide a used=0 et free=capacity.
Coordonnez la construction et la consommation de la file. N’ajoutez rien pendant son exécution par une interruption, ne modifiez pas directement ses compteurs et n’écrasez pas involontairement les sources conservées. Ces API n’offrent ni verrouillage ni double tampon. La capacité concerne le tampon d’ordres, pas les octets libres de VRAM physique.
Exemple d’utilisation
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.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le programme complet présente les écritures différées, le suivi de capacité et la reprise après débordement. Sept appels de dessin occupent 7 des 32 emplacements sur GB, ou 52 des 128 octets sur FC : CAPACITY/USED/FREE affiche 032/007/025 ou 128/052/076. AFTER FLUSH et FAILED CHECKS doivent valoir 000, et OVERFLOW SEEN, 001. Un ajout volontaire à une file pleine teste l’indicateur : ni la lecture ni l’exécution ne l’effacent, contrairement à la remise à zéro de la file. Sur FC, l’exécution directe sans validation doit laisser la file intacte.
Les coordonnées sont en pixels depuis le coin supérieur gauche. On attend des carrés pleins de 8 × 8 en (16,16) et (32,16), un rectangle plein de 32 × 24 en (16,32) et une barre horizontale de 40 × 8 en (80,64). L’écriture finale en VBlank ajoute un carré de 8 × 8 en (144,80). L’écriture annulée en (144,24) doit laisser cette case vide. Le DMG affiche des formes noires sur blanc, le CGB des formes rouges, bleues et vertes sur blanc, et le FC des formes rouges, bleues et vertes sur noir. Ces images d’émulateur ne constituent pas une validation sur matériel réel.
Trois motifs originaux de 8 × 8 distinguent les copies : le 1 est plein, le 2 remplit les quatre colonnes de gauche et le 3 est un triangle aligné à gauche, large d’un pixel en haut et de huit en bas. Le bloc de 3 × 2 tuiles en (80,32) doit afficher [1,2,3] / [3,0,2], où 0 est vide. Son premier octet change après l’ajout ; la tuile pleine en haut à gauche prouve que le pointeur est conservé. La copie en (16,64) affiche [1,2,3] ; l’alias tiles en (48,64), [2,3]. Leurs tailles respectives sont de 24 × 16, 24 × 8 et 16 × 8 pixels.
Sur CGB, les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank sont rouges. Le rectangle de 32 × 24 et la copie de deux motifs sont bleus. Le bloc de 3 × 2 tuiles et la barre de 40 × 8 sont verts. Le texte reste noir sur blanc. La couleur de chaque pixel dessiné est vérifiée en plus de la géométrie.


Commande de compilation
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-disasmImplémentation et source
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
Ajoute à la file le remplissage de len octets consécutifs en dst par l’octet value. Répète un octet, pas un motif de tuile de plusieurs octets, sans introduire de saut de ligne de carte de 32 octets.
Syntaxe
u8 vram_queue_memset(u16 dst, u8 value, u16 len);Paramètres
dstAdresse de destination en octets dans la VRAM (
0x8000–0x9FFF), dans la banque sélectionnée à l’exécution. Le transfert est contigu, sans saut de ligne. Toute la plage doit être valide. LCD actif, les chemins d’écriture sûrs peuvent activer les interruptions ; ils ne préservent pas un état d’appel où elles étaient désactivées.valueUn octet de 0 à 255 répété. Son effet visible dépend du contenu de destination : indices de tuiles, plans de pixels ou autre structure d’octets.
lenNombre d’octets consécutifs, de 0 à 65535, pas de tuiles. Gardez toute la plage dans une source valide et une destination modifiable ; l’API ne vérifie pas les limites et n’empêche pas le bouclage d’adresse sur 16 bits.
Valeur renvoyée
1 si cet ordre a été ajouté, 0 si aucune place n’était libre. Un échec mémorise le débordement sans toucher aux ordres existants. Un débordement antérieur ne fait pas renvoyer 0 à un ajout ultérieur réussi.
Conditions et limites
GB compte des emplacements d’ordre : la capacité par défaut est 32. Chaque fonction d’ajout en utilise un, même pour un transfert long ou nul. Définissez VRAM_QUEUE_MAX uniformément dans toutes les unités, entre 1 et 255. Une file vide a used=0 et free=capacity.
Coordonnez la construction et la consommation de la file. N’ajoutez rien pendant son exécution par une interruption, ne modifiez pas directement ses compteurs et n’écrasez pas involontairement les sources conservées. Ces API n’offrent ni verrouillage ni double tampon. La capacité concerne le tampon d’ordres, pas les octets libres de VRAM physique.
Exemple d’utilisation
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.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le programme complet présente les écritures différées, le suivi de capacité et la reprise après débordement. Sept appels de dessin occupent 7 des 32 emplacements sur GB, ou 52 des 128 octets sur FC : CAPACITY/USED/FREE affiche 032/007/025 ou 128/052/076. AFTER FLUSH et FAILED CHECKS doivent valoir 000, et OVERFLOW SEEN, 001. Un ajout volontaire à une file pleine teste l’indicateur : ni la lecture ni l’exécution ne l’effacent, contrairement à la remise à zéro de la file. Sur FC, l’exécution directe sans validation doit laisser la file intacte.
Les coordonnées sont en pixels depuis le coin supérieur gauche. On attend des carrés pleins de 8 × 8 en (16,16) et (32,16), un rectangle plein de 32 × 24 en (16,32) et une barre horizontale de 40 × 8 en (80,64). L’écriture finale en VBlank ajoute un carré de 8 × 8 en (144,80). L’écriture annulée en (144,24) doit laisser cette case vide. Le DMG affiche des formes noires sur blanc, le CGB des formes rouges, bleues et vertes sur blanc, et le FC des formes rouges, bleues et vertes sur noir. Ces images d’émulateur ne constituent pas une validation sur matériel réel.
Trois motifs originaux de 8 × 8 distinguent les copies : le 1 est plein, le 2 remplit les quatre colonnes de gauche et le 3 est un triangle aligné à gauche, large d’un pixel en haut et de huit en bas. Le bloc de 3 × 2 tuiles en (80,32) doit afficher [1,2,3] / [3,0,2], où 0 est vide. Son premier octet change après l’ajout ; la tuile pleine en haut à gauche prouve que le pointeur est conservé. La copie en (16,64) affiche [1,2,3] ; l’alias tiles en (48,64), [2,3]. Leurs tailles respectives sont de 24 × 16, 24 × 8 et 16 × 8 pixels.
Sur CGB, les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank sont rouges. Le rectangle de 32 × 24 et la copie de deux motifs sont bleus. Le bloc de 3 × 2 tuiles et la barre de 40 × 8 sont verts. Le texte reste noir sur blanc. La couleur de chaque pixel dessiné est vérifiée en plus de la géométrie.


Commande de compilation
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-disasmImplémentation et source
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 appelle directement vram_queue_bg_tile avec les mêmes arguments et renvoie son résultat. C’est le nom court pour une entrée de carte de fond, pas une opération sur un sprite ni un chargement de graphismes.
Syntaxe
u8 vram_queue_tile(u8 x, u8 y, u8 tile);Paramètres
x, yCoordonnées du coin supérieur gauche en tuiles de 8×8, pas en pixels. Aucun découpage. Gardez
x + w <= 32ety + h <= 32sur GB, ou<= 30dans la zone de tuiles d’une nametable FC. Une tuile seule a une largeur et une hauteur de 1.tileOctet de carte, de 0 à 255. Chargez le graphisme séparément et choisissez la table de motifs ou le mode d’adressage voulu. Ce numéro n’est ni un pointeur ni une couleur.
Valeur renvoyée
1 si cet ordre a été ajouté, 0 si aucune place n’était libre. Un échec mémorise le débordement sans toucher aux ordres existants. Un débordement antérieur ne fait pas renvoyer 0 à un ajout ultérieur réussi.
Conditions et limites
GB compte des emplacements d’ordre : la capacité par défaut est 32. Chaque fonction d’ajout en utilise un, même pour un transfert long ou nul. Définissez VRAM_QUEUE_MAX uniformément dans toutes les unités, entre 1 et 255. Une file vide a used=0 et free=capacity.
Les ordres de tuile et de rectangle choisissent la carte de fond selon le bit 3 de LCDC à l’exécution. Sur CGB, utilisez la banque VRAM 0 pour les indices de tuile. Le bloc utilise la base indiquée, normalement 0x9800 ou 0x9C00. Le pas entre lignes est de 32 octets ; les coordonnées ne sont pas bornées automatiquement.
Coordonnez la construction et la consommation de la file. N’ajoutez rien pendant son exécution par une interruption, ne modifiez pas directement ses compteurs et n’écrasez pas involontairement les sources conservées. Ces API n’offrent ni verrouillage ni double tampon. La capacité concerne le tampon d’ordres, pas les octets libres de VRAM physique.
Exemple d’utilisation
check_result=vram_queue_tile(4,2,1); // The short alias draws at pixel (32,16).
if (check_result!=1) failures++;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le programme complet présente les écritures différées, le suivi de capacité et la reprise après débordement. Sept appels de dessin occupent 7 des 32 emplacements sur GB, ou 52 des 128 octets sur FC : CAPACITY/USED/FREE affiche 032/007/025 ou 128/052/076. AFTER FLUSH et FAILED CHECKS doivent valoir 000, et OVERFLOW SEEN, 001. Un ajout volontaire à une file pleine teste l’indicateur : ni la lecture ni l’exécution ne l’effacent, contrairement à la remise à zéro de la file. Sur FC, l’exécution directe sans validation doit laisser la file intacte.
Les coordonnées sont en pixels depuis le coin supérieur gauche. On attend des carrés pleins de 8 × 8 en (16,16) et (32,16), un rectangle plein de 32 × 24 en (16,32) et une barre horizontale de 40 × 8 en (80,64). L’écriture finale en VBlank ajoute un carré de 8 × 8 en (144,80). L’écriture annulée en (144,24) doit laisser cette case vide. Le DMG affiche des formes noires sur blanc, le CGB des formes rouges, bleues et vertes sur blanc, et le FC des formes rouges, bleues et vertes sur noir. Ces images d’émulateur ne constituent pas une validation sur matériel réel.
Trois motifs originaux de 8 × 8 distinguent les copies : le 1 est plein, le 2 remplit les quatre colonnes de gauche et le 3 est un triangle aligné à gauche, large d’un pixel en haut et de huit en bas. Le bloc de 3 × 2 tuiles en (80,32) doit afficher [1,2,3] / [3,0,2], où 0 est vide. Son premier octet change après l’ajout ; la tuile pleine en haut à gauche prouve que le pointeur est conservé. La copie en (16,64) affiche [1,2,3] ; l’alias tiles en (48,64), [2,3]. Leurs tailles respectives sont de 24 × 16, 24 × 8 et 16 × 8 pixels.
Sur CGB, les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank sont rouges. Le rectangle de 32 × 24 et la copie de deux motifs sont bleus. Le bloc de 3 × 2 tuiles et la barre de 40 × 8 sont verts. Le texte reste noir sur blanc. La couleur de chaque pixel dessiné est vérifiée en plus de la géométrie.


Commande de compilation
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-disasmImplémentation et source
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 appelle directement vram_queue_memcpy. len compte toujours des octets, pas des tuiles. Le pointeur source, les enregistrements, la valeur renvoyée et le moment d’exécution sont identiques.
Syntaxe
u8 vram_queue_tiles(u16 dst, const void* src, u16 len);Paramètres
dstAdresse de destination en octets dans la VRAM (
0x8000–0x9FFF), dans la banque sélectionnée à l’exécution. Le transfert est contigu, sans saut de ligne. Toute la plage doit être valide. LCD actif, les chemins d’écriture sûrs peuvent activer les interruptions ; ils ne préservent pas un état d’appel où elles étaient désactivées.srcPointeur proche vers des octets lisibles, conservé jusqu’à l’exécution. Gardez les données vivantes et leur banque mémoire ou ROM accessible pendant tout le traitement ; aucun numéro de banque ni copie n’est mémorisé. Un transfert non vide exige une source valide. N’utilisez pas un tableau local dont la durée de vie est terminée.
lenNombre d’octets consécutifs, de 0 à 65535, pas de tuiles. Gardez toute la plage dans une source valide et une destination modifiable ; l’API ne vérifie pas les limites et n’empêche pas le bouclage d’adresse sur 16 bits.
Valeur renvoyée
1 si cet ordre a été ajouté, 0 si aucune place n’était libre. Un échec mémorise le débordement sans toucher aux ordres existants. Un débordement antérieur ne fait pas renvoyer 0 à un ajout ultérieur réussi.
Conditions et limites
GB compte des emplacements d’ordre : la capacité par défaut est 32. Chaque fonction d’ajout en utilise un, même pour un transfert long ou nul. Définissez VRAM_QUEUE_MAX uniformément dans toutes les unités, entre 1 et 255. Une file vide a used=0 et free=capacity.
Coordonnez la construction et la consommation de la file. N’ajoutez rien pendant son exécution par une interruption, ne modifiez pas directement ses compteurs et n’écrasez pas involontairement les sources conservées. Ces API n’offrent ni verrouillage ni double tampon. La capacité concerne le tampon d’ordres, pas les octets libres de VRAM physique.
Exemple d’utilisation
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.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Le programme complet présente les écritures différées, le suivi de capacité et la reprise après débordement. Sept appels de dessin occupent 7 des 32 emplacements sur GB, ou 52 des 128 octets sur FC : CAPACITY/USED/FREE affiche 032/007/025 ou 128/052/076. AFTER FLUSH et FAILED CHECKS doivent valoir 000, et OVERFLOW SEEN, 001. Un ajout volontaire à une file pleine teste l’indicateur : ni la lecture ni l’exécution ne l’effacent, contrairement à la remise à zéro de la file. Sur FC, l’exécution directe sans validation doit laisser la file intacte.
Les coordonnées sont en pixels depuis le coin supérieur gauche. On attend des carrés pleins de 8 × 8 en (16,16) et (32,16), un rectangle plein de 32 × 24 en (16,32) et une barre horizontale de 40 × 8 en (80,64). L’écriture finale en VBlank ajoute un carré de 8 × 8 en (144,80). L’écriture annulée en (144,24) doit laisser cette case vide. Le DMG affiche des formes noires sur blanc, le CGB des formes rouges, bleues et vertes sur blanc, et le FC des formes rouges, bleues et vertes sur noir. Ces images d’émulateur ne constituent pas une validation sur matériel réel.
Trois motifs originaux de 8 × 8 distinguent les copies : le 1 est plein, le 2 remplit les quatre colonnes de gauche et le 3 est un triangle aligné à gauche, large d’un pixel en haut et de huit en bas. Le bloc de 3 × 2 tuiles en (80,32) doit afficher [1,2,3] / [3,0,2], où 0 est vide. Son premier octet change après l’ajout ; la tuile pleine en haut à gauche prouve que le pointeur est conservé. La copie en (16,64) affiche [1,2,3] ; l’alias tiles en (48,64), [2,3]. Leurs tailles respectives sont de 24 × 16, 24 × 8 et 16 × 8 pixels.
Sur CGB, les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank sont rouges. Le rectangle de 32 × 24 et la copie de deux motifs sont bleus. Le bloc de 3 × 2 tuiles et la barre de 40 × 8 sont verts. Le texte reste noir sur blanc. La couleur de chaque pixel dessiné est vérifiée en plus de la géométrie.


Commande de compilation
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-disasmImplémentation et source
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 — Rendu filaire pour DMG
Dessin de lignes 3D monochromes. Fournissez sommets, arêtes et faces du modèle, ainsi que position, rotation et échelle de l’objet. Suivez l’ordre initialisation, début d’image, dessin, transfert. La physique est séparée. Les angles ont seize pas par tour ; l’échelle de modèle 256 vaut l’unité.
Vec3 contient x/y/z, Edge les indices de sommets a/b, et Face les indices de triangle a/b/c. Les champs vertices, edges et faces de Model pointent vers ces tableaux ; chaque compteur en donne la longueur. edge_faces contient les indices des faces adjacentes f0/f1, avec FACE_NONE pour une face absente. MODEL_HIDDEN_LINES dans flags demande une sélection d’arêtes fondée sur les faces. L’aire projetée signée détermine l’orientation d’une face : l’ordre des sommets compte.
Object mémorise une référence au modèle, la position x/y/z, les angles rx/ry/rz, scale_q8 et visible. Les objets peuvent partager un modèle, mais le dessin ne copie pas les tables et ne change pas automatiquement leurs banques ROM. Gardez les données référencées lisibles pendant tout le dessin. L’Object CGB possède aussi un indice de couleur.
Le Model de hauteur 96 contient aussi edge_masks et edge_mask_count. Fournissez une table RAM de masques d’arêtes sur 16 bits sélectionnés selon le lacet de l’objet, ou mettez les deux champs à zéro si inutilisés.
Wire3D_BeginFrame
Commence le dessin d’une image et désactive le test d’occlusion.
Syntaxe
void Wire3D_BeginFrame();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96. Efface les pixels préparés et le masque d’occlusion, puis désactive le filtrage d’occlusion. L’image VRAM affichée et la file de tuiles BG en attente restent inchangées.
Cet exemple utilise le profil 128×96 ; son viewport commence à l’écran en (0,0). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.


Commande de compilation
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-disasmImplémentation et source
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
Trace dans la zone de préparation une ligne en coordonnées écran à connexité 4, extrémités incluses.
Syntaxe
void Wire3D_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by);Paramètres
axCoordonnée X du sommet A en pixels du viewport.
ayCoordonnée Y du sommet A en pixels du viewport.
bxCoordonnée X du sommet B en pixels du viewport.
byCoordonnée Y du sommet B en pixels du viewport.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96. Trace une ligne connexe dans la zone de préparation de 128×96, extrémités incluses. Pendant DrawScene, utilise le rejet d’occlusion grossier à cinq échantillons ; sinon, trace directement. Fournissez des coordonnées du viewport. Seul EndFrame met à jour la VRAM.
Cet exemple utilise le profil 128×96 ; son viewport commence à l’écran en (0,0). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.


Commande de compilation
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-disasmImplémentation et source
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
Projette deux extrémités du monde et trace une ligne entre elles.
Syntaxe
void Wire3D_DrawLine3D(w3ddmg_i16 ax, w3ddmg_i16 ay, w3ddmg_i16 az, w3ddmg_i16 bx, w3ddmg_i16 by, w3ddmg_i16 bz);Paramètres
axComposante X du point de départ en coordonnées du monde.
ayComposante Y du point de départ en coordonnées du monde.
azComposante Z du point de départ en coordonnées du monde.
bxComposante X du point d’arrivée en coordonnées du monde.
byComposante Y du point d’arrivée en coordonnées du monde.
bzComposante Z du point d’arrivée en coordonnées du monde.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96. Projette les deux extrémités du monde et dessine uniquement si les deux passent la plage de profondeur. Ne calcule pas l’intersection d’un segment traversant avec les plans proche ou lointain ; chaque extrémité projetée est bornée indépendamment aux bords de l’écran.
Cet exemple utilise le profil 128×96 ; son viewport commence à l’écran en (0,0). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.


Commande de compilation
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-disasmImplémentation et source
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
Dessine un modèle de sommets et d’arêtes à la position et avec la rotation demandées, à l’échelle unitaire.
Syntaxe
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);Paramètres
modelModèle contenant les tableaux de sommets, d’arêtes et de faces, ainsi que leurs nombres ; ses tables doivent rester lisibles pendant l’appel.
xComposante X du point ou de l’origine de l’objet en coordonnées du monde.
yComposante Y du point ou de l’origine de l’objet en coordonnées du monde.
zComposante Z du point ou de l’origine de l’objet en coordonnées du monde.
rxRotation autour de X ; seize pas font un tour complet.
ryRotation autour de Y ; seize pas font un tour complet.
rzRotation autour de Z ; seize pas font un tour complet.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96. Dessine un modèle sans redimensionnement en appelant DrawModelScaled avec l’échelle 256.
Cet exemple utilise le profil 128×96 ; son viewport commence à l’écran en (0,0). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Des modèles à l’échelle unitaire et à demi-échelle apparaissent au-dessus d’une scène issue d’un tableau d’objets aux mêmes échelles, illustrant projection et redimensionnement.


Commande de compilation
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-disasmImplémentation et source
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
Redimensionne un modèle, le tourne dans l’ordre Y/X/Z, translate et projette ses sommets, puis trace ses arêtes.
Syntaxe
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);Paramètres
modelModèle contenant les tableaux de sommets, d’arêtes et de faces, ainsi que leurs nombres ; ses tables doivent rester lisibles pendant l’appel.
xComposante X du point ou de l’origine de l’objet en coordonnées du monde.
yComposante Y du point ou de l’origine de l’objet en coordonnées du monde.
zComposante Z du point ou de l’origine de l’objet en coordonnées du monde.
rxRotation autour de X ; seize pas font un tour complet.
ryRotation autour de Y ; seize pas font un tour complet.
rzRotation autour de Z ; seize pas font un tour complet.
scale_q8Échelle dont l’unité vaut 256 ; les valeurs nulles ou négatives signifient aussi l’unité.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96. Redimensionne au plus 24 sommets, les tourne dans l’ordre Y/X/Z, les translate et les projette ; trace ensuite au plus 16 arêtes filtrées par masques de lacet et, éventuellement, par faces avant. Une échelle non positive devient l’unité (256). Les pointeurs de modèle, sommets ou arêtes nuls sont ignorés ; les tables référencées doivent rester lisibles. Produits d’échelle et translations doivent tenir sur 16 bits signés. Les arêtes traversant une limite de profondeur sont rejetées, pas découpées.
Cet exemple utilise le profil 128×96 ; son viewport commence à l’écran en (0,0). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Des modèles à l’échelle unitaire et à demi-échelle apparaissent au-dessus d’une scène issue d’un tableau d’objets aux mêmes échelles, illustrant projection et redimensionnement.


Commande de compilation
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-disasmImplémentation et source
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
Dessine au plus huit objets du plus proche au plus lointain, les faces proches masquant les arêtes suivantes.
Syntaxe
void Wire3D_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count);Paramètres
objectsTableau d’objets contenant positions, rotations, échelles et indicateurs de visibilité.
countNombre d’entrées fournies ; consultez la limite de traitement propre à l’opération.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96. Traite au plus les huit premiers objets, triés du plus proche au plus lointain selon la profondeur de leur origine transformée. Dessine les modèles visibles et valides, puis marque les rectangles englobants de leurs faces avant pour rejeter les lignes suivantes dont tous les points échantillonnés sont masqués. C’est une approximation de l’occlusion entre objets, pas un tampon de profondeur. Efface son masque mais conserve les pixels déjà préparés. Ignore les tableaux null ; les objets et leurs données doivent rester lisibles.
Cet exemple utilise le profil 128×96 ; son viewport commence à l’écran en (0,0). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Des modèles à l’échelle unitaire et à demi-échelle apparaissent au-dessus d’une scène issue d’un tableau d’objets aux mêmes échelles, illustrant projection et redimensionnement.


Commande de compilation
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-disasmImplémentation et source
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
Soumet à la VRAM les écritures du fond en attente et le dessin préparé.
Syntaxe
void Wire3D_EndFrame();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96. Attend le prochain VBlank, applique les écritures BG en attente, puis copie la zone de préparation en VRAM en interrogeant les fenêtres d’accès. La copie consomme les pixels préparés. Le transfert peut dépasser le VBlank ; ce n’est pas un échange atomique d’image.
Cet exemple utilise le profil 128×96 ; son viewport commence à l’écran en (0,0). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.


Commande de compilation
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-disasmImplémentation et source
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
Projette les triangles avant du modèle et efface les pixels préparés à l’intérieur.
Syntaxe
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);Paramètres
modelModèle contenant les tableaux de sommets, d’arêtes et de faces, ainsi que leurs nombres ; ses tables doivent rester lisibles pendant l’appel.
xComposante X du point ou de l’origine de l’objet en coordonnées du monde.
yComposante Y du point ou de l’origine de l’objet en coordonnées du monde.
zComposante Z du point ou de l’origine de l’objet en coordonnées du monde.
rxRotation autour de X ; seize pas font un tour complet.
ryRotation autour de Y ; seize pas font un tour complet.
rzRotation autour de Z ; seize pas font un tour complet.
scale_q8Échelle dont l’unité vaut 256 ; les valeurs nulles ou négatives signifient aussi l’unité.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96. Projette au plus 24 sommets et efface l’intérieur des triangles avant dans la zone de préparation, pour un modèle doté d’indicateurs de lignes cachées et de données de faces. Une échelle non positive signifie 256, soit l’unité. Examine au plus 16 faces ; celles traversant une limite de profondeur sont ignorées. Remplace aussi les caches de projection partagés, sans mettre à jour la VRAM.
Cet exemple utilise le profil 128×96 ; son viewport commence à l’écran en (0,0). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Les faces projetées effacent une région remplie, rendant visibles les zones conservées et effacées.


Commande de compilation
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-disasmImplémentation et source
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
Efface un segment horizontal, bornes incluses, sur une ligne préparée.
Syntaxe
void Wire3D_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1);Paramètres
yCoordonnée Y en pixels de la ligne à effacer.
x0Borne X inférieure, en pixels du viewport ; l’ordre et le découpage suivent les notes de cette opération.
x1Borne X supérieure, en pixels du viewport ; l’ordre et le découpage suivent les notes de cette opération.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96. Ordonne les extrémités X et efface le segment préparé, bornes incluses. Les deux extrémités doivent être dans 0..127 ; un Y invalide est ignoré. La routine ne découpe pas X à votre place.
Cet exemple utilise le profil 128×96 ; son viewport commence à l’écran en (0,0). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.


Commande de compilation
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-disasmImplémentation et source
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
Efface un triangle en coordonnées écran dans la zone de préparation, par segments horizontaux de lignes de balayage.
Syntaxe
void Wire3D_EraseTriangle2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by, w3ddmg_u8 cx, w3ddmg_u8 cy);Paramètres
axCoordonnée X du sommet A en pixels du viewport.
ayCoordonnée Y du sommet A en pixels du viewport.
bxCoordonnée X du sommet B en pixels du viewport.
byCoordonnée Y du sommet B en pixels du viewport.
cxCoordonnée X du sommet C en pixels du viewport.
cyCoordonnée Y du sommet C en pixels du viewport.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96. Efface un triangle dans les pixels préparés à l’aide d’intersections entières avec les lignes de balayage. Fournissez des coordonnées du viewport. Les triangles dégénérés sont ignorés ; masque d’occlusion et VRAM restent inchangés.
Cet exemple utilise le profil 128×96 ; son viewport commence à l’écran en (0,0). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Les faces projetées effacent une région remplie, rendant visibles les zones conservées et effacées.


Commande de compilation
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-disasmImplémentation et source
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
Initialise le LCD, les tuiles et la carte du fond pour un viewport filaire monochrome.
Syntaxe
void Wire3D_Init();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96. Prend le contrôle du LCD : attend le VBlank, l’éteint, efface 6144 octets de tuiles et la carte BG, installe les tuiles HUD et le viewport 128×96 à numéros de tuiles signés, puis active le fond avec défilement nul et BGP=0xB4. Réinitialise caméra, file BG et zone de préparation. Réservez 0xD000..0xDFFF pour cette zone et conservez son mappage de banque WRAM. Appelez BeginFrame avant de dessiner pour initialiser aussi l’occlusion.
Cet exemple utilise le profil 128×96 ; son viewport commence à l’écran en (0,0). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.


Commande de compilation
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-disasmImplémentation et source
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
Projette un point du monde par la caméra vers les coordonnées du viewport.
Syntaxe
w3ddmg_u8 Wire3D_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy);Paramètres
xComposante X du point ou de l’origine de l’objet en coordonnées du monde.
yComposante Y du point ou de l’origine de l’objet en coordonnées du monde.
zComposante Z du point ou de l’origine de l’objet en coordonnées du monde.
sxPointeur u8 valide et accessible en écriture recevant la coordonnée X projetée.
syPointeur u8 valide et accessible en écriture recevant la coordonnée Y projetée.
Valeur renvoyée
Renvoie 1 si la projection réussit, 0 si la profondeur est rejetée.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96. Projette un point du monde avec la caméra courante. Une profondeur rejetée renvoie zéro sans changer les sorties ; le succès écrit des coordonnées bornées à 128×96. Les pointeurs de sortie doivent être valides. Borner à l’écran n’est pas un découpage géométrique.
Cet exemple utilise le profil 128×96 ; son viewport commence à l’écran en (0,0). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.


Commande de compilation
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-disasmImplémentation et source
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
Met en file une écriture de numéro de tuile dans une case de la carte du fond.
Syntaxe
void Wire3D_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile);Paramètres
xCoordonnée X en tuiles dans la carte de fond de 32×32.
yCoordonnée Y en tuiles dans la carte de fond de 32×32.
tileNuméro de tuile sur huit bits pour la case du fond.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96. Met en file une écriture de tuile dans la carte 32×32 en 0x9800 pour EndFrame. Les coordonnées invalides et les soumissions au-delà de 48 écritures en attente sont ignorées sans signalement. Cette file est distincte de celle de la bibliothèque vram générale.
Cet exemple utilise le profil 128×96 ; son viewport commence à l’écran en (0,0). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.


Commande de compilation
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-disasmImplémentation et source
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
Choisit un masque précalculé de visibilité des arêtes selon le lacet de l’objet.
Syntaxe
w3ddmg_u16 Wire3D_SelectEdgeMask(const Wire3DDMG_Model* model, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz);Paramètres
modelModèle contenant les tableaux de sommets, d’arêtes et de faces, ainsi que leurs nombres ; ses tables doivent rester lisibles pendant l’appel.
rxRotation autour de X ; seize pas font un tour complet.
ryRotation autour de Y ; seize pas font un tour complet.
rzRotation autour de Z ; seize pas font un tour complet.
Valeur renvoyée
Masque de visibilité des arêtes sur 16 bits, ou 0xFFFF si aucune table n’est fournie.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96. Choisit un masque précalculé d’après les quatre bits faibles du lacet de l’objet ; tangage, roulis et orientation de caméra sont ignorés. Utilisez 16, 8, 4 ou 2 secteurs ; les autres nombres positifs sélectionnent l’entrée zéro, sauf qu’un nombre >=16 utilise les 16 premières. Sans données, renvoie 0xFFFF. La table de masques doit rester lisible avec le mappage courant des pointeurs de données.
Cet exemple utilise le profil 128×96 ; son viewport commence à l’écran en (0,0). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Des modèles à l’échelle unitaire et à demi-échelle apparaissent au-dessus d’une scène issue d’un tableau d’objets aux mêmes échelles, illustrant projection et redimensionnement.


Commande de compilation
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-disasmImplémentation et source
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
Mémorise la position et l’orientation de la caméra pour les projections suivantes.
Syntaxe
void Wire3D_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 pitch, w3ddmg_i8 yaw, w3ddmg_i8 roll);Paramètres
xComposante X de la caméra en coordonnées du monde.
yComposante Y de la caméra en coordonnées du monde.
zComposante Z de la caméra en coordonnées du monde.
pitchRotation autour de X ; seize pas font un tour complet.
yawRotation autour de Y ; seize pas font un tour complet.
rollRotation autour de Z ; seize pas font un tour complet.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96. Mémorise la position et les angles de caméra pour les dessins suivants ; un tour compte 16 pas angulaires. Ne reprojette pas les dessins existants et ne valide pas les plages d’entrée.
Cet exemple utilise le profil 128×96 ; son viewport commence à l’écran en (0,0). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.


Commande de compilation
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-disasmImplémentation et source
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
Écrit la correspondance des quatre nuances dans le registre de palette du fond monochrome BGP.
Syntaxe
void Wire3D_SetPalette(w3ddmg_u8 bgp);Paramètres
bgpValeur du registre BGP contenant quatre affectations de nuance sur deux bits.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96. Écrit immédiatement l’encodage brut de la palette DMG BGP, sans synchronisation d’image.
Cet exemple utilise le profil 128×96 ; son viewport commence à l’écran en (0,0). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.


Commande de compilation
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-disasmImplémentation et source
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 — Rendu filaire couleur pour CGB
Utilisation des chemins de rendu rapide
Le rendu normal en 128×96 fait avancer les adresses de dessin progressivement. Pour une ligne sans occlusion, il choisit le plan de couleur une seule fois et garde le nombre de pixels et l’erreur dans les registres CPU. Les lignes avec occlusion choisissent également les plans une fois par ligne et font avancer progressivement les adresses de dessin et de masque. Chaque pixel teste son bit de masque et n’est écrit que s’il n’est pas masqué. Le rendu en 160×144 et FastMap ont chacun leurs chemins dédiés. Les rotations de 0, 90, 180 et 270 degrés bornent les entrées, puis échangent les coordonnées et changent les signes. Les performances du jeu dépendent aussi du nombre de sommets, de la longueur des arêtes, de l’occlusion et des transferts VRAM. Mesurez séparément chaque opération et le temps nécessaire pour achever une image affichée.
Rendu filaire couleur pour CGB. Le moteur par pixels de 128×96, l’allocateur de tuiles de 160×144 et FastMap à tuiles de contour ont des séquences d’initialisation et de transfert distinctes. L’appelant possède sommets, arêtes et faces triangulaires. Ce module ne simule pas la physique.
Vec3 contient x/y/z, Edge les indices de sommets a/b, et Face les indices de triangle a/b/c. Les champs vertices, edges et faces de Model pointent vers ces tableaux ; chaque compteur en donne la longueur. edge_faces contient les indices des faces adjacentes f0/f1, avec FACE_NONE pour une face absente. MODEL_HIDDEN_LINES dans flags demande une sélection d’arêtes fondée sur les faces. L’aire projetée signée détermine l’orientation d’une face : l’ordre des sommets compte.
Object mémorise une référence au modèle, la position x/y/z, les angles rx/ry/rz, scale_q8 et visible. Les objets peuvent partager un modèle, mais le dessin ne copie pas les tables et ne change pas automatiquement leurs banques ROM. Gardez les données référencées lisibles pendant tout le dessin. L’Object CGB possède aussi un indice de couleur.
Les x/y de FastCube sont des décalages par rapport au centre de l’écran ; z choisit la taille ou l’ordre de dessin. FastCubes ignore les angles, tandis que FastCubeFrame utilise rx/ry/rz pour choisir parmi quatre variantes de motifs. Ces affichages simplifiés ont un autre usage que DrawModel, qui projette par la caméra.
Wire3DCGB_BeginFrame
Commence une nouvelle image vide dans le mode de rendu choisi.
Syntaxe
void Wire3DCGB_BeginFrame();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
En mode normal, sélectionne le transfert intégral de la zone de préparation, efface tous ses pixels et le masque bitmap, réinitialise les limites du masque et désactive l’occlusion. En plein écran, réinitialise à la place l’allocateur et les segments de ce mode. Les écritures BG en attente restent dans la file. Nécessite une compilation avec le runtime complet.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Au démarrage sparse CGB, la première utilisation de chaque banque cible (les deux premières images) actualise tout le viewport et efface les tuiles d’initialisation. Cette charge est incluse dans les mesures. DrawLine2D ne déclare pas de zone sparse : utilisez DrawLineClipped2D ou MarkDirtyRect2D explicitement.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre les lignes, les points, l’effacement et la projection de base dans une seule image. Un cadre rouge contient une diagonale bleue, avec un point et une ligne horizontale verts, un L bleu et un zéro vert en haut à droite.
Commande de compilation
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-disasmImplémentation et source
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
Commence une image effacée et invalide les anciennes plages partielles en les étendant à tout le viewport.
Syntaxe
void Wire3DCGB_BeginFrameFast();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Effectue la même réinitialisation d’image normale ou plein écran que BeginFrame, mais étend d’abord chacune des deux plages de l’historique partiel à la totalité des 192 tuiles du viewport. Ainsi, le prochain transfert partiel ne se fie pas à des banques périmées.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Au démarrage sparse CGB, la première utilisation de chaque banque cible (les deux premières images) actualise tout le viewport et efface les tuiles d’initialisation. Cette charge est incluse dans les mesures. DrawLine2D ne déclare pas de zone sparse : utilisez DrawLineClipped2D ou MarkDirtyRect2D explicitement.
Exemple d’utilisation
#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) {}
}Résultat attendu
Les cadres rouge et bleu dessinés précédemment disparaissent ; seul reste le cadre vert final de (80,8) à (112,32), ce qui illustre le transfert partiel et la gestion de l’historique.
Commande de compilation
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-disasmImplémentation et source
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
Commence une image destinée au transfert de plages partielles.
Syntaxe
void Wire3DCGB_BeginFrameSparse();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Sélectionne le transfert partiel et efface toute la zone de préparation de 128×96 pour éviter les anciens pixels lorsque la plage modifiée s’agrandit. Réinitialise les limites du masque et désactive l’occlusion ; les builds PAINTER_ONLY n’effacent pas le masque bitmap inutilisé. Le mode plein écran délègue à la réinitialisation de son propre allocateur.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Au démarrage sparse CGB, la première utilisation de chaque banque cible (les deux premières images) actualise tout le viewport et efface les tuiles d’initialisation. Cette charge est incluse dans les mesures. DrawLine2D ne déclare pas de zone sparse : utilisez DrawLineClipped2D ou MarkDirtyRect2D explicitement.
Exemple d’utilisation
#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) {}
}Résultat attendu
Les cadres rouge et bleu dessinés précédemment disparaissent ; seul reste le cadre vert final de (80,8) à (112,32), ce qui illustre le transfert partiel et la gestion de l’historique.
Commande de compilation
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-disasmImplémentation et source
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
Efface les tuiles de l’image affichée en 128×96 et la zone de préparation.
Syntaxe
void Wire3DCGB_ClearFrameTiles();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Pour le moteur de 128×96, attend le VBlank, éteint le LCD, efface la zone de préparation et les plages de tuiles de l’image dans les deux banques, réinitialise les attributs de carte, puis active LCDC 0x81. Efface les indicateurs et compteurs de modification, mais conserve l’historique min/max des transferts partiels. Ne réinitialise pas full_mode et ne réinitialise pas le mode plein écran.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Au démarrage sparse CGB, la première utilisation de chaque banque cible (les deux premières images) actualise tout le viewport et efface les tuiles d’initialisation. Cette charge est incluse dans les mesures. DrawLine2D ne déclare pas de zone sparse : utilisez DrawLineClipped2D ou MarkDirtyRect2D explicitement.
Exemple d’utilisation
#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) {}
}Résultat attendu
Les cadres rouge et bleu dessinés précédemment disparaissent ; seul reste le cadre vert final de (80,8) à (112,32), ce qui illustre le transfert partiel et la gestion de l’historique.
Commande de compilation
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-disasmImplémentation et source
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
Efface le bitmap d’occlusion ou l’historique des segments plein écran.
Syntaxe
void Wire3DCGB_ClearOcclusionMask();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Si full_mode est actif, efface l’historique des segments plein écran ; sinon, efface le masque bitmap de 128×96 et ses limites. N’efface pas les pixels affichés ou préparés et ne change pas l’activation du test d’occlusion.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Un triangle masque le milieu des lignes de balayage rouges ; une silhouette compactée masque les lignes bleues. Les contours verts situent la région occultante.
Commande de compilation
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-disasmImplémentation et source
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
Efface toute la zone de préparation et marque tout le viewport de 128×96 pour transfert.
Syntaxe
void Wire3DCGB_ClearSparseStageFast();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Efface toute la zone de préparation de la banque 2 et marque l’intégralité du viewport de 128×96 comme modifiée. Malgré son nom, ce n’est pas un effacement partiel et aucun pixel préparé n’est conservé. Ne réinitialise pas l’occlusion et ne choisit pas de mode de transfert.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Les cadres rouge et bleu dessinés précédemment disparaissent ; seul reste le cadre vert final de (80,8) à (112,32), ce qui illustre le transfert partiel et la gestion de l’historique.
Commande de compilation
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-disasmImplémentation et source
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
Trace au plus 64 arêtes à partir de décalages de sommets préprojetés sur octets signés.
Syntaxe
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);Paramètres
edgesIndices des sommets de chaque arête, dans le format déclaré de structure ou de paire d’octets.
edge_countNombre d’arêtes.
vertex_xTableau des décalages X des sommets préprojetés.
vertex_yTableau des décalages Y des sommets préprojetés.
xCoordonnée X du centre en pixels du viewport.
yCoordonnée Y du centre en pixels du viewport.
colorIndice de couleur de dessin ; les palettes d’exemple utilisent 1=rouge, 2=bleu et 3=vert.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Trace au plus 64 arêtes indexées à partir de décalages sur octets signés autour de (cx,cy). Ignore les tableaux null ; les indices doivent désigner des sommets lisibles. Gardez les extrémités translatées dans le viewport avant la conversion en octets, qui boucle. Choisit selon le mode et préserve l’ancienne couleur ; aucun contrôle du nombre de sommets n’est effectué.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Deux arêtes horizontales rouges, un carré bleu, un cadre vert découpé, un repère vert de six pixels et un projectile rouge permettent de comparer les formats de listes.
Commande de compilation
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-disasmImplémentation et source
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
Valide les sommets projetés signés et les arêtes, puis découpe et trace la liste d’arêtes.
Syntaxe
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);Paramètres
edgesIndices des sommets de chaque arête, dans le format déclaré de structure ou de paire d’octets.
edge_countNombre d’arêtes.
vxTableau de décalages X signés sur 16 bits avant découpage.
vyTableau de décalages Y signés sur 16 bits avant découpage.
vertex_countNombre d’entrées du tableau de sommets.
cxCoordonnée X du centre en pixels du viewport.
cyCoordonnée Y du centre en pixels du viewport.
colorIndice de couleur de dessin ; les palettes d’exemple utilisent 1=rouge, 2=bleu et 3=vert.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Avant de dessiner, valide les pointeurs, 1 à 24 sommets, au plus 64 arêtes, chaque indice et les coordonnées et centres d’entrée dans ±2047. La géométrie entièrement visible utilise un tampon temporaire d’octets signés et le chemin indexé rapide ; les autres arêtes passent par le découpage de lignes signées. Celui-ci peut rejeter des extrémités translatées hors de ±2047 même si chaque entrée a passé la validation. Remplace le tampon d’écran partagé et préserve la couleur précédente via les API de lignes appelées.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Deux arêtes horizontales rouges, un carré bleu, un cadre vert découpé, un repère vert de six pixels et un projectile rouge permettent de comparer les formats de listes.
Commande de compilation
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-disasmImplémentation et source
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
Remplace l’image précédente de motifs de cube et transfère au plus trois motifs avec leurs indicateurs d’état.
Syntaxe
void Wire3DCGB_DrawFastCubeFrame(Wire3DCGB_FastCube* cubes, w3dcgb_u8 count, w3dcgb_u8 hidden_enabled, w3dcgb_u8 selected);Paramètres
cubesTableau de positions, angles et couleurs pour le dessin rapide de cubes.
countNombre d’entrées fournies ; consultez la limite de traitement propre à l’opération.
hidden_enabledZéro inclut les arêtes cachées ; une valeur non nulle choisit leur suppression simplifiée.
selectedIndice de l’objet sélectionné dans le tableau original ; l’API de motifs l’utilise pour un indicateur d’état.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Prépare la carte, efface les anciennes limites et cases d’état, trie au plus trois motifs de cube du plus loin au plus près selon le Z brut, puis dessine et transfère numéros et attributs au VBlank. Le tableau de l’appelant reste dans son ordre. Avec un tableau non nul, count zéro efface les anciens motifs ; un tableau null ne fait rien. selected & 3 choisit seulement la case d’état, pas une mise en évidence du cube. Nécessite les motifs chargés, le runtime complet et un mappage WRAM FastMap cohérent ; ne les initialise pas.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Au démarrage sparse CGB, la première utilisation de chaque banque cible (les deux premières images) actualise tout le viewport et efface les tuiles d’initialisation. Cette charge est incluse dans les mesures. DrawLine2D ne déclare pas de zone sparse : utilisez DrawLineClipped2D ou MarkDirtyRect2D explicitement.
Exemple d’utilisation
#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) {}
}Résultat attendu
L’ancien motif de cube disparaît. Un cube rouge de 32×32 commence en (72,32), avec des indicateurs d’état verts en haut.
Commande de compilation
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-disasmImplémentation et source
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
Dessine au plus trois cubes sous forme de contours 2D dimensionnés selon la profondeur.
Syntaxe
void Wire3DCGB_DrawFastCubes(Wire3DCGB_FastCube* cubes, w3dcgb_u8 count, w3dcgb_u8 hidden_enabled, w3dcgb_u8 selected);Paramètres
cubesTableau de positions, angles et couleurs pour le dessin rapide de cubes.
countNombre d’entrées fournies ; consultez la limite de traitement propre à l’opération.
hidden_enabledZéro inclut les arêtes cachées ; une valeur non nulle choisit leur suppression simplifiée.
selectedIndice de l’objet sélectionné dans le tableau original ; l’API de motifs l’utilise pour un indicateur d’état.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Dessine au plus trois approximations 2D de cubes, triées du plus loin au plus près selon le Z brut sans réordonner le tableau de l’appelant. Ignore null ou une entrée vide. selected est un indice du tableau original. Caméra et rotation ne sont pas utilisées ; la couleur n’est pas restaurée.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Le cube rouge proche à gauche est plus grand que le cube bleu lointain à droite. Une croix verte marque le cube rouge sélectionné.
Commande de compilation
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-disasmImplémentation et source
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
Dessine un projectile à six arêtes autour d’un centre déjà projeté, la profondeur et la phase choisissant sa taille et son orientation.
Syntaxe
void Wire3DCGB_DrawFastProjectile(w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_i16 z, w3dcgb_u8 phase, w3dcgb_u8 color);Paramètres
xCoordonnée X du centre en pixels du viewport.
yCoordonnée Y du centre en pixels du viewport.
zProfondeur utilisée pour choisir la taille ou calculer la projection.
phasePhase de rotation ; passe à l’orientation suivante tous les huit comptes.
colorIndice de couleur de dessin ; les palettes d’exemple utilisent 1=rouge, 2=bleu et 3=vert.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Dessine un projectile à six arêtes autour d’un centre déjà projeté, avec quatre tailles selon la profondeur et quatre orientations selon la phase. Rejette les centres hors de X=10..117 ou Y=10..85, marque les limites modifiées et laisse la couleur demandée sélectionnée. Utilise le rastériseur normal sans appliquer la caméra.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Deux arêtes horizontales rouges, un carré bleu, un cadre vert découpé, un repère vert de six pixels et un projectile rouge permettent de comparer les formats de listes.
Commande de compilation
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-disasmImplémentation et source
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
Dessine de petits indicateurs en lignes pour la sélection d’objet et le mode de lignes cachées.
Syntaxe
void Wire3DCGB_DrawFastStatus(w3dcgb_u8 hidden_enabled, w3dcgb_u8 selected);Paramètres
hidden_enabledZéro inclut les arêtes cachées ; une valeur non nulle choisit leur suppression simplifiée.
selectedIndice de l’objet sélectionné dans le tableau original ; l’API de motifs l’utilise pour un indicateur d’état.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Dessine de petits indicateurs de sélection et de mode de lignes cachées en couleur 3, et marque leurs limites normales comme modifiées. selected doit valoir 0..2, sans vérification. Ces indicateurs utilisent des lignes, pas des tuiles de police ; la couleur précédente n’est pas restaurée.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Le cube rouge proche à gauche est plus grand que le cube bleu lointain à droite. Une croix verte marque le cube rouge sélectionné.
Commande de compilation
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-disasmImplémentation et source
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
Trace une ligne en coordonnées écran, extrémités incluses, avec le moteur actif.
Syntaxe
void Wire3DCGB_DrawLine2D(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by);Paramètres
axCoordonnée X du sommet A en pixels du viewport.
ayCoordonnée Y du sommet A en pixels du viewport.
bxCoordonnée X du sommet B en pixels du viewport.
byCoordonnée Y du sommet B en pixels du viewport.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Mémorise les extrémités sur octets et appelle le rastériseur de lignes normal ou plein écran. Les coordonnées doivent être dans le viewport choisi ; utilisez DrawLineClipped2D pour une géométrie signée ou hors écran. Les lignes normales combinent les plans de couleur par OR sans marquer les limites partielles ; utilisez l’API avec découpage ou InvalidateFrameHistory avant un transfert partiel. Les lignes plein écran remplacent les couleurs et allouent des tuiles. Les deux chemins traitent la couleur zéro comme 3, pas comme un effacement.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre les lignes, les points, l’effacement et la projection de base dans une seule image. Un cadre rouge contient une diagonale bleue, avec un point et une ligne horizontale verts, un L bleu et un zéro vert en haut à droite.
Commande de compilation
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-disasmImplémentation et source
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
Trace une ligne en coordonnées écran dans une couleur temporaire, en préservant la couleur sélectionnée.
Syntaxe
void Wire3DCGB_DrawLine2DColor(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by, w3dcgb_u8 color);Paramètres
axCoordonnée X du sommet A en pixels du viewport.
ayCoordonnée Y du sommet A en pixels du viewport.
bxCoordonnée X du sommet B en pixels du viewport.
byCoordonnée Y du sommet B en pixels du viewport.
colorIndice de couleur de dessin ; les palettes d’exemple utilisent 1=rouge, 2=bleu et 3=vert.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Définit color & 3 pour DrawLine2D, puis restaure la couleur précédente. Respectez son contrat de coordonnées, de combinaison des couleurs et de plages partielles ; zéro n’efface une ligne dans aucun des deux moteurs actifs.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre les lignes, les points, l’effacement et la projection de base dans une seule image. Un cadre rouge contient une diagonale bleue, avec un point et une ligne horizontale verts, un L bleu et un zéro vert en haut à droite.
Commande de compilation
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-disasmImplémentation et source
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
Projette les extrémités du monde par la caméra et trace une ligne dans la couleur courante.
Syntaxe
void Wire3DCGB_DrawLine3D(w3dcgb_i16 ax, w3dcgb_i16 ay, w3dcgb_i16 az, w3dcgb_i16 bx, w3dcgb_i16 by, w3dcgb_i16 bz);Paramètres
axComposante X du point de départ en coordonnées du monde.
ayComposante Y du point de départ en coordonnées du monde.
azComposante Z du point de départ en coordonnées du monde.
bxComposante X du point d’arrivée en coordonnées du monde.
byComposante Y du point d’arrivée en coordonnées du monde.
bzComposante Z du point d’arrivée en coordonnées du monde.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Projette les deux extrémités par la caméra vers le viewport de 128×96. Rejette toute la ligne si une extrémité échoue au test de profondeur ; ne découpe pas les traversées du plan proche. DrawLine2D choisit selon le mode, mais la projection reste en 128×96. Les lignes normales cumulent les plans de couleur sans marquer les limites partielles ; utilisez un transfert complet ou invalidez explicitement l’historique avant un transfert partiel.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Compare les modèles à l’échelle unitaire et redimensionnés en rouge, bleu et vert, ainsi que des lignes 3D qui se croisent. Les valeurs en RAM vérifient aussi la projection de caméra et sa variante sans rotation.
Commande de compilation
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-disasmImplémentation et source
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
Trace une ligne 3D dans une couleur temporaire.
Syntaxe
void Wire3DCGB_DrawLine3DColor(w3dcgb_i16 ax, w3dcgb_i16 ay, w3dcgb_i16 az, w3dcgb_i16 bx, w3dcgb_i16 by, w3dcgb_i16 bz, w3dcgb_u8 color);Paramètres
axComposante X du point de départ en coordonnées du monde.
ayComposante Y du point de départ en coordonnées du monde.
azComposante Z du point de départ en coordonnées du monde.
bxComposante X du point d’arrivée en coordonnées du monde.
byComposante Y du point d’arrivée en coordonnées du monde.
bzComposante Z du point d’arrivée en coordonnées du monde.
colorIndice de couleur de dessin ; les palettes d’exemple utilisent 1=rouge, 2=bleu et 3=vert.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Sélectionne temporairement color & 3 pour DrawLine3D, puis restaure l’ancienne couleur.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Compare les modèles à l’échelle unitaire et redimensionnés en rouge, bleu et vert, ainsi que des lignes 3D qui se croisent. Les valeurs en RAM vérifient aussi la projection de caméra et sa variante sans rotation.
Commande de compilation
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-disasmImplémentation et source
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
Découpe les coordonnées d’écran signées au viewport et trace une ligne dans la couleur demandée.
Syntaxe
void Wire3DCGB_DrawLineClipped2D(w3dcgb_i16 x0, w3dcgb_i16 y0, w3dcgb_i16 x1, w3dcgb_i16 y1, w3dcgb_u8 color);Paramètres
x0Borne X inférieure, en pixels du viewport ; l’ordre et le découpage suivent les notes de cette opération.
y0Borne Y inférieure, en pixels du viewport ; l’ordre et le découpage suivent les notes de cette opération.
x1Borne X supérieure, en pixels du viewport ; l’ordre et le découpage suivent les notes de cette opération.
y1Borne Y supérieure, en pixels du viewport ; l’ordre et le découpage suivent les notes de cette opération.
colorIndice de couleur de dessin ; les palettes d’exemple utilisent 1=rouge, 2=bleu et 3=vert.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Les extrémités signées sont découpées avant conversion vers l’ABI u8 du rastériseur. Découpe une ligne 2D signée au viewport choisi, puis la trace avec une couleur temporaire. Rejette les entrées hors de ±2047. Les lignes entièrement dans 128×96 utilisent un chemin rapide ; les autres utilisent des codes de région et des intersections entières bornées, avec une limite de huit itérations. Les lignes acceptées en mode normal marquent les limites modifiées. Ce n’est qu’un découpage à l’écran, sans projection 3D ni découpage en profondeur.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre les lignes, les points, l’effacement et la projection de base dans une seule image. Un cadre rouge contient une diagonale bleue, avec un point et une ligne horizontale verts, un L bleu et un zéro vert en haut à droite.
Commande de compilation
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-disasmImplémentation et source
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
Trace une liste de lignes en coordonnées écran, à quatre octets par enregistrement, dans la couleur choisie.
Syntaxe
void Wire3DCGB_DrawLineList2DColor(const w3dcgb_u8* line_xy, w3dcgb_u8 line_count, w3dcgb_u8 color);Paramètres
line_xyTableau d’octets d’enregistrements x0,y0,x1,y1.
line_countNombre d’enregistrements de lignes ; au plus 64 sont traités.
colorIndice de couleur de dessin ; les palettes d’exemple utilisent 1=rouge, 2=bleu et 3=vert.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Trace au plus 64 enregistrements de quatre octets (x0,y0,x1,y1), en ignorant une liste null. Les extrémités doivent être dans le viewport choisi. Préserve la couleur précédente et envoie chaque ligne au rastériseur normal ou plein écran.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre les lignes, les points, l’effacement et la projection de base dans une seule image. Un cadre rouge contient une diagonale bleue, avec un point et une ligne horizontale verts, un L bleu et un zéro vert en haut à droite.
Commande de compilation
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-disasmImplémentation et source
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
Trace les arêtes activées à partir de sommets préprojetés et d’un masque de bits d’arêtes.
Syntaxe
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);Paramètres
modelModèle contenant les tableaux de sommets, d’arêtes et de faces, ainsi que leurs nombres ; ses tables doivent rester lisibles pendant l’appel.
vertex_xTableau des décalages X des sommets préprojetés.
vertex_yTableau des décalages Y des sommets préprojetés.
edge_maskTableau d’octets avec un bit de visibilité par arête, bit de poids faible en premier.
xCoordonnée X du centre en pixels du viewport.
yCoordonnée Y du centre en pixels du viewport.
colorIndice de couleur de dessin ; les palettes d’exemple utilisent 1=rouge, 2=bleu et 3=vert.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Trace les arêtes activées du modèle à partir de décalages préprojetés sur octets signés autour de (x,y). Les bits du masque commencent par le moins significatif, huit arêtes par octet. Tous les pointeurs et indices doivent être valides ; edge_mask[0] est lu même pour zéro arête. Aucun compteur n’est plafonné. Les extrémités translatées doivent rester dans le viewport avant conversion en octets ; les valeurs négatives boucleraient. Préserve la couleur précédente et choisit le chemin selon le mode actif.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Deux arêtes horizontales rouges, un carré bleu, un cadre vert découpé, un repère vert de six pixels et un projectile rouge permettent de comparer les formats de listes.
Commande de compilation
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-disasmImplémentation et source
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
Dessine un modèle 3D à la position et avec la rotation fournies, à l’échelle unitaire.
Syntaxe
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);Paramètres
modelModèle contenant les tableaux de sommets, d’arêtes et de faces, ainsi que leurs nombres ; ses tables doivent rester lisibles pendant l’appel.
xComposante X du point ou de l’origine de l’objet en coordonnées du monde.
yComposante Y du point ou de l’origine de l’objet en coordonnées du monde.
zComposante Z du point ou de l’origine de l’objet en coordonnées du monde.
rxRotation autour de X ; seize pas font un tour complet.
ryRotation autour de Y ; seize pas font un tour complet.
rzRotation autour de Z ; seize pas font un tour complet.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Dessine un modèle à l’échelle Q8 unitaire (256), selon le contrat de DrawModelScaled.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Compare les modèles à l’échelle unitaire et redimensionnés en rouge, bleu et vert, ainsi que des lignes 3D qui se croisent. Les valeurs en RAM vérifient aussi la projection de caméra et sa variante sans rotation.
Commande de compilation
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-disasmImplémentation et source
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
Dessine un modèle à l’échelle unitaire dans une couleur temporaire.
Syntaxe
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);Paramètres
modelModèle contenant les tableaux de sommets, d’arêtes et de faces, ainsi que leurs nombres ; ses tables doivent rester lisibles pendant l’appel.
xComposante X du point ou de l’origine de l’objet en coordonnées du monde.
yComposante Y du point ou de l’origine de l’objet en coordonnées du monde.
zComposante Z du point ou de l’origine de l’objet en coordonnées du monde.
rxRotation autour de X ; seize pas font un tour complet.
ryRotation autour de Y ; seize pas font un tour complet.
rzRotation autour de Z ; seize pas font un tour complet.
colorIndice de couleur de dessin ; les palettes d’exemple utilisent 1=rouge, 2=bleu et 3=vert.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Dessine un modèle à l’échelle Q8 unitaire avec une couleur temporaire, puis rétablit la couleur d’entrée.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Compare les modèles à l’échelle unitaire et redimensionnés en rouge, bleu et vert, ainsi que des lignes 3D qui se croisent. Les valeurs en RAM vérifient aussi la projection de caméra et sa variante sans rotation.
Commande de compilation
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-disasmImplémentation et source
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
Redimensionne, tourne et projette un modèle, puis trace les arêtes sélectionnées dans la couleur courante.
Syntaxe
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);Paramètres
modelModèle contenant les tableaux de sommets, d’arêtes et de faces, ainsi que leurs nombres ; ses tables doivent rester lisibles pendant l’appel.
xComposante X du point ou de l’origine de l’objet en coordonnées du monde.
yComposante Y du point ou de l’origine de l’objet en coordonnées du monde.
zComposante Z du point ou de l’origine de l’objet en coordonnées du monde.
rxRotation autour de X ; seize pas font un tour complet.
ryRotation autour de Y ; seize pas font un tour complet.
rzRotation autour de Z ; seize pas font un tour complet.
scale_q8Échelle dont l’unité vaut 256 ; les valeurs nulles ou négatives signifient aussi l’unité.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Projette au plus 24 sommets avec une échelle Q8 positive ; une échelle nulle ou négative vaut l’unité. Évite la multiplication à l’unité et les rotations d’angle nul. Les intermédiaires doivent tenir dans s16. Si le filtrage par adjacence est disponible, construit jusqu’à 16 indicateurs de face avant, puis trace les arêtes dont la profondeur et les indices de sommets sont valides. Le nombre d’arêtes n’est pas plafonné à 64. Aucun découpage au plan proche n’est effectué. Remplace le cache de projection partagé et combine par OR les couleurs de ligne dans la zone normale de 128×96. Ce chemin ne marque pas les limites partielles ; prévoyez un transfert complet ou invalidez explicitement l’historique avant un transfert partiel.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Compare les modèles à l’échelle unitaire et redimensionnés en rouge, bleu et vert, ainsi que des lignes 3D qui se croisent. Les valeurs en RAM vérifient aussi la projection de caméra et sa variante sans rotation.
Commande de compilation
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-disasmImplémentation et source
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
Dessine un modèle avec l’échelle choisie et une couleur de ligne temporaire.
Syntaxe
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);Paramètres
modelModèle contenant les tableaux de sommets, d’arêtes et de faces, ainsi que leurs nombres ; ses tables doivent rester lisibles pendant l’appel.
xComposante X du point ou de l’origine de l’objet en coordonnées du monde.
yComposante Y du point ou de l’origine de l’objet en coordonnées du monde.
zComposante Z du point ou de l’origine de l’objet en coordonnées du monde.
rxRotation autour de X ; seize pas font un tour complet.
ryRotation autour de Y ; seize pas font un tour complet.
rzRotation autour de Z ; seize pas font un tour complet.
scale_q8Échelle dont l’unité vaut 256 ; les valeurs nulles ou négatives signifient aussi l’unité.
colorIndice de couleur de dessin ; les palettes d’exemple utilisent 1=rouge, 2=bleu et 3=vert.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Sélectionne color & 3 pour l’appel à DrawModelScaled, puis rétablit la couleur d’entrée.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Compare les modèles à l’échelle unitaire et redimensionnés en rouge, bleu et vert, ainsi que des lignes 3D qui se croisent. Les valeurs en RAM vérifient aussi la projection de caméra et sa variante sans rotation.
Commande de compilation
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-disasmImplémentation et source
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
Écrit un pixel dans la couleur courante.
Syntaxe
void Wire3DCGB_DrawPoint2D(w3dcgb_u8 x, w3dcgb_u8 y);Paramètres
xCoordonnée X du centre en pixels du viewport.
yCoordonnée Y du centre en pixels du viewport.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
En mode normal, rejette les coordonnées hors de 128×96, marque les limites partielles et remplace le pixel préparé par la couleur courante, zéro compris. En plein écran, trace à la place une ligne rapide aux extrémités confondues : zéro signifie alors couleur 3 et les coordonnées invalides activent l’indicateur de débordement de l’image. Le transfert vers l’écran a lieu plus tard.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre les lignes, les points, l’effacement et la projection de base dans une seule image. Un cadre rouge contient une diagonale bleue, avec un point et une ligne horizontale verts, un L bleu et un zéro vert en haut à droite.
Commande de compilation
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-disasmImplémentation et source
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
Dessine au plus huit objets du plus proche au plus lointain, les faces précédentes masquant les lignes suivantes.
Syntaxe
void Wire3DCGB_DrawScene(Wire3DCGB_Object* objects, w3dcgb_u8 count);Paramètres
objectsTableau d’objets contenant positions, rotations, échelles et indicateurs de visibilité.
countNombre d’entrées fournies ; consultez la limite de traitement propre à l’opération.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Trie au plus huit objets du plus proche au plus lointain selon la profondeur de leur origine dans l’espace caméra, sans modifier le tableau de l’appelant. Efface le masque, dessine les modèles visibles en tenant compte des zones déjà couvertes, puis ajoute leurs faces comme occultants. Les tableaux des modèles et les indices de faces doivent être valides. La couleur zéro hérite de la couleur courante, éventuellement celle de l’objet précédent. Restaure la couleur d’entrée et désactive l’occlusion à la fin. Ce chemin vise la zone normale de 128×96.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Un carré rouge proche, de (46,30) à (82,66), masque le milieu d’une ligne horizontale bleue plus lointaine ; seuls ses segments gauche et droit restent visibles.
Commande de compilation
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-disasmImplémentation et source
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
Dessine un repère de six pixels dont l’avant et l’arrière indiquent la direction.
Syntaxe
void Wire3DCGB_DrawTinyModel2D(w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_u8 turn, w3dcgb_u8 color);Paramètres
xCoordonnée X du centre en pixels du viewport.
yCoordonnée Y du centre en pixels du viewport.
turnValeur dont les cinq bits faibles choisissent la direction du petit repère.
colorIndice de couleur de dessin ; les palettes d’exemple utilisent 1=rouge, 2=bleu et 3=vert.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Dessine un repère de six pixels via le traceur de points de 128×96, en préservant la couleur de ligne. Ignore les centres hors de X=3..124 ou Y=3..92. Les cinq bits faibles de turn choisissent les décalages avant et arrière pour gauche/tout droit/droite. Ce n’est pas une transformation 3D générale et cela n’utilise pas le moteur plein écran.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Deux arêtes horizontales rouges, un carré bleu, un cadre vert découpé, un repère vert de six pixels et un projectile rouge permettent de comparer les formats de listes.
Commande de compilation
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-disasmImplémentation et source
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
Trace un bord d’un pixel d’indice de couleur 2 autour de la zone de préparation de 128×96.
Syntaxe
void Wire3DCGB_DrawWhiteBorderFast();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Trace un bord d’un pixel en couleur 2 autour de la zone de préparation normale, en préservant les pixels intérieurs et la sélection de banque WRAM. La couleur visible dépend de la palette. Aucune plage modifiée n’est marquée ; les appels à transfert partiel doivent prévoir son transfert.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Les 24 colonnes de gauche sont effacées, une bande rouge subsiste et le bord extérieur d’indice de couleur 2 est bleu.
Commande de compilation
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-disasmImplémentation et source
kitaqgb/lib/wire3d_cgb.h:147
kitaqgb/lib/wire3d_cgb.c:9369
void Wire3DCGB_DrawWhiteBorderFast()
{
w3dcgb_draw_white_border_asm();
}Wire3DCGB_EnableAtomicMaps
Configure la présentation en 128×96 pour alterner entre deux cartes du fond.
Syntaxe
void Wire3DCGB_EnableAtomicMaps();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Au démarrage seulement : réserve les deux cartes BG et réplique les tuiles HUD mises en file. Active une seule fois l’alternance des cartes pendant le démarrage en 128×96 ; ignore le plein écran ou un réglage déjà actif. Si le LCD est allumé, attend le VBlank, l’éteint, copie les deux banques de 9800 vers 9C00 et affecte aux attributs des viewports les banques de tuiles 0/1 respectivement. Restaure LCDC avec la carte 9C00 sélectionnée et VBK à zéro. Les deux cartes BG sont réservées ; les numéros de tuiles HUD en file sont répliqués.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Les cadres rouge et bleu dessinés précédemment disparaissent ; seul reste le cadre vert final de (80,8) à (112,32), ce qui illustre le transfert partiel et la gestion de l’historique.
Commande de compilation
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-disasmImplémentation et source
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
Passe le processeur CGB en double vitesse.
Syntaxe
void Wire3DCGB_EnableDoubleSpeed();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Sur CGB, retourne immédiatement si KEY1 indique déjà la double vitesse ; sinon, demande le changement de vitesse et appelle l’auxiliaire STOP. Cette API suppose un matériel CGB et ne propose aucun repli pour les modèles monochromes.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre les lignes, les points, l’effacement et la projection de base dans une seule image. Un cadre rouge contient une diagonale bleue, avec un point et une ligne horizontale verts, un L bleu et un zéro vert en haut à droite.
Commande de compilation
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-disasmImplémentation et source
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
Transfère et affiche l’image terminée.
Syntaxe
void Wire3DCGB_EndFrame();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
En mode normal, applique les écritures BG en file, transfère toute la zone de préparation et affiche la banque de tuiles terminée. En plein écran, transfère et affiche les tuiles allouées sans vider la file HUD. Nécessite un LCD activé et le respect des contrats de banques et d’interruptions des auxiliaires de transfert ; peut prendre plusieurs images.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Au démarrage sparse CGB, la première utilisation de chaque banque cible (les deux premières images) actualise tout le viewport et efface les tuiles d’initialisation. Cette charge est incluse dans les mesures. DrawLine2D ne déclare pas de zone sparse : utilisez DrawLineClipped2D ou MarkDirtyRect2D explicitement.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre les lignes, les points, l’effacement et la projection de base dans une seule image. Un cadre rouge contient une diagonale bleue, avec un point et une ligne horizontale verts, un L bleu et un zéro vert en haut à droite.
Commande de compilation
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-disasmImplémentation et source
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
Transfère et affiche une image complète sans appliquer les écritures du fond en attente.
Syntaxe
void Wire3DCGB_EndFrameFast();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Transfère et affiche l’image complète du mode choisi sans vider la file BG. Ne consomme pas les écritures HUD en attente. Exige les mêmes conditions LCD, banques et interruptions qu’EndFrame ; runtime complet requis.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Au démarrage sparse CGB, la première utilisation de chaque banque cible (les deux premières images) actualise tout le viewport et efface les tuiles d’initialisation. Cette charge est incluse dans les mesures. DrawLine2D ne déclare pas de zone sparse : utilisez DrawLineClipped2D ou MarkDirtyRect2D explicitement.
Exemple d’utilisation
#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) {}
}Résultat attendu
Les cadres rouge et bleu dessinés précédemment disparaissent ; seul reste le cadre vert final de (80,8) à (112,32), ce qui illustre le transfert partiel et la gestion de l’historique.
Commande de compilation
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-disasmImplémentation et source
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
Attend un nouveau VBlank, puis transfère et affiche les plages partielles nécessaires.
Syntaxe
void Wire3DCGB_EndFrameSparse();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
En mode normal, attend un nouveau VBlank et appelle EndFrameSparseNow. En plein écran, utilise le transfert et la présentation complets de ce mode. Nécessite le runtime complet et un LCD activé ; l’achèvement en une seule image n’est pas garanti.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Au démarrage sparse CGB, la première utilisation de chaque banque cible (les deux premières images) actualise tout le viewport et efface les tuiles d’initialisation. Cette charge est incluse dans les mesures. DrawLine2D ne déclare pas de zone sparse : utilisez DrawLineClipped2D ou MarkDirtyRect2D explicitement.
Exemple d’utilisation
#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) {}
}Résultat attendu
Les cadres rouge et bleu dessinés précédemment disparaissent ; seul reste le cadre vert final de (80,8) à (112,32), ce qui illustre le transfert partiel et la gestion de l’historique.
Commande de compilation
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-disasmImplémentation et source
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
Soumet les écritures du fond et les plages partielles courantes/N−2 sans attendre initialement un nouveau VBlank.
Syntaxe
void Wire3DCGB_EndFrameSparseNow();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Applique les écritures BG en file, transfère la plage partielle de tuiles courante/N−2 dans la banque arrière et l’affiche. Saute l’attente initiale d’un nouveau VBlank, mais le mode de carte normal attend encore lors de la restauration de la tuile HUD vide ; DMA et présentation peuvent aussi attendre. Le mode plein écran du runtime complet utilise son propre chemin. Le LCD doit être activé et SVBK/VBK doivent rester stables pendant le DMA.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Au démarrage sparse CGB, la première utilisation de chaque banque cible (les deux premières images) actualise tout le viewport et efface les tuiles d’initialisation. Cette charge est incluse dans les mesures. DrawLine2D ne déclare pas de zone sparse : utilisez DrawLineClipped2D ou MarkDirtyRect2D explicitement.
Exemple d’utilisation
#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) {}
}Résultat attendu
Les cadres rouge et bleu dessinés précédemment disparaissent ; seul reste le cadre vert final de (80,8) à (112,32), ce qui illustre le transfert partiel et la gestion de l’historique.
Commande de compilation
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-disasmImplémentation et source
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
Efface les 24 colonnes les plus à gauche de la zone de préparation normale.
Syntaxe
void Wire3DCGB_EraseLeftGuard24Fast();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Efface les 24 colonnes les plus à gauche de la zone de préparation par ASM, en préservant la sélection de banque. Aucune plage modifiée n’est marquée ; les appels à transfert partiel doivent inclure les tuiles effacées.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Les 24 colonnes de gauche sont effacées, une bande rouge subsiste et le bord extérieur d’indice de couleur 2 est bleu.
Commande de compilation
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-disasmImplémentation et source
kitaqgb/lib/wire3d_cgb.h:146
kitaqgb/lib/wire3d_cgb.c:9200
void Wire3DCGB_EraseLeftGuard24Fast()
{
w3dcgb_erase_left_guard24_asm();
}Wire3DCGB_EraseModelFaces
Efface les pixels préparés à l’intérieur des faces avant projetées du modèle.
Syntaxe
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);Paramètres
modelModèle contenant les tableaux de sommets, d’arêtes et de faces, ainsi que leurs nombres ; ses tables doivent rester lisibles pendant l’appel.
xComposante X du point ou de l’origine de l’objet en coordonnées du monde.
yComposante Y du point ou de l’origine de l’objet en coordonnées du monde.
zComposante Z du point ou de l’origine de l’objet en coordonnées du monde.
rxRotation autour de X ; seize pas font un tour complet.
ryRotation autour de Y ; seize pas font un tour complet.
rzRotation autour de Z ; seize pas font un tour complet.
scale_q8Échelle dont l’unité vaut 256 ; les valeurs nulles ou négatives signifient aussi l’unité.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Pour un modèle à lignes cachées contenant sommets et faces, transforme au plus 24 sommets et efface les triangles orientés vers l’avant parmi au plus 16 faces. Une échelle non positive vaut l’unité ; ce chemin multiplie encore à l’unité et exécute les trois auxiliaires de rotation même pour des angles nuls. Rejette les faces invalides ou échouant au test de profondeur. Remplace le cache de projection partagé et utilise l’effacement normal en C de la zone de préparation : l’appelant ou l’allocation doit assurer le bon mappage WRAM.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Les faces projetées effacent une région remplie, rendant visibles les zones conservées et effacées.
Commande de compilation
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-disasmImplémentation et source
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
Efface une silhouette compactée dans les deux plans de couleur de la zone de préparation normale.
Syntaxe
void Wire3DCGB_ErasePackedSilhouette2D(const w3dcgb_u8* profile, w3dcgb_u8 count, w3dcgb_i8 y0, w3dcgb_u8 x, w3dcgb_u8 y);Paramètres
profileTableau de silhouette à un octet par ligne ; 0xFF saute une ligne.
countNombre d’entrées fournies ; consultez la limite de traitement propre à l’opération.
y0Décalage signé du centre Y vers la première ligne de silhouette.
xCoordonnée X du centre en pixels du viewport.
yCoordonnée Y du centre en pixels du viewport.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Efface au plus 29 lignes de silhouette compactée dans les deux plans de bits préparés. Format, placement, marge de deux pixels et découpage sont ceux de MarkPackedSilhouette2D ; null est ignoré. L’écriture ASM des segments sélectionne la banque WRAM 2 puis restaure la sélection précédente, mais ne marque pas les tuiles modifiées. En mode partiel, l’appelant doit inclure les tuiles effacées dans la plage à transférer. Cette API vise la zone de préparation de 128×96.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Triangles, segments horizontaux, rectangles et silhouettes compactées creusent des trous noirs dans des panneaux remplis en rouge, bleu et vert.
Commande de compilation
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-disasmImplémentation et source
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
Efface un rectangle dans la zone de préparation normale.
Syntaxe
void Wire3DCGB_EraseRect2D(w3dcgb_u8 x0, w3dcgb_u8 y0, w3dcgb_u8 x1, w3dcgb_u8 y1);Paramètres
x0Borne X inférieure, en pixels du viewport ; l’ordre et le découpage suivent les notes de cette opération.
y0Borne Y inférieure, en pixels du viewport ; l’ordre et le découpage suivent les notes de cette opération.
x1Borne X supérieure, en pixels du viewport ; l’ordre et le découpage suivent les notes de cette opération.
y1Borne Y supérieure, en pixels du viewport ; l’ordre et le découpage suivent les notes de cette opération.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Ordonne les bornes du rectangle et le découpe à 128×96. Les bandes gauches de pleine hauteur et de 16 ou 24 pixels de large utilisent l’effacement ASM avec préservation de banque et marquage des modifications. Les autres rectangles utilisent l’effacement ligne par ligne en C et nécessitent que l’appelant assure le bon mappage WRAM de la zone de préparation.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Triangles, segments horizontaux, rectangles et silhouettes compactées creusent des trous noirs dans des panneaux remplis en rouge, bleu et vert.
Commande de compilation
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-disasmImplémentation et source
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
Efface un segment horizontal en sauvegardant puis restaurant la sélection de banque WRAM.
Syntaxe
void Wire3DCGB_EraseSpan2D(w3dcgb_u8 y, w3dcgb_u8 x0, w3dcgb_u8 x1);Paramètres
yCoordonnée Y en pixels de la ligne à effacer.
x0Borne X inférieure, en pixels du viewport ; l’ordre et le découpage suivent les notes de cette opération.
x1Borne X supérieure, en pixels du viewport ; l’ordre et le découpage suivent les notes de cette opération.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Ordonne les bornes X, rejette une ligne ou une borne gauche hors écran, puis limite la borne droite à 127. Marque la plage comme modifiée et utilise l’effacement ASM de segments, qui sélectionne la banque WRAM 2 puis restaure la sélection précédente.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Triangles, segments horizontaux, rectangles et silhouettes compactées creusent des trous noirs dans des panneaux remplis en rouge, bleu et vert.
Commande de compilation
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-disasmImplémentation et source
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
Efface un triangle dans les deux plans de couleur de la zone de préparation normale.
Syntaxe
void Wire3DCGB_EraseTriangle2D(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by, w3dcgb_u8 cx, w3dcgb_u8 cy);Paramètres
axCoordonnée X du sommet A en pixels du viewport.
ayCoordonnée Y du sommet A en pixels du viewport.
bxCoordonnée X du sommet B en pixels du viewport.
byCoordonnée Y du sommet B en pixels du viewport.
cxCoordonnée X du sommet C en pixels du viewport.
cyCoordonnée Y du sommet C en pixels du viewport.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Efface un triangle avec l’effacement normal en C de la zone de préparation. Ses segments découpés marquent les tuiles touchées comme modifiées ; l’appelant ou l’allocation doit assurer le mappage WRAM de cette zone.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Triangles, segments horizontaux, rectangles et silhouettes compactées creusent des trous noirs dans des panneaux remplis en rouge, bleu et vert.
Commande de compilation
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-disasmImplémentation et source
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
Efface les numéros de tuiles et attributs du viewport FastMap de 16×12.
Syntaxe
void Wire3DCGB_FastMapBegin();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Marque FastMap comme préparé et efface les numéros de tuiles et attributs de son viewport de 16×12. Les colonnes 16..31 de la copie de travail sont conservées, même si le transfert copie 32 colonnes par ligne. Nécessite le runtime complet et un mappage WRAM FastMap stable ; n’initialise pas le matériel et ne transfère pas la carte.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Un coin rouge, un grand rectangle bleu et un cadre vert d’une tuile illustrent les cases de contour. La case rouge initiale en haut à gauche disparaît, tandis que la mise à jour des seules tuiles conserve les attributs.
Commande de compilation
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-disasmImplémentation et source
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
Efface uniquement les numéros de tuiles du viewport FastMap de 16×12.
Syntaxe
void Wire3DCGB_FastMapBeginTilesOnly();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Marque FastMap comme préparé et efface seulement les numéros de tuiles de son viewport de 16×12. Conserve les attributs et les colonnes 16..31. Nécessite le runtime complet et le mappage WRAM prévu ; initialisation matérielle et transfert sont séparés.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Un coin rouge, un grand rectangle bleu et un cadre vert d’une tuile illustrent les cases de contour. La case rouge initiale en haut à gauche disparaît, tandis que la mise à jour des seules tuiles conserve les attributs.
Commande de compilation
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-disasmImplémentation et source
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
Ajoute à une case de carte les côtés de contour choisis parmi haut, bas, gauche et droite.
Syntaxe
void Wire3DCGB_FastMapCell(w3dcgb_u8 tx, w3dcgb_u8 ty, w3dcgb_u8 color, w3dcgb_u8 mask);Paramètres
txPosition X en coordonnées de tuiles.
tyPosition Y en coordonnées de tuiles.
colorIndice de couleur de dessin ; les palettes d’exemple utilisent 1=rouge, 2=bleu et 3=vert.
maskMasque des côtés de case : 1=haut, 2=bas, 4=gauche, 8=droite.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Ajoute des côtés de contour à une case : les bits 1/2/4/8 désignent haut/bas/gauche/droite. Les masques de même couleur se combinent ; une autre couleur remplace l’ancien masque. Un masque nul est ignoré, la couleur zéro signifie MAIN et les valeurs au-delà de 3 sont ramenées à 3. Vise la copie de travail de 16×12 avec un mappage WRAM stable ; runtime complet requis.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Un coin rouge, un grand rectangle bleu et un cadre vert d’une tuile illustrent les cases de contour. La case rouge initiale en haut à gauche disparaît, tandis que la mise à jour des seules tuiles conserve les attributs.
Commande de compilation
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-disasmImplémentation et source
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
Transfère en VRAM les douze premières lignes complètes de numéros de tuiles et d’attributs de la copie de travail.
Syntaxe
void Wire3DCGB_FastMapFlush();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Si le LCD est allumé, attend un nouveau VBlank, puis transfère les douze premières lignes complètes de numéros de tuiles et d’attributs vers la carte 9800. LCD éteint, procède immédiatement. Nécessite le runtime complet, un mappage WRAM stable et une période sûre assez longue pour les deux transferts GDMA immédiats.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Un coin rouge, un grand rectangle bleu et un cadre vert d’une tuile illustrent les cases de contour. La case rouge initiale en haut à gauche disparaît, tandis que la mise à jour des seules tuiles conserve les attributs.
Commande de compilation
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-disasmImplémentation et source
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
Transfère uniquement les numéros de tuiles des douze premières lignes complètes de la carte de travail.
Syntaxe
void Wire3DCGB_FastMapFlushTilesOnly();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Si le LCD est allumé, attend un nouveau VBlank et transfère uniquement les numéros de tuiles des douze premières lignes complètes vers la carte 9800. Les attributs restent intacts. Nécessite le runtime complet, un mappage WRAM stable et un intervalle sûr pour le GDMA.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Un coin rouge, un grand rectangle bleu et un cadre vert d’une tuile illustrent les cases de contour. La case rouge initiale en haut à gauche disparaît, tandis que la mise à jour des seules tuiles conserve les attributs.
Commande de compilation
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-disasmImplémentation et source
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
Place les côtés de contour choisis autour d’un rectangle en coordonnées de tuiles.
Syntaxe
void Wire3DCGB_FastMapRect(w3dcgb_u8 tx0, w3dcgb_u8 ty0, w3dcgb_u8 tx1, w3dcgb_u8 ty1, w3dcgb_u8 color, w3dcgb_u8 sides);Paramètres
tx0Position X en coordonnées de tuiles.
ty0Position Y en coordonnées de tuiles.
tx1Position X en coordonnées de tuiles.
ty1Position Y en coordonnées de tuiles.
colorIndice de couleur de dessin ; les palettes d’exemple utilisent 1=rouge, 2=bleu et 3=vert.
sidesMasque des côtés du rectangle : 1=haut, 2=bas, 4=gauche, 8=droite.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Ordonne les coordonnées de tuiles sur octets et les découpe à 16×12, puis remplace les cases de bord choisies. Les bits 1/2/4/8 désignent haut/bas/gauche/droite. La couleur zéro signifie MAIN ; les valeurs au-delà de 3 sont ramenées à 3. Attributs et cases intérieures restent intacts. Utilisez au moins deux lignes et deux colonnes pour des coins distincts ; les coins confondus sont écrasés successivement. Nécessite le runtime complet et un mappage WRAM stable.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Un coin rouge, un grand rectangle bleu et un cadre vert d’une tuile illustrent les cases de contour. La case rouge initiale en haut à gauche disparaît, tandis que la mise à jour des seules tuiles conserve les attributs.
Commande de compilation
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-disasmImplémentation et source
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
Signale une coordonnée invalide ou l’épuisement de l’allocation de tuiles en plein écran.
Syntaxe
w3dcgb_u8 Wire3DCGB_GetFullScreenOverflow();Valeur renvoyée
Zéro sans erreur, un après épuisement de l’allocation ou coordonnée invalide.
Conditions et limites
Renvoie l’indicateur d’erreur de l’image plein écran : le chemin de lignes rapides le définit en cas d’épuisement des tuiles ou de coordonnée invalide. Une fois défini, les tracés de pixels rapides suivants sont supprimés jusqu’à sa réinitialisation par BeginFrame. Ce n’est pas un indicateur général d’état matériel ; la lecture nécessite le runtime complet.
L’allocation plein écran a lieu avant que l’occlusion ou le débordement ne supprime les écritures de pixels. Des tuiles allouées peuvent rester noires, et dessiner après une erreur peut encore augmenter leur nombre.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
127 points rouges occupent des tuiles distinctes. Une tentative de 128e allocation laisse le compteur à 127 et met overflow à un.
Commande de compilation
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-disasmImplémentation et source
kitaqgb/lib/wire3d_cgb.h:194
kitaqgb/lib/wire3d_cgb.c:9965
w3dcgb_u8 Wire3DCGB_GetFullScreenOverflow()
{
return w3dcgb_full_overflow;
}Wire3DCGB_GetFullScreenTileCount
Renvoie le nombre de tuiles plein écran allouées dans l’image courante.
Syntaxe
w3dcgb_u8 Wire3DCGB_GetFullScreenTileCount();Valeur renvoyée
Nombre de tuiles allouées, de 0 à 127.
Conditions et limites
Renvoie le nombre courant d’allocations plein écran, jusqu’à 127. Ce n’est ni un nombre d’octets ni le nombre de pixels visibles ou non nuls. Runtime complet uniquement.
L’allocation plein écran a lieu avant que l’occlusion ou le débordement ne supprime les écritures de pixels. Des tuiles allouées peuvent rester noires, et dessiner après une erreur peut encore augmenter leur nombre.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
127 points rouges occupent des tuiles distinctes. Une tentative de 128e allocation laisse le compteur à 127 et met overflow à un.
Commande de compilation
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-disasmImplémentation et source
kitaqgb/lib/wire3d_cgb.h:193
kitaqgb/lib/wire3d_cgb.c:9956
w3dcgb_u8 Wire3DCGB_GetFullScreenTileCount()
{
return w3dcgb_full_tile_count;
}Wire3DCGB_GetLineColor
Lit l’indice de couleur de ligne actuellement stocké.
Syntaxe
w3dcgb_u8 Wire3DCGB_GetLineColor();Valeur renvoyée
Valeur de couleur de ligne actuellement stockée.
Conditions et limites
Renvoie la couleur de ligne courante sur deux bits sans modifier l’état de dessin.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre les lignes, les points, l’effacement et la projection de base dans une seule image. Un cadre rouge contient une diagonale bleue, avec un point et une ligne horizontale verts, un L bleu et un zéro vert en haut à droite.
Commande de compilation
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-disasmImplémentation et source
kitaqgb/lib/wire3d_cgb.h:120
kitaqgb/lib/wire3d_cgb.c:1147
w3dcgb_u8 Wire3DCGB_GetLineColor()
{
return w3dcgb_line_color;
}Wire3DCGB_Init
Initialise le moteur de rendu par pixels CGB de 128×96.
Syntaxe
void Wire3DCGB_Init();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Initialise le moteur CGB de 128×96 : active la double vitesse, éteint le LCD au VBlank, efface les deux banques de tuiles, charge les tuiles du HUD et les tuiles générées, puis installe une zone de 16×12 en ordre par colonnes. L’état initial utilise la banque de tuiles vide 1, un défilement nul, les palettes BG par défaut, la couleur 2 et une caméra à zéro. Réinitialise les files et efface la zone de préparation de la banque 2. Appelez BeginFrame avant de dessiner pour initialiser l’occlusion. L’initialisation remplace globalement l’état du LCD, des tuiles et de la carte.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Au démarrage sparse CGB, la première utilisation de chaque banque cible (les deux premières images) actualise tout le viewport et efface les tuiles d’initialisation. Cette charge est incluse dans les mesures. DrawLine2D ne déclare pas de zone sparse : utilisez DrawLineClipped2D ou MarkDirtyRect2D explicitement.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre les lignes, les points, l’effacement et la projection de base dans une seule image. Un cadre rouge contient une diagonale bleue, avec un point et une ligne horizontale verts, un L bleu et un zéro vert en haut à droite.
Commande de compilation
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-disasmImplémentation et source
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
Initialise le rendu FastMap avec des tuiles de contour précalculées.
Syntaxe
void Wire3DCGB_InitFastMapLite();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Initialise un moteur de carte de tuiles CGB avec HUD et 48 tuiles de contour précalculées. Efface la VRAM des tuiles et les cartes, réinitialise défilement, palettes et caméra, puis choisit le mode normal. La disposition de carte du viewport par pixels et les motifs de cube générés sont omis ; utilisez les API FastMap dans ce mode. Efface la zone de préparation en banque 2 et marque la préparation de FastMap comme en attente. Une compilation avec le runtime complet est requise.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Un coin rouge, un grand rectangle bleu et un cadre vert d’une tuile illustrent les cases de contour. La case rouge initiale en haut à gauche disparaît, tandis que la mise à jour des seules tuiles conserve les attributs.
Commande de compilation
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-disasmImplémentation et source
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
Initialise un moteur de 160×144 qui alloue les tuiles au fur et à mesure du tracé des pixels.
Syntaxe
void Wire3DCGB_InitFullScreen();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Initialise l’allocateur de tuiles CGB de 160×144. Efface les deux banques et la carte 9800, règle défilement, palettes, couleur et caméra, réinitialise les compteurs de tuiles et l’état des tables et segments, puis active l’adressage BG non signé. Les tuiles du HUD ne sont pas chargées. Réservez ses zones fixes en WRAM pour les tables, les données et les listes d’adresses ; gardez la même banque WRAM mappée pendant tout le rendu plein écran.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Un grand cadre s’étend de (8,8) à (151,135) : haut et gauche rouges, bas bleu, droite verte. Il utilise 64 tuiles, avec overflow à zéro.
Commande de compilation
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-disasmImplémentation et source
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
Étend la plage de transfert courante et les deux précédentes aux 192 tuiles du mode normal.
Syntaxe
void Wire3DCGB_InvalidateFrameHistory();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Étend la plage partielle courante et les deux précédentes aux 192 tuiles du mode normal. Les pixels ne sont pas effacés ; les transferts suivants ne peuvent plus se fier aux anciennes plages.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Au démarrage sparse CGB, la première utilisation de chaque banque cible (les deux premières images) actualise tout le viewport et efface les tuiles d’initialisation. Cette charge est incluse dans les mesures. DrawLine2D ne déclare pas de zone sparse : utilisez DrawLineClipped2D ou MarkDirtyRect2D explicitement.
Exemple d’utilisation
#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) {}
}Résultat attendu
Les cadres rouge et bleu dessinés précédemment disparaissent ; seul reste le cadre vert final de (80,8) à (112,32), ce qui illustre le transfert partiel et la gestion de l’historique.
Commande de compilation
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-disasmImplémentation et source
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
Ajoute un rectangle de pixels à la plage à transférer ultérieurement.
Syntaxe
void Wire3DCGB_MarkDirtyRect2D(w3dcgb_u8 min_x, w3dcgb_u8 min_y, w3dcgb_u8 max_x, w3dcgb_u8 max_y);Paramètres
min_xBorne X inférieure, en pixels du viewport ; l’ordre et le découpage suivent les notes de cette opération.
min_yBorne Y inférieure, en pixels du viewport ; l’ordre et le découpage suivent les notes de cette opération.
max_xBorne X supérieure, en pixels du viewport ; l’ordre et le découpage suivent les notes de cette opération.
max_yBorne X supérieure, en pixels du viewport ; l’ordre et le découpage suivent les notes de cette opération.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Marque un rectangle de pixels, bornes incluses, pour un transfert ultérieur sans le dessiner. Fournissez les bornes dans l’ordre ; les valeurs dépassant 127/95 sont ramenées au bord. Le suivi porte sur les tuiles de 128×96, pas sur l’allocateur plein écran.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Les cadres rouge et bleu dessinés précédemment disparaissent ; seul reste le cadre vert final de (80,8) à (112,32), ce qui illustre le transfert partiel et la gestion de l’historique.
Commande de compilation
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-disasmImplémentation et source
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
Marque une silhouette compactée ligne par ligne dans le bitmap d’occlusion de 128×96.
Syntaxe
void Wire3DCGB_MarkPackedSilhouette2D(const w3dcgb_u8* profile, w3dcgb_u8 count, w3dcgb_i8 y0, w3dcgb_u8 x, w3dcgb_u8 y);Paramètres
profileTableau de silhouette à un octet par ligne ; 0xFF saute une ligne.
countNombre d’entrées fournies ; consultez la limite de traitement propre à l’opération.
y0Décalage signé du centre Y vers la première ligne de silhouette.
xCoordonnée X du centre en pixels du viewport.
yCoordonnée Y du centre en pixels du viewport.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Marque au plus 29 lignes de silhouette dans le masque bitmap de 128×96. Chaque octet compacté utilise son demi-octet haut pour le décalage du centre (nibble−7) et le bas pour la demi-largeur ; 0xFF saute une ligne. Place les lignes à y+y0+i, élargit les segments de deux pixels et les découpe au viewport. profile doit contenir count octets lisibles ; null est ignoré. Ne met pas à jour les segments plein écran et n’active pas l’occlusion.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Un triangle masque le milieu des lignes de balayage rouges ; une silhouette compactée masque les lignes bleues. Les contours verts situent la région occultante.
Commande de compilation
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-disasmImplémentation et source
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
Enregistre un triangle comme zone pouvant masquer les lignes tracées ensuite.
Syntaxe
void Wire3DCGB_MarkTriangle2D(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by, w3dcgb_u8 cx, w3dcgb_u8 cy);Paramètres
axCoordonnée X du sommet A en pixels du viewport.
ayCoordonnée Y du sommet A en pixels du viewport.
bxCoordonnée X du sommet B en pixels du viewport.
byCoordonnée Y du sommet B en pixels du viewport.
cxCoordonnée X du sommet C en pixels du viewport.
cyCoordonnée Y du sommet C en pixels du viewport.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Marque un triangle en coordonnées écran sans dessiner de pixels ni activer l’occlusion. Les sommets doivent se trouver dans le viewport choisi. L’ASM utilisé ajoute une marge d’un pixel en X, limitée à 0..127 en mode 128×96 ou 0..159 en mode 160×144. Cette fonction ne découpe pas des triangles arbitrairement hors limites.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Un triangle masque le milieu des lignes de balayage rouges ; une silhouette compactée masque les lignes bleues. Les contours verts situent la région occultante.
Commande de compilation
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-disasmImplémentation et source
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
Approxime un décalage projeté avec une focale de 48.
Syntaxe
w3dcgb_i16 Wire3DCGB_ProjectAxis48(w3dcgb_i16 value, w3dcgb_i16 z);Paramètres
valueComposante signée sur 16 bits à projeter.
zProfondeur utilisée pour choisir la taille ou calculer la projection.
Valeur renvoyée
Décalage projeté approximatif, signé sur 16 bits.
Conditions et limites
Approxime value*48/z sans caméra ni décalage du centre d’écran. Un Z négatif ou très petit devient 4. Au-delà de 255, décale ensemble profondeur et magnitude vers la droite jusqu’à ce que la profondeur tienne dans un octet, puis plafonne la magnitude à 160. Renvoie un décalage signé ; cet auxiliaire ne rejette pas les profondeurs proches ou lointaines.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Deux arêtes horizontales rouges, un carré bleu, un cadre vert découpé, un repère vert de six pixels et un projectile rouge permettent de comparer les formats de listes.
Commande de compilation
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-disasmImplémentation et source
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
Projette un point du monde par la caméra vers le viewport de 128×96.
Syntaxe
w3dcgb_u8 Wire3DCGB_ProjectPoint(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_u8* sx, w3dcgb_u8* sy);Paramètres
xComposante X du point ou de l’origine de l’objet en coordonnées du monde.
yComposante Y du point ou de l’origine de l’objet en coordonnées du monde.
zComposante Z du point ou de l’origine de l’objet en coordonnées du monde.
sxPointeur u8 valide et accessible en écriture recevant la coordonnée X projetée.
syPointeur u8 valide et accessible en écriture recevant la coordonnée Y projetée.
Valeur renvoyée
Renvoie 1 si la projection réussit, 0 si la profondeur est rejetée.
Conditions et limites
Projette un point du monde par la caméra courante vers le viewport de 128×96. Renvoie zéro en cas de rejet de profondeur sans modifier les sorties ; sinon, écrit des coordonnées sur octets bornées au viewport. Des pointeurs valides et accessibles en écriture sont requis. Ce n’est pas le projecteur plein écran de 160×144. Absent des builds MINIMAL_RUNTIME.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Compare les modèles à l’échelle unitaire et redimensionnés en rouge, bleu et vert, ainsi que des lignes 3D qui se croisent. Les valeurs en RAM vérifient aussi la projection de caméra et sa variante sans rotation.
Commande de compilation
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-disasmImplémentation et source
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
Projette un point après soustraction de la position de caméra, sans rotation de caméra.
Syntaxe
w3dcgb_u8 Wire3DCGB_ProjectPointNoRotation(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_u8* sx, w3dcgb_u8* sy);Paramètres
xComposante X du point ou de l’origine de l’objet en coordonnées du monde.
yComposante Y du point ou de l’origine de l’objet en coordonnées du monde.
zComposante Z du point ou de l’origine de l’objet en coordonnées du monde.
sxPointeur u8 valide et accessible en écriture recevant la coordonnée X projetée.
syPointeur u8 valide et accessible en écriture recevant la coordonnée Y projetée.
Valeur renvoyée
Renvoie 1 si la projection réussit, 0 si la profondeur est rejetée.
Conditions et limites
Chemin rapide pour les jeux dont le tangage, le lacet et le roulis de caméra restent nuls. Soustrait la position de caméra et projette vers 128×96 en ignorant tous ses angles. À utiliser lorsque les trois angles sont nuls. Rejette une profondeur invalide sans modifier les valeurs pointées en sortie ; les coordonnées réussies sont bornées au viewport. Absent des builds MINIMAL_RUNTIME.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Compare les modèles à l’échelle unitaire et redimensionnés en rouge, bleu et vert, ainsi que des lignes 3D qui se croisent. Les valeurs en RAM vérifient aussi la projection de caméra et sa variante sans rotation.
Commande de compilation
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-disasmImplémentation et source
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
Met en file un changement de numéro de tuile du fond pour EndFrame.
Syntaxe
void Wire3DCGB_PutBgTile(w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_u8 tile);Paramètres
xCoordonnée X en tuiles dans la carte de fond de 32×32.
yCoordonnée Y en tuiles dans la carte de fond de 32×32.
tileNuméro de tuile sur huit bits pour la case du fond.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Met en file une écriture de numéro de tuile pour une carte BG de 32×32. Ignore les coordonnées invalides et les soumissions au-delà de 48 écritures en attente. EndFrame vide cette file privée ; le mode atomic-map réplique les écritures sur les deux cartes BG. Les attributs ne sont pas mis en file.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre les lignes, les points, l’effacement et la projection de base dans une seule image. Un cadre rouge contient une diagonale bleue, avec un point et une ligne horizontale verts, un L bleu et un zéro vert en haut à droite.
Commande de compilation
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-disasmImplémentation et source
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
Regroupe les canaux rouge, vert et bleu sur cinq bits en une couleur CGB de 15 bits.
Syntaxe
#define WIRE3DCGB_RGB15(r5, g5, b5) ((w3dcgb_u16)((w3dcgb_u16)((r5) & 31) | ((w3dcgb_u16)((g5) & 31) << 5) | ((w3dcgb_u16)((b5) & 31) << 10)))Paramètres
r5Canal rouge, 0..31.
g5Canal vert, 0..31.
b5Canal bleu, 0..31.
Valeur renvoyée
Valeur RGB15 regroupée dans un u16.
Conditions et limites
Regroupe les cinq bits faibles de chaque canal en RGB15 ; chaque argument est évalué une seule fois.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre les lignes, les points, l’effacement et la projection de base dans une seule image. Un cadre rouge contient une diagonale bleue, avec un point et une ligne horizontale verts, un L bleu et un zéro vert en haut à droite.
Commande de compilation
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-disasmImplémentation et source
kitaqgb/lib/wire3d_cgb.h:50
Wire3DCGB_SetCamera
Mémorise la position et l’orientation de la caméra pour la projection, avec 16 pas angulaires par tour.
Syntaxe
void Wire3DCGB_SetCamera(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 pitch, w3dcgb_i8 yaw, w3dcgb_i8 roll);Paramètres
xComposante X de la caméra en coordonnées du monde.
yComposante Y de la caméra en coordonnées du monde.
zComposante Z de la caméra en coordonnées du monde.
pitchRotation autour de X ; seize pas font un tour complet.
yawRotation autour de Y ; seize pas font un tour complet.
rollRotation autour de Z ; seize pas font un tour complet.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Mémorise la position et les angles de la caméra sans changer les pixels existants. Les auxiliaires de rotation utilisent les quatre bits faibles des angles, soit 16 pas par tour. Les décalages d’écran sont des registres LCD distincts, que cet appel ne modifie pas.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Compare les modèles à l’échelle unitaire et redimensionnés en rouge, bleu et vert, ainsi que des lignes 3D qui se croisent. Les valeurs en RAM vérifient aussi la projection de caméra et sa variante sans rotation.
Commande de compilation
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-disasmImplémentation et source
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
Choisit l’indice de couleur pour les lignes suivantes.
Syntaxe
void Wire3DCGB_SetLineColor(w3dcgb_u8 color);Paramètres
colorIndice de couleur de dessin ; les palettes d’exemple utilisent 1=rouge, 2=bleu et 3=vert.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Stocke color & 3. Utilisez les couleurs de ligne nommées 1..3 : les lignes normales combinent leurs plans de bits par OR, donc les couleurs se combinent aux intersections ; les lignes rapides plein écran remplacent la couleur du pixel. La couleur de ligne zéro est traitée comme 3 et n’efface pas. Le tracé de points en mode normal accepte séparément la couleur zéro pour effacer.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre les lignes, les points, l’effacement et la projection de base dans une seule image. Un cadre rouge contient une diagonale bleue, avec un point et une ligne horizontale verts, un L bleu et un zéro vert en haut à droite.
Commande de compilation
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-disasmImplémentation et source
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
Active ou désactive le test d’occlusion pour les lignes suivantes.
Syntaxe
void Wire3DCGB_SetOcclusionActive(w3dcgb_u8 active);Paramètres
activeZéro désactive le test d’occlusion ; toute autre valeur l’active.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Normalise active à zéro ou un et le mémorise comme interrupteur d’occlusion. N’efface aucun masque et ne marque aucune géométrie.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Un triangle masque le milieu des lignes de balayage rouges ; une silhouette compactée masque les lignes bleues. Les contours verts situent la région occultante.
Commande de compilation
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-disasmImplémentation et source
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
Définit les quatre couleurs de dessin et les palettes du fond servant à colorer les motifs.
Syntaxe
void Wire3DCGB_SetPaletteRGB15(w3dcgb_u16 color0, w3dcgb_u16 color1, w3dcgb_u16 color2, w3dcgb_u16 color3);Paramètres
color0Couleur RGB15 de l’entrée 0 de la palette.
color1Couleur RGB15 de l’entrée 1 de la palette.
color2Couleur RGB15 de l’entrée 2 de la palette.
color3Couleur RGB15 de l’entrée 3 de la palette.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Affecte les quatre couleurs RGB15 fournies à la palette BG 0. Les palettes 1..3 partagent color0 et répètent leur couleur non nulle respective dans les entrées 1..3, ce qui permet de recolorer les tuiles de motifs monochromes par leurs attributs. Appelez dans une période autorisant l’accès aux palettes, généralement pendant la configuration LCD éteint ou le VBlank.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre les lignes, les points, l’effacement et la projection de base dans une seule image. Un cadre rouge contient une diagonale bleue, avec un point et une ligne horizontale verts, un L bleu et un zéro vert en haut à droite.
Commande de compilation
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-disasmImplémentation et source
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
Règle directement les registres de défilement LCD SCX et SCY.
Syntaxe
void Wire3DCGB_SetScreenOffset(w3dcgb_u8 scx, w3dcgb_u8 scy);Paramètres
scxDécalage de défilement en pixels écrit dans SCX.
scyDécalage de défilement en pixels écrit dans SCY.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
Écrit immédiatement SCX/SCY, sans attendre le VBlank ni modifier les coordonnées projetées. L’appelant choisit quand un changement visible du défilement est acceptable.
CGB uniquement. La préparation normale réserve D300..DEFF dans la banque WRAM 2. L’état partagé rend ces routines non réentrantes ; ne les rappelez pas récursivement depuis une interruption. Les exemples utilisent une pile fixe et le runtime complet.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre les lignes, les points, l’effacement et la projection de base dans une seule image. Un cadre rouge contient une diagonale bleue, avec un point et une ligne horizontale verts, un L bleu et un zéro vert en haut à droite.
Commande de compilation
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-disasmImplémentation et source
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;
}Mesure Wire3D, profils de 88 lignes et horloges indépendantes
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Un transfert complet de 88 lignes lit 1 408 octets sur DMG et 2 816 sur CGB. La réduction est de 26,67 % face aux 120 lignes DMG et de 8,33 % face à 96 lignes ; elle ne prédit pas le gain de fps. DMG conserve des colonnes espacées de 256 octets ; CGB compacte des colonnes de 11 tuiles. CGB réserve toujours 3 072 octets pour rester compatible avec le plein écran.
ProjectCameraPoint projette des coordonnées caméra sans soustraction ni rotation de caméra. Hors de Z=8..255, il renvoie 0 et conserve les sorties. X/Y sont limités à ±120 ; les produits de la table inverse de profondeur sont divisés par 32 avec arrondi signé vers le bas, puis bornés à l’écran. Ce n’est pas un découpage géométrique des lignes. Le ProjectPoint générique CGB conserve les limites de rotation ±220, même aux angles nuls.
EndFrameNow sur DMG supprime seulement l’attente initiale d’un nouveau VBlank ; il traite la file BG, les modes de transfert et l’historique dirty. EndFrameSparseNow sur CGB reste synchrone. Now attend encore les accès STAT, la fin du DMA et une présentation sûre. Les mises à jour DMG ne sont pas atomiques. L’effacement sparse CGB couvre la zone actuelle et celle présente dans la banque cible deux images auparavant. Les lignes CGB de bas niveau exigent un marquage dirty.
Au démarrage sparse CGB, la première utilisation de chaque banque cible (les deux premières images) actualise tout le viewport et efface les tuiles d’initialisation. Cette charge est incluse dans les mesures. DrawLine2D ne déclare pas de zone sparse : utilisez DrawLineClipped2D ou MarkDirtyRect2D explicitement.
Les exemples emploient une boîte mobile, une jauge et un BGM de quatre notes créés indépendamment. Le mouvement utilise les ticks écoulés d’audio_vblank ; un bref traitement VBlank sûr actualise la jauge. N’appelez jamais le moteur à état partagé depuis une ISR. wire3d_audio_vblank.c place la file de 80 octets en WRAM fixe et les fonctions de contrôle dans la banque ROM 5. Ne compilez pas aussi audio_vblank.c. Les exemples CGB utilisent WIRE3DCGB_STAGE_BANK2_ALLOCATION. Lisez la différence de ticks sur 8 bits avant 255 images.
L’outil compte les marqueurs après transfert et présentation terminés. Il mesure en dots PPU (4 194 304/s ; 70 224/image) l’effacement, la projection, la rastérisation, le transfert avec présentation et les attentes externes. Il donne moyenne, médiane, intervalle maximal et échéances dépassées. Le transfert avec présentation inclut les attentes internes STAT/DMA/VBlank. Ne comparez pas directement les cycles CPU CGB à double vitesse et DMG. Une même moyenne de fps ne prouve pas le respect de chaque échéance. Matériel réel non vérifié.
Sept configurations originales ont effectué 48 transferts chacune : 336 comparaisons stage/VRAM et 84 images vides pour vérifier l’effacement. Cinq profils ont réussi 25 700 cas limites de projection. Cinq builds Rust ont aussi terminé 48 images avec BGM non nul. Certains intervalles dépassent quatre images PPU : la moyenne des fps ne prouve pas l’absence de ralentissement. Vérification par émulateur, sans validation matérielle.
KOKURA a exécuté chaque exemple original DMG/CGB sur 400 images ; analyse SARAKURA et validation stricte réussies. Chacun conserve zéro erreur, un avertissement PC répété dans la boucle d’attente et trois observations, dont le risque de clic DAC/mixeur. Cela ne valide ni la fidélité sonore ni le matériel.
Les exemples, images et preuves publiés utilisent uniquement des formes, jauges et motifs sonores créés indépendamment. Aucun ROM commercial, code extrait, géométrie, écran, musique ou sauvegarde d’état d’un jeu commercial n’est inclus.
Résultats de vérification et exemples · C / BGM / HUD
| Profil | fps | Médiane / maximum (images PPU) | Dépassements / 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 projette des coordonnées caméra sans soustraction ni rotation de caméra. Hors de Z=8..255, il renvoie 0 et conserve les sorties. X/Y sont limités à ±120 ; les produits de la table inverse de profondeur sont divisés par 32 avec arrondi signé vers le bas, puis bornés à l’écran. Ce n’est pas un découpage géométrique des lignes. Le ProjectPoint générique CGB conserve les limites de rotation ±220, même aux angles nuls.
Syntaxe
w3ddmg_u8 Wire3DDMG_ProjectCameraPoint(w3ddmg_i16 x,w3ddmg_i16 y,w3ddmg_i16 z,w3ddmg_u8* sx,w3ddmg_u8* sy);Paramètres
xX/Y/Z caméra signés sur 16 bits. sx et sy doivent être des pointeurs u8 valides et modifiables.
yX/Y/Z caméra signés sur 16 bits. sx et sy doivent être des pointeurs u8 valides et modifiables.
zX/Y/Z caméra signés sur 16 bits. sx et sy doivent être des pointeurs u8 valides et modifiables.
sxX/Y/Z caméra signés sur 16 bits. sx et sy doivent être des pointeurs u8 valides et modifiables.
syX/Y/Z caméra signés sur 16 bits. sx et sy doivent être des pointeurs u8 valides et modifiables.
Valeur renvoyée
Renvoie 1 si la projection réussit, 0 si la profondeur est rejetée. Un rejet conserve sx et sy.
Conditions et limites
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Les exemples emploient une boîte mobile, une jauge et un BGM de quatre notes créés indépendamment. Le mouvement utilise les ticks écoulés d’audio_vblank ; un bref traitement VBlank sûr actualise la jauge. N’appelez jamais le moteur à état partagé depuis une ISR. wire3d_audio_vblank.c place la file de 80 octets en WRAM fixe et les fonctions de contrôle dans la banque ROM 5. Ne compilez pas aussi audio_vblank.c. Les exemples CGB utilisent WIRE3DCGB_STAGE_BANK2_ALLOCATION. Lisez la différence de ticks sur 8 bits avant 255 images.
L’outil compte les marqueurs après transfert et présentation terminés. Il mesure en dots PPU (4 194 304/s ; 70 224/image) l’effacement, la projection, la rastérisation, le transfert avec présentation et les attentes externes. Il donne moyenne, médiane, intervalle maximal et échéances dépassées. Le transfert avec présentation inclut les attentes internes STAT/DMA/VBlank. Ne comparez pas directement les cycles CPU CGB à double vitesse et DMG. Une même moyenne de fps ne prouve pas le respect de chaque échéance. Matériel réel non vérifié.
Exemple d’utilisation
#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.
}
}Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Sept configurations originales ont effectué 48 transferts chacune : 336 comparaisons stage/VRAM et 84 images vides pour vérifier l’effacement. Cinq profils ont réussi 25 700 cas limites de projection. Cinq builds Rust ont aussi terminé 48 images avec BGM non nul. Certains intervalles dépassent quatre images PPU : la moyenne des fps ne prouve pas l’absence de ralentissement. Vérification par émulateur, sans validation matérielle.
Implémentation et source
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 projette des coordonnées caméra sans soustraction ni rotation de caméra. Hors de Z=8..255, il renvoie 0 et conserve les sorties. X/Y sont limités à ±120 ; les produits de la table inverse de profondeur sont divisés par 32 avec arrondi signé vers le bas, puis bornés à l’écran. Ce n’est pas un découpage géométrique des lignes. Le ProjectPoint générique CGB conserve les limites de rotation ±220, même aux angles nuls.
Syntaxe
w3dcgb_u8 Wire3DCGB_ProjectCameraPoint(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_u8* sx, w3dcgb_u8* sy);Paramètres
xX/Y/Z caméra signés sur 16 bits. sx et sy doivent être des pointeurs u8 valides et modifiables.
yX/Y/Z caméra signés sur 16 bits. sx et sy doivent être des pointeurs u8 valides et modifiables.
zX/Y/Z caméra signés sur 16 bits. sx et sy doivent être des pointeurs u8 valides et modifiables.
sxX/Y/Z caméra signés sur 16 bits. sx et sy doivent être des pointeurs u8 valides et modifiables.
syX/Y/Z caméra signés sur 16 bits. sx et sy doivent être des pointeurs u8 valides et modifiables.
Valeur renvoyée
Renvoie 1 si la projection réussit, 0 si la profondeur est rejetée. Un rejet conserve sx et sy.
Conditions et limites
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Les exemples emploient une boîte mobile, une jauge et un BGM de quatre notes créés indépendamment. Le mouvement utilise les ticks écoulés d’audio_vblank ; un bref traitement VBlank sûr actualise la jauge. N’appelez jamais le moteur à état partagé depuis une ISR. wire3d_audio_vblank.c place la file de 80 octets en WRAM fixe et les fonctions de contrôle dans la banque ROM 5. Ne compilez pas aussi audio_vblank.c. Les exemples CGB utilisent WIRE3DCGB_STAGE_BANK2_ALLOCATION. Lisez la différence de ticks sur 8 bits avant 255 images.
L’outil compte les marqueurs après transfert et présentation terminés. Il mesure en dots PPU (4 194 304/s ; 70 224/image) l’effacement, la projection, la rastérisation, le transfert avec présentation et les attentes externes. Il donne moyenne, médiane, intervalle maximal et échéances dépassées. Le transfert avec présentation inclut les attentes internes STAT/DMA/VBlank. Ne comparez pas directement les cycles CPU CGB à double vitesse et DMG. Une même moyenne de fps ne prouve pas le respect de chaque échéance. Matériel réel non vérifié.
Exemple d’utilisation
#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.
}
}Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Sept configurations originales ont effectué 48 transferts chacune : 336 comparaisons stage/VRAM et 84 images vides pour vérifier l’effacement. Cinq profils ont réussi 25 700 cas limites de projection. Cinq builds Rust ont aussi terminé 48 images avec BGM non nul. Certains intervalles dépassent quatre images PPU : la moyenne des fps ne prouve pas l’absence de ralentissement. Vérification par émulateur, sans validation matérielle.
Implémentation et source
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
EndFrameNow sur DMG supprime seulement l’attente initiale d’un nouveau VBlank ; il traite la file BG, les modes de transfert et l’historique dirty. EndFrameSparseNow sur CGB reste synchrone. Now attend encore les accès STAT, la fin du DMA et une présentation sûre. Les mises à jour DMG ne sont pas atomiques. L’effacement sparse CGB couvre la zone actuelle et celle présente dans la banque cible deux images auparavant. Les lignes CGB de bas niveau exigent un marquage dirty.
Syntaxe
void Wire3DDMG_EndFrameNow();Valeur renvoyée
Aucune valeur de retour ; revient après transfert et synchronisation nécessaires.
Conditions et limites
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Les exemples emploient une boîte mobile, une jauge et un BGM de quatre notes créés indépendamment. Le mouvement utilise les ticks écoulés d’audio_vblank ; un bref traitement VBlank sûr actualise la jauge. N’appelez jamais le moteur à état partagé depuis une ISR. wire3d_audio_vblank.c place la file de 80 octets en WRAM fixe et les fonctions de contrôle dans la banque ROM 5. Ne compilez pas aussi audio_vblank.c. Les exemples CGB utilisent WIRE3DCGB_STAGE_BANK2_ALLOCATION. Lisez la différence de ticks sur 8 bits avant 255 images.
L’outil compte les marqueurs après transfert et présentation terminés. Il mesure en dots PPU (4 194 304/s ; 70 224/image) l’effacement, la projection, la rastérisation, le transfert avec présentation et les attentes externes. Il donne moyenne, médiane, intervalle maximal et échéances dépassées. Le transfert avec présentation inclut les attentes internes STAT/DMA/VBlank. Ne comparez pas directement les cycles CPU CGB à double vitesse et DMG. Une même moyenne de fps ne prouve pas le respect de chaque échéance. Matériel réel non vérifié.
Exemple d’utilisation
#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();
}Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Sept configurations originales ont effectué 48 transferts chacune : 336 comparaisons stage/VRAM et 84 images vides pour vérifier l’effacement. Cinq profils ont réussi 25 700 cas limites de projection. Cinq builds Rust ont aussi terminé 48 images avec BGM non nul. Certains intervalles dépassent quatre images PPU : la moyenne des fps ne prouve pas l’absence de ralentissement. Vérification par émulateur, sans validation matérielle.
Implémentation et source
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 — Rendu filaire pour DMG
Utilisation des chemins de rendu rapide
Pour les lignes dans la zone de rendu, l’adresse de dessin et le bit du pixel avancent progressivement ; le nombre de pixels restant et l’erreur restent dans les registres CPU. Cela évite de recalculer les coordonnées de tuile pour chaque pixel et ajoute des pixels de liaison pour raccorder les diagonales. Avec l’occlusion, cinq points de la ligne déterminent si elle doit être dessinée ; les lignes retenues empruntent le même chemin rapide. Les lignes du masque sont remplies octet par octet en préservant les bits partiels aux bords. Les rectangles englobant les faces et le rejet sur cinq points sont des approximations, pas une occlusion exacte des triangles ou lignes pixel par pixel. Les rotations de 0, 90, 180 et 270 degrés bornent les entrées, puis échangent les coordonnées et changent les signes. Les performances du jeu dépendent aussi du nombre de sommets, de la longueur des arêtes, de l’occlusion et des transferts VRAM. Mesurez séparément chaque opération et le temps nécessaire pour achever une image affichée.
Dessin de lignes 3D monochromes. Fournissez sommets, arêtes et faces du modèle, ainsi que position, rotation et échelle de l’objet. Suivez l’ordre initialisation, début d’image, dessin, transfert. La physique est séparée. Les angles ont seize pas par tour ; l’échelle de modèle 256 vaut l’unité.
Vec3 contient x/y/z, Edge les indices de sommets a/b, et Face les indices de triangle a/b/c. Les champs vertices, edges et faces de Model pointent vers ces tableaux ; chaque compteur en donne la longueur. edge_faces contient les indices des faces adjacentes f0/f1, avec FACE_NONE pour une face absente. MODEL_HIDDEN_LINES dans flags demande une sélection d’arêtes fondée sur les faces. L’aire projetée signée détermine l’orientation d’une face : l’ordre des sommets compte.
Object mémorise une référence au modèle, la position x/y/z, les angles rx/ry/rz, scale_q8 et visible. Les objets peuvent partager un modèle, mais le dessin ne copie pas les tables et ne change pas automatiquement leurs banques ROM. Gardez les données référencées lisibles pendant tout le dessin. L’Object CGB possède aussi un indice de couleur.
Le Model de hauteur 96 contient aussi edge_masks et edge_mask_count. Fournissez une table RAM de masques d’arêtes sur 16 bits sélectionnés selon le lacet de l’objet, ou mettez les deux champs à zéro si inutilisés.
Wire3DDMG_BeginFrame
Commence le dessin d’une image et désactive le test d’occlusion.
Syntaxe
void Wire3DDMG_BeginFrame();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_BeginFrame(); Efface les pixels préparés et le masque d’occlusion, puis désactive le filtrage d’occlusion. L’image VRAM affichée et la file de tuiles BG en attente restent inchangées. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_BeginFrame(); Désactive uniquement le filtrage d’occlusion. La zone de préparation est normalement effacée pendant le transfert ; Init fournit la première zone vierge. Ne supprime pas une image non soumise, n’efface pas le masque et ne réinitialise ni écritures BG en attente ni indicateurs de modification.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
WIRE3D_DMG_HEIGHT vaut 120 par défaut. Utilisez wire3d_dmg_96.c pour la hauteur 96. SelectEdgeMask est disponible à la hauteur 96 ; RotatePoint, DrawIndexedEdges, les contrôles d’autorisation de transfert et les transferts directs exigent la hauteur 120.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.
Commande de compilation
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-disasmImplémentation et source
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
Dessine un modèle de lignes à échelle entière à partir de sommets et de paires d’indices d’arêtes sur deux octets.
Syntaxe
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);Paramètres
verticesTableau de sommets 3D.
vertex_countNombre d’entrées du tableau de sommets.
edgesIndices des sommets de chaque arête, dans le format déclaré de structure ou de paire d’octets.
edge_countNombre d’arêtes.
xComposante X du point ou de l’origine de l’objet en coordonnées du monde.
yComposante Y du point ou de l’origine de l’objet en coordonnées du monde.
zComposante Z du point ou de l’origine de l’objet en coordonnées du monde.
scaleÉchelle entière ; zéro est traité comme un.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
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); Trace les arêtes indexées par paires d’octets après mise à l’échelle entière et translation ; l’échelle zéro signifie un, sans rotation d’objet ni filtrage de faces. Projette au plus 24 sommets. Fournissez au plus 128 paires d’arêtes, car les décalages sur octets bouclent après 255. Ignore les ID de sommets invalides, les extrémités rejetées en profondeur et les tableaux null. Produits et sommes de coordonnées doivent tenir dans s16.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
WIRE3D_DMG_HEIGHT vaut 120 par défaut. Utilisez wire3d_dmg_96.c pour la hauteur 96. SelectEdgeMask est disponible à la hauteur 96 ; RotatePoint, DrawIndexedEdges, les contrôles d’autorisation de transfert et les transferts directs exigent la hauteur 120.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Une ligne horizontale projetée et un bloc auxiliaire de 8×8 illustrent les transferts directs ; un octet source passe de 255 à 0 lorsqu’il est consommé.
Commande de compilation
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-disasmImplémentation et source
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
Trace dans la zone de préparation une ligne en coordonnées écran à connexité 4, extrémités incluses.
Syntaxe
void Wire3DDMG_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by);Paramètres
axCoordonnée X du sommet A en pixels du viewport.
ayCoordonnée Y du sommet A en pixels du viewport.
bxCoordonnée X du sommet B en pixels du viewport.
byCoordonnée Y du sommet B en pixels du viewport.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by); Trace une ligne connexe dans la zone de préparation de 128×96, extrémités incluses. Pendant DrawScene, utilise le rejet d’occlusion grossier à cinq échantillons ; sinon, trace directement. Fournissez des coordonnées du viewport. Seul EndFrame met à jour la VRAM. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by); Si le transfert des zones modifiées est actif, marque le rectangle englobant en tuiles, puis trace une ligne connexe préparée. Le dessin de scène peut la rejeter avec cinq échantillons du masque. Fournissez des extrémités dans le viewport 128×120 ; les contrôles de pixels bas niveau ne découpent pas géométriquement le segment.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
WIRE3D_DMG_HEIGHT vaut 120 par défaut. Utilisez wire3d_dmg_96.c pour la hauteur 96. SelectEdgeMask est disponible à la hauteur 96 ; RotatePoint, DrawIndexedEdges, les contrôles d’autorisation de transfert et les transferts directs exigent la hauteur 120.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.
Commande de compilation
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-disasmImplémentation et source
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
Projette deux extrémités du monde et trace une ligne entre elles.
Syntaxe
void Wire3DDMG_DrawLine3D(w3ddmg_i16 ax, w3ddmg_i16 ay, w3ddmg_i16 az, w3ddmg_i16 bx, w3ddmg_i16 by, w3ddmg_i16 bz);Paramètres
axComposante X du point de départ en coordonnées du monde.
ayComposante Y du point de départ en coordonnées du monde.
azComposante Z du point de départ en coordonnées du monde.
bxComposante X du point d’arrivée en coordonnées du monde.
byComposante Y du point d’arrivée en coordonnées du monde.
bzComposante Z du point d’arrivée en coordonnées du monde.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
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); Projette les deux extrémités du monde et dessine uniquement si les deux passent la plage de profondeur. Ne calcule pas l’intersection d’un segment traversant avec les plans proche ou lointain ; chaque extrémité projetée est bornée indépendamment aux bords de l’écran. 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); Projette les deux extrémités du monde et dessine uniquement si les deux passent la plage de profondeur. Ne calcule pas l’intersection d’un segment traversant avec les plans proche ou lointain ; chaque extrémité projetée est bornée indépendamment aux bords de l’écran.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
WIRE3D_DMG_HEIGHT vaut 120 par défaut. Utilisez wire3d_dmg_96.c pour la hauteur 96. SelectEdgeMask est disponible à la hauteur 96 ; RotatePoint, DrawIndexedEdges, les contrôles d’autorisation de transfert et les transferts directs exigent la hauteur 120.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.
Commande de compilation
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-disasmImplémentation et source
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
Dessine un modèle de sommets et d’arêtes à la position et avec la rotation demandées, à l’échelle unitaire.
Syntaxe
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);Paramètres
modelModèle contenant les tableaux de sommets, d’arêtes et de faces, ainsi que leurs nombres ; ses tables doivent rester lisibles pendant l’appel.
xComposante X du point ou de l’origine de l’objet en coordonnées du monde.
yComposante Y du point ou de l’origine de l’objet en coordonnées du monde.
zComposante Z du point ou de l’origine de l’objet en coordonnées du monde.
rxRotation autour de X ; seize pas font un tour complet.
ryRotation autour de Y ; seize pas font un tour complet.
rzRotation autour de Z ; seize pas font un tour complet.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
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); Dessine un modèle sans redimensionnement en appelant DrawModelScaled avec l’échelle 256. 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); Dessine un modèle sans redimensionnement en appelant DrawModelScaled avec l’échelle 256.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
WIRE3D_DMG_HEIGHT vaut 120 par défaut. Utilisez wire3d_dmg_96.c pour la hauteur 96. SelectEdgeMask est disponible à la hauteur 96 ; RotatePoint, DrawIndexedEdges, les contrôles d’autorisation de transfert et les transferts directs exigent la hauteur 120.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Des modèles à l’échelle unitaire et à demi-échelle apparaissent au-dessus d’une scène issue d’un tableau d’objets aux mêmes échelles, illustrant projection et redimensionnement.
Commande de compilation
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-disasmImplémentation et source
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
Redimensionne un modèle, le tourne dans l’ordre Y/X/Z, translate et projette ses sommets, puis trace ses arêtes.
Syntaxe
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);Paramètres
modelModèle contenant les tableaux de sommets, d’arêtes et de faces, ainsi que leurs nombres ; ses tables doivent rester lisibles pendant l’appel.
xComposante X du point ou de l’origine de l’objet en coordonnées du monde.
yComposante Y du point ou de l’origine de l’objet en coordonnées du monde.
zComposante Z du point ou de l’origine de l’objet en coordonnées du monde.
rxRotation autour de X ; seize pas font un tour complet.
ryRotation autour de Y ; seize pas font un tour complet.
rzRotation autour de Z ; seize pas font un tour complet.
scale_q8Échelle dont l’unité vaut 256 ; les valeurs nulles ou négatives signifient aussi l’unité.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
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); Redimensionne au plus 24 sommets, les tourne dans l’ordre Y/X/Z, les translate et les projette ; trace ensuite au plus 16 arêtes filtrées par masques de lacet et, éventuellement, par faces avant. Une échelle non positive devient l’unité (256). Les pointeurs de modèle, sommets ou arêtes nuls sont ignorés ; les tables référencées doivent rester lisibles. Produits d’échelle et translations doivent tenir sur 16 bits signés. Les arêtes traversant une limite de profondeur sont rejetées, pas découpées. 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); Redimensionne au plus 24 sommets, les tourne Y/X/Z, les translate et les projette, puis parcourt les edge_count entrées, compteur sur un octet, avec filtrage facultatif par faces adjacentes. Le tampon de faces est limité à 16 ; les tables d’arêtes doivent contenir toutes les entrées déclarées. Une échelle non positive signifie 256. Les pointeurs de modèle, sommets ou arêtes nuls sont ignorés. Gardez produits et translations sur 16 bits signés ; les arêtes traversant une limite de profondeur sont rejetées.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
WIRE3D_DMG_HEIGHT vaut 120 par défaut. Utilisez wire3d_dmg_96.c pour la hauteur 96. SelectEdgeMask est disponible à la hauteur 96 ; RotatePoint, DrawIndexedEdges, les contrôles d’autorisation de transfert et les transferts directs exigent la hauteur 120.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Des modèles à l’échelle unitaire et à demi-échelle apparaissent au-dessus d’une scène issue d’un tableau d’objets aux mêmes échelles, illustrant projection et redimensionnement.
Commande de compilation
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-disasmImplémentation et source
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
Dessine au plus huit objets du plus proche au plus lointain, les faces proches masquant les arêtes suivantes.
Syntaxe
void Wire3DDMG_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count);Paramètres
objectsTableau d’objets contenant positions, rotations, échelles et indicateurs de visibilité.
countNombre d’entrées fournies ; consultez la limite de traitement propre à l’opération.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count); Traite au plus les huit premiers objets, triés du plus proche au plus lointain selon la profondeur de leur origine transformée. Dessine les modèles visibles et valides, puis marque les rectangles englobants de leurs faces avant pour rejeter les lignes suivantes dont tous les points échantillonnés sont masqués. C’est une approximation de l’occlusion entre objets, pas un tampon de profondeur. Efface son masque mais conserve les pixels déjà préparés. Ignore les tableaux null ; les objets et leurs données doivent rester lisibles. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count); Trie au plus huit origines d’objets selon leur profondeur caméra, du plus proche au plus lointain. Dessine les modèles visibles et valides et marque les rectangles englobants des faces avant pour les objets suivants. La première place triée évite les tests de masque ; la dernière n’ajoute pas d’occultant. C’est un rejet grossier de lignes, pas un tampon de profondeur. Ignore null et les entrées vides ; données de l’appelant et cache de projection courant doivent rester valides pendant le parcours.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
WIRE3D_DMG_HEIGHT vaut 120 par défaut. Utilisez wire3d_dmg_96.c pour la hauteur 96. SelectEdgeMask est disponible à la hauteur 96 ; RotatePoint, DrawIndexedEdges, les contrôles d’autorisation de transfert et les transferts directs exigent la hauteur 120.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Des modèles à l’échelle unitaire et à demi-échelle apparaissent au-dessus d’une scène issue d’un tableau d’objets aux mêmes échelles, illustrant projection et redimensionnement.
Commande de compilation
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-disasmImplémentation et source
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
Soumet à la VRAM les écritures du fond en attente et le dessin préparé.
Syntaxe
void Wire3DDMG_EndFrame();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_EndFrame(); Attend le prochain VBlank, applique les écritures BG en attente, puis copie la zone de préparation en VRAM en interrogeant les fenêtres d’accès. La copie consomme les pixels préparés. Le transfert peut dépasser le VBlank ; ce n’est pas un échange atomique d’image. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_EndFrame(); Attend le prochain VBlank et applique les écritures BG, puis consomme éventuellement les bandes auxiliaires avant de transférer les tuiles modifiées ou toute la zone principale. Le recouvrement des sources auxiliaire et principale rend cet ordre important. L’interrogation de STAT continue à travers les fenêtres d’accès ; la mise à jour peut dépasser un seul VBlank.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
WIRE3D_DMG_HEIGHT vaut 120 par défaut. Utilisez wire3d_dmg_96.c pour la hauteur 96. SelectEdgeMask est disponible à la hauteur 96 ; RotatePoint, DrawIndexedEdges, les contrôles d’autorisation de transfert et les transferts directs exigent la hauteur 120.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.
Commande de compilation
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-disasmImplémentation et source
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
Projette les triangles avant du modèle et efface les pixels préparés à l’intérieur.
Syntaxe
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);Paramètres
modelModèle contenant les tableaux de sommets, d’arêtes et de faces, ainsi que leurs nombres ; ses tables doivent rester lisibles pendant l’appel.
xComposante X du point ou de l’origine de l’objet en coordonnées du monde.
yComposante Y du point ou de l’origine de l’objet en coordonnées du monde.
zComposante Z du point ou de l’origine de l’objet en coordonnées du monde.
rxRotation autour de X ; seize pas font un tour complet.
ryRotation autour de Y ; seize pas font un tour complet.
rzRotation autour de Z ; seize pas font un tour complet.
scale_q8Échelle dont l’unité vaut 256 ; les valeurs nulles ou négatives signifient aussi l’unité.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
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); Projette au plus 24 sommets et efface l’intérieur des triangles avant dans la zone de préparation, pour un modèle doté d’indicateurs de lignes cachées et de données de faces. Une échelle non positive signifie 256, soit l’unité. Examine au plus 16 faces ; celles traversant une limite de profondeur sont ignorées. Remplace aussi les caches de projection partagés, sans mettre à jour la 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); Projette au plus 24 sommets et efface l’intérieur des triangles avant dans la zone de préparation, pour un modèle doté d’indicateurs de lignes cachées et de données de faces. Une échelle non positive signifie 256, soit l’unité. Examine au plus 16 faces ; celles traversant une limite de profondeur sont ignorées. Remplace aussi les caches de projection partagés, sans mettre à jour la VRAM.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
WIRE3D_DMG_HEIGHT vaut 120 par défaut. Utilisez wire3d_dmg_96.c pour la hauteur 96. SelectEdgeMask est disponible à la hauteur 96 ; RotatePoint, DrawIndexedEdges, les contrôles d’autorisation de transfert et les transferts directs exigent la hauteur 120.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Les faces projetées effacent une région remplie, rendant visibles les zones conservées et effacées.
Commande de compilation
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-disasmImplémentation et source
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
Efface un segment horizontal, bornes incluses, sur une ligne préparée.
Syntaxe
void Wire3DDMG_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1);Paramètres
yCoordonnée Y en pixels de la ligne à effacer.
x0Borne X inférieure, en pixels du viewport ; l’ordre et le découpage suivent les notes de cette opération.
x1Borne X supérieure, en pixels du viewport ; l’ordre et le découpage suivent les notes de cette opération.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1); Ordonne les extrémités X et efface le segment préparé, bornes incluses. Les deux extrémités doivent être dans 0..127 ; un Y invalide est ignoré. La routine ne découpe pas X à votre place. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1); Ordonne les extrémités X et efface le segment préparé, bornes incluses. Les deux extrémités doivent être dans 0..127 ; un Y invalide est ignoré. La routine ne découpe pas X à votre place.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
WIRE3D_DMG_HEIGHT vaut 120 par défaut. Utilisez wire3d_dmg_96.c pour la hauteur 96. SelectEdgeMask est disponible à la hauteur 96 ; RotatePoint, DrawIndexedEdges, les contrôles d’autorisation de transfert et les transferts directs exigent la hauteur 120.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.
Commande de compilation
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-disasmImplémentation et source
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
Efface un triangle en coordonnées écran dans la zone de préparation, par segments horizontaux de lignes de balayage.
Syntaxe
void Wire3DDMG_EraseTriangle2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by, w3ddmg_u8 cx, w3ddmg_u8 cy);Paramètres
axCoordonnée X du sommet A en pixels du viewport.
ayCoordonnée Y du sommet A en pixels du viewport.
bxCoordonnée X du sommet B en pixels du viewport.
byCoordonnée Y du sommet B en pixels du viewport.
cxCoordonnée X du sommet C en pixels du viewport.
cyCoordonnée Y du sommet C en pixels du viewport.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
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); Efface un triangle dans les pixels préparés à l’aide d’intersections entières avec les lignes de balayage. Fournissez des coordonnées du viewport. Les triangles dégénérés sont ignorés ; masque d’occlusion et VRAM restent inchangés. 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); Efface un triangle dans les pixels préparés à l’aide d’intersections entières avec les lignes de balayage. Fournissez des coordonnées du viewport. Les triangles dégénérés sont ignorés ; masque d’occlusion et VRAM restent inchangés.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
WIRE3D_DMG_HEIGHT vaut 120 par défaut. Utilisez wire3d_dmg_96.c pour la hauteur 96. SelectEdgeMask est disponible à la hauteur 96 ; RotatePoint, DrawIndexedEdges, les contrôles d’autorisation de transfert et les transferts directs exigent la hauteur 120.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Les faces projetées effacent une région remplie, rendant visibles les zones conservées et effacées.
Commande de compilation
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-disasmImplémentation et source
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
Initialise le LCD, les tuiles et la carte du fond pour un viewport filaire monochrome.
Syntaxe
void Wire3DDMG_Init();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_Init(); Prend le contrôle du LCD : attend le VBlank, l’éteint, efface 6144 octets de tuiles et la carte BG, installe les tuiles HUD et le viewport 128×96 à numéros de tuiles signés, puis active le fond avec défilement nul et BGP=0xB4. Réinitialise caméra, file BG et zone de préparation. Réservez 0xD000..0xDFFF pour cette zone et conservez son mappage de banque WRAM. Appelez BeginFrame avant de dessiner pour initialiser aussi l’occlusion. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_Init(); Prend le contrôle du LCD, efface la VRAM des tuiles et la carte BG, puis installe un viewport de 16×15 à partir de la tuile (3,1). Règle le défilement à (8,0), BGP à 0xB4 et active le fond. Réinitialise caméra, files, modes de transfert, les deux tables de modifications et la zone de préparation. Réservez 0xD000..0xDFFF et gardez son mappage WRAM ; le stockage auxiliaire partage ces adresses. Appelez BeginFrame avant de dessiner pour établir l’état d’occlusion.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
WIRE3D_DMG_HEIGHT vaut 120 par défaut. Utilisez wire3d_dmg_96.c pour la hauteur 96. SelectEdgeMask est disponible à la hauteur 96 ; RotatePoint, DrawIndexedEdges, les contrôles d’autorisation de transfert et les transferts directs exigent la hauteur 120.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.
Commande de compilation
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-disasmImplémentation et source
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
Projette un point du monde par la caméra vers les coordonnées du viewport.
Syntaxe
w3ddmg_u8 Wire3DDMG_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy);Paramètres
xComposante X du point ou de l’origine de l’objet en coordonnées du monde.
yComposante Y du point ou de l’origine de l’objet en coordonnées du monde.
zComposante Z du point ou de l’origine de l’objet en coordonnées du monde.
sxPointeur u8 valide et accessible en écriture recevant la coordonnée X projetée.
syPointeur u8 valide et accessible en écriture recevant la coordonnée Y projetée.
Valeur renvoyée
Renvoie 1 si la projection réussit, 0 si la profondeur est rejetée.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96 w3ddmg_u8 Wire3DDMG_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy); Projette un point du monde avec la caméra courante. Une profondeur rejetée renvoie zéro sans changer les sorties ; le succès écrit des coordonnées bornées à 128×96. Les pointeurs de sortie doivent être valides. Borner à l’écran n’est pas un découpage géométrique. WIRE3D_DMG_HEIGHT = 120 w3ddmg_u8 Wire3DDMG_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy); Projette un point du monde avec la caméra courante. Une profondeur invalide renvoie zéro sans changer les sorties ; le succès écrit des coordonnées bornées à 128×120. Les deux pointeurs de sortie doivent être valides. Les différences de coordonnées doivent tenir dans s16.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
WIRE3D_DMG_HEIGHT vaut 120 par défaut. Utilisez wire3d_dmg_96.c pour la hauteur 96. SelectEdgeMask est disponible à la hauteur 96 ; RotatePoint, DrawIndexedEdges, les contrôles d’autorisation de transfert et les transferts directs exigent la hauteur 120.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.
Commande de compilation
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-disasmImplémentation et source
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
Met en file une écriture de numéro de tuile dans une case de la carte du fond.
Syntaxe
void Wire3DDMG_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile);Paramètres
xCoordonnée X en tuiles dans la carte de fond de 32×32.
yCoordonnée Y en tuiles dans la carte de fond de 32×32.
tileNuméro de tuile sur huit bits pour la case du fond.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile); Met en file une écriture de tuile dans la carte 32×32 en 0x9800 pour EndFrame. Les coordonnées invalides et les soumissions au-delà de 48 écritures en attente sont ignorées sans signalement. Cette file est distincte de celle de la bibliothèque vram générale. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile); Met en file une écriture de tuile dans la carte 32×32 en 0x9800 pour EndFrame. Les coordonnées invalides et les soumissions au-delà de 48 écritures en attente sont ignorées sans signalement. Cette file est distincte de celle de la bibliothèque vram générale.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
WIRE3D_DMG_HEIGHT vaut 120 par défaut. Utilisez wire3d_dmg_96.c pour la hauteur 96. SelectEdgeMask est disponible à la hauteur 96 ; RotatePoint, DrawIndexedEdges, les contrôles d’autorisation de transfert et les transferts directs exigent la hauteur 120.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.
Commande de compilation
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-disasmImplémentation et source
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
Fait tourner un point sur place selon les angles fournis.
Syntaxe
void Wire3DDMG_RotatePoint(w3ddmg_i16* x, w3ddmg_i16* y, w3ddmg_i16* z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz);Paramètres
xPointeur s16 distinct et accessible en écriture pour la composante X.
yPointeur s16 distinct et accessible en écriture pour la composante Y.
zPointeur s16 distinct et accessible en écriture pour la composante Z.
rxRotation autour de X ; seize pas font un tour complet.
ryRotation autour de Y ; seize pas font un tour complet.
rzRotation autour de Z ; seize pas font un tour complet.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
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); Tourne sur place dans l’ordre Y/X/Z, avec 16 pas par tour. Un pointeur de composante null rend tout l’appel sans effet ; utilisez des pointeurs distincts. Chaque rotation d’axe borne ses entrées à ±220.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
WIRE3D_DMG_HEIGHT vaut 120 par défaut. Utilisez wire3d_dmg_96.c pour la hauteur 96. SelectEdgeMask est disponible à la hauteur 96 ; RotatePoint, DrawIndexedEdges, les contrôles d’autorisation de transfert et les transferts directs exigent la hauteur 120.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Des modèles à l’échelle unitaire et à demi-échelle apparaissent au-dessus d’une scène issue d’un tableau d’objets aux mêmes échelles, illustrant projection et redimensionnement.
Commande de compilation
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-disasmImplémentation et source
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
Choisit un masque précalculé de visibilité des arêtes selon le lacet de l’objet.
Syntaxe
w3ddmg_u16 Wire3DDMG_SelectEdgeMask(const Wire3DDMG_Model* model, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz);Paramètres
modelModèle contenant les tableaux de sommets, d’arêtes et de faces, ainsi que leurs nombres ; ses tables doivent rester lisibles pendant l’appel.
rxRotation autour de X ; seize pas font un tour complet.
ryRotation autour de Y ; seize pas font un tour complet.
rzRotation autour de Z ; seize pas font un tour complet.
Valeur renvoyée
Masque de visibilité des arêtes sur 16 bits, ou 0xFFFF si aucune table n’est fournie.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96 w3ddmg_u16 Wire3DDMG_SelectEdgeMask(const Wire3DDMG_Model* model, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz); Choisit un masque précalculé d’après les quatre bits faibles du lacet de l’objet ; tangage, roulis et orientation de caméra sont ignorés. Utilisez 16, 8, 4 ou 2 secteurs ; les autres nombres positifs sélectionnent l’entrée zéro, sauf qu’un nombre >=16 utilise les 16 premières. Sans données, renvoie 0xFFFF. La table de masques doit rester lisible avec le mappage courant des pointeurs de données.
Cet exemple utilise le profil 128×96 ; son viewport commence à l’écran en (0,0). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
WIRE3D_DMG_HEIGHT vaut 120 par défaut. Utilisez wire3d_dmg_96.c pour la hauteur 96. SelectEdgeMask est disponible à la hauteur 96 ; RotatePoint, DrawIndexedEdges, les contrôles d’autorisation de transfert et les transferts directs exigent la hauteur 120.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Des modèles à l’échelle unitaire et à demi-échelle apparaissent au-dessus d’une scène issue d’un tableau d’objets aux mêmes échelles, illustrant projection et redimensionnement.
Commande de compilation
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-disasmImplémentation et source
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
Choisit si EndFrame transfère aussi les bandes auxiliaires.
Syntaxe
void Wire3DDMG_SetAuxTransfer(w3ddmg_u8 flag);Paramètres
flagZéro désactive la fonction de transfert ; toute autre valeur l’active.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_SetAuxTransfer(w3ddmg_u8 flag); Mémorise l’autorisation de transfert auxiliaire d’EndFrame ; toute valeur non nulle l’active. Aucune donnée n’est copiée ou effacée ici. Les octets source auxiliaires partagent les adresses de la zone principale.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
WIRE3D_DMG_HEIGHT vaut 120 par défaut. Utilisez wire3d_dmg_96.c pour la hauteur 96. SelectEdgeMask est disponible à la hauteur 96 ; RotatePoint, DrawIndexedEdges, les contrôles d’autorisation de transfert et les transferts directs exigent la hauteur 120.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Une partie de la zone principale est consommée par le transfert auxiliaire, ce qui produit un bloc noir de 8×8 à l’écran en (80,24).
Commande de compilation
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-disasmImplémentation et source
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
Mémorise la position et l’orientation de la caméra pour les projections suivantes.
Syntaxe
void Wire3DDMG_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 pitch, w3ddmg_u8 yaw, w3ddmg_u8 roll);Paramètres
xComposante X de la caméra en coordonnées du monde.
yComposante Y de la caméra en coordonnées du monde.
zComposante Z de la caméra en coordonnées du monde.
pitchRotation autour de X ; seize pas font un tour complet.
yawRotation autour de Y ; seize pas font un tour complet.
rollRotation autour de Z ; seize pas font un tour complet.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
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); Mémorise la position et les angles de caméra pour les dessins suivants ; un tour compte 16 pas angulaires. Ne reprojette pas les dessins existants et ne valide pas les plages d’entrée. 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); Mémorise la position et les angles de caméra pour les dessins suivants ; un tour compte 16 pas angulaires. Ne reprojette pas les dessins existants et ne valide pas les plages d’entrée.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
WIRE3D_DMG_HEIGHT vaut 120 par défaut. Utilisez wire3d_dmg_96.c pour la hauteur 96. SelectEdgeMask est disponible à la hauteur 96 ; RotatePoint, DrawIndexedEdges, les contrôles d’autorisation de transfert et les transferts directs exigent la hauteur 120.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.
Commande de compilation
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-disasmImplémentation et source
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
Sélectionne le transfert des tuiles modifiées pour le viewport principal de 120 lignes.
Syntaxe
void Wire3DDMG_SetDirtyTransfer(w3ddmg_u8 flag);Paramètres
flagZéro désactive la fonction de transfert ; toute autre valeur l’active.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_SetDirtyTransfer(w3ddmg_u8 flag); Mémorise l’autorisation de transfert des zones modifiées et efface les deux historiques de modifications ainsi que la zone principale, même si la valeur ne change pas. La VRAM est conservée ; l’activer sur une ancienne image peut laisser d’anciennes tuiles non marquées. Préparez donc un affichage de départ propre.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
WIRE3D_DMG_HEIGHT vaut 120 par défaut. Utilisez wire3d_dmg_96.c pour la hauteur 96. SelectEdgeMask est disponible à la hauteur 96 ; RotatePoint, DrawIndexedEdges, les contrôles d’autorisation de transfert et les transferts directs exigent la hauteur 120.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
L’ancien cadre en haut à gauche disparaît ; seul reste le nouveau cadre aux coordonnées écran (96,88)..(120,112).
Commande de compilation
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-disasmImplémentation et source
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
Écrit la correspondance des quatre nuances dans le registre de palette du fond monochrome BGP.
Syntaxe
void Wire3DDMG_SetPalette(w3ddmg_u8 bgp);Paramètres
bgpValeur du registre BGP contenant quatre affectations de nuance sur deux bits.
Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_SetPalette(w3ddmg_u8 bgp); Écrit immédiatement l’encodage brut de la palette DMG BGP, sans synchronisation d’image. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_SetPalette(w3ddmg_u8 bgp); Écrit immédiatement l’encodage brut de la palette DMG BGP, sans synchronisation d’image.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
WIRE3D_DMG_HEIGHT vaut 120 par défaut. Utilisez wire3d_dmg_96.c pour la hauteur 96. SelectEdgeMask est disponible à la hauteur 96 ; RotatePoint, DrawIndexedEdges, les contrôles d’autorisation de transfert et les transferts directs exigent la hauteur 120.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Cet exemple montre lignes, points, effacement et projection dans une même image. Le milieu du bord supérieur du cadre en haut à gauche est effacé, et une diagonale est projetée près du centre. Une projection rejetée conserve les sorties 91 et 92.
Commande de compilation
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-disasmImplémentation et source
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
Transfère immédiatement six bandes auxiliaires et efface leurs octets source.
Syntaxe
void Wire3DDMG_TransferAuxNow();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_TransferAuxNow(); Transfère et consomme immédiatement les bandes source auxiliaires, indépendamment de leur autorisation. N’attend pas le début du VBlank et ne met à jour ni historique de modifications ni file BG. La source recouvre la zone principale ; coordonnez les deux transferts.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
WIRE3D_DMG_HEIGHT vaut 120 par défaut. Utilisez wire3d_dmg_96.c pour la hauteur 96. SelectEdgeMask est disponible à la hauteur 96 ; RotatePoint, DrawIndexedEdges, les contrôles d’autorisation de transfert et les transferts directs exigent la hauteur 120.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Une ligne horizontale projetée et un bloc auxiliaire de 8×8 illustrent les transferts directs ; un octet source passe de 255 à 0 lorsqu’il est consommé.
Commande de compilation
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-disasmImplémentation et source
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
Transfère immédiatement toute la zone principale et efface les pixels source consommés.
Syntaxe
void Wire3DDMG_TransferMainNow();Valeur renvoyée
Aucune valeur de retour ; l’état modifié et les contraintes temporelles d’affichage sont décrits ci-dessus.
Conditions et limites
WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_TransferMainNow(); Transfère et consomme immédiatement toute la zone principale en interrogeant STAT, sans attendre le prochain VBlank. Ignore les autorisations de transfert et conserve les historiques de modifications et la file de tuiles BG ; l’appelant coordonne le cycle de l’image.
Cet exemple utilise le profil 128×120 ; son viewport commence à l’écran en (16,8). Réservez WRAM D000..DFFF et gardez son mappage de banque stable, sur CGB également. L’état partagé n’est pas réentrant.
WIRE3D_DMG_HEIGHT vaut 120 par défaut. Utilisez wire3d_dmg_96.c pour la hauteur 96. SelectEdgeMask est disponible à la hauteur 96 ; RotatePoint, DrawIndexedEdges, les contrôles d’autorisation de transfert et les transferts directs exigent la hauteur 120.
WIRE3D_DMG_HEIGHT accepte 88, 96 ou 120 ; WIRE3DCGB_HEIGHT accepte 88 ou 96. Les valeurs par défaut restent DMG 120 et CGB 96. Le profil de 88 lignes mesure 128×88, avec Y central=44. Utilisez le même réglage dans la bibliothèque et le programme ; compilez wire3d_dmg_88.c / wire3d_cgb_88.c à la place de l’entrée normale. DMG 88 garde la structure des modèles à 96 lignes et la limite de 16 arêtes. Le mode CGB 160×144 reste inchangé.
Exemple d’utilisation
#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) {}
}Résultat attendu
Une ligne horizontale projetée et un bloc auxiliaire de 8×8 illustrent les transferts directs ; un octet source passe de 255 à 0 lorsqu’il est consommé.
Commande de compilation
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-disasmImplémentation et source
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();
}Structures, constantes et en-têtes complets
Consultez ces en-têtes pour les macros qui ne sont pas des fonctions, les structures, les limites des tableaux, les énumérations et les alias. Ils reproduisent fidèlement les sources collectées, commentaires d'origine compris.
asset.h — Identifiants de ressources et descripteurs de données
#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 — Musique, effets sonores et commandes audio
#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 — Lecture musicale par interruption VBlank
#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 — Accès au code et aux données tenant compte des banques
#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 — Coordonnées du monde et zones visibles
#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 — Palettes BG et OBJ de la CGB
#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 — Numéros et attributs de tuiles CGB
#pragma once
// Declarations for compiler-intrinsic CGB tile helpers.
// Canonical intrinsic entry points use the "__" prefix.
// Attr writes no-op on DMG. Combined tile+attr writes still write the tile on DMG.
// These helpers emit compiler code; cgb_tile.c has no runtime bodies. Scalar coordinates address 32x32 maps.
// Safe write paths poll VRAM access; LCD-on paths can enable interrupts after writing.
// Use _unsafe/_fast only with caller-managed writable VRAM timing, especially inside an ISR.
// Tile writes use the selected VRAM bank; choose bank zero before combined tile/attribute operations.
#define KQ_CGB_ATTR_PAL_MASK 0x07
#define KQ_CGB_ATTR_BANK1 0x08
#define KQ_CGB_ATTR_XFLIP 0x20
#define KQ_CGB_ATTR_YFLIP 0x40
#define KQ_CGB_ATTR_PRIORITY 0x80
#define KQ_CGB_ATTR_NONE ((u8)0)
#define KQ_CGB_ATTR_PAL(n) ((u8)((n) & KQ_CGB_ATTR_PAL_MASK))
#define KQ_CGB_ATTR_BANK(bank) ((u8)((bank) ? KQ_CGB_ATTR_BANK1 : 0))
#define KQ_CGB_ATTR_XFLIP_IF(enabled) ((u8)((enabled) ? KQ_CGB_ATTR_XFLIP : 0))
#define KQ_CGB_ATTR_YFLIP_IF(enabled) ((u8)((enabled) ? KQ_CGB_ATTR_YFLIP : 0))
#define KQ_CGB_ATTR_PRIORITY_IF(enabled) ((u8)((enabled) ? KQ_CGB_ATTR_PRIORITY : 0))
#define KQ_CGB_ATTR(palette, bank, xflip, yflip, priority) ((u8)(((palette) & KQ_CGB_ATTR_PAL_MASK) | ((bank) ? KQ_CGB_ATTR_BANK1 : 0) | ((xflip) ? KQ_CGB_ATTR_XFLIP : 0) | ((yflip) ? KQ_CGB_ATTR_YFLIP : 0) | ((priority) ? KQ_CGB_ATTR_PRIORITY : 0)))
// Return the compiler/runtime CGB mode test as a byte Boolean.
u8 __cgb_is_cgb();
// Write the VRAM bank selection only on CGB. Safe here means hardware-mode guarded, not PPU-timed.
void __cgb_safe_set_vbk(u8 value);
// Write a tile number to map 9800, waiting for VRAM access when necessary.
void __settile(u8 x, u8 y, u8 tile);
// Write a tile number to map 9800 without waiting for writable VRAM.
void __settile_unsafe(u8 x, u8 y, u8 tile);
// Write at base+32*y+x with VRAM access checks; supply a valid tile-map base.
void __settileat(u16 base, u8 x, u8 y, u8 tile);
// Use an explicit map base without waiting for VRAM access.
void __settileat_unsafe(u16 base, u8 x, u8 y, u8 tile);
// Select the window map from LCDC bit 6, then write a tile with access checks.
void __settilewin(u8 x, u8 y, u8 tile);
// Select the LCDC window map and write without access waits.
void __settilewin_unsafe(u8 x, u8 y, u8 tile);
// Select the background map from LCDC bit 3, then write with access checks.
void __settilebg(u8 x, u8 y, u8 tile);
// Select the LCDC background map and write without access waits.
void __settilebg_unsafe(u8 x, u8 y, u8 tile);
// Copy count sequential bytes to dest using the current VRAM bank and access-checked transfer.
void __settile_bulk(u16 dest, const u8* src, u8 count);
// Copy count sequential bytes to dest without VRAM access waits; retain source-bank visibility.
void __settile_bulk_fast(u16 dest, const u8* src, u8 count);
// Write attributes in bank one at map 9800 on CGB, then leave VBK zero; skip on DMG. Use the access-checked write path.
void __settileattr(u8 x, u8 y, u8 attr);
// Write attributes in bank one at map 9800 on CGB, then leave VBK zero; skip on DMG. No VRAM access waits are inserted.
void __settileattr_unsafe(u8 x, u8 y, u8 attr);
// Write tile and CGB attributes at map 9800; DMG receives only the tile write. Use the access-checked write path.
void __settilecgb(u8 x, u8 y, u8 tile, u8 attr);
// Write tile and CGB attributes at map 9800; DMG receives only the tile write. No VRAM access waits are inserted.
void __settilecgb_unsafe(u8 x, u8 y, u8 tile, u8 attr);
// Write attributes in bank one at the explicit map base on CGB, then leave VBK zero; skip on DMG. Use the access-checked write path.
void __settileatattr(u16 base, u8 x, u8 y, u8 attr);
// Write attributes in bank one at the explicit map base on CGB, then leave VBK zero; skip on DMG. No VRAM access waits are inserted.
void __settileatattr_unsafe(u16 base, u8 x, u8 y, u8 attr);
// Write tile and CGB attributes at the explicit map base; DMG receives only the tile write. Use the access-checked write path.
void __settileatcgb(u16 base, u8 x, u8 y, u8 tile, u8 attr);
// Write tile and CGB attributes at the explicit map base; DMG receives only the tile write. No VRAM access waits are inserted.
void __settileatcgb_unsafe(u16 base, u8 x, u8 y, u8 tile, u8 attr);
// Write attributes in bank one at the LCDC window map on CGB, then leave VBK zero; skip on DMG. Use the access-checked write path.
void __settilewinattr(u8 x, u8 y, u8 attr);
// Write attributes in bank one at the LCDC window map on CGB, then leave VBK zero; skip on DMG. No VRAM access waits are inserted.
void __settilewinattr_unsafe(u8 x, u8 y, u8 attr);
// Write tile and CGB attributes at the LCDC window map; DMG receives only the tile write. Use the access-checked write path.
void __settilewincgb(u8 x, u8 y, u8 tile, u8 attr);
// Write tile and CGB attributes at the LCDC window map; DMG receives only the tile write. No VRAM access waits are inserted.
void __settilewincgb_unsafe(u8 x, u8 y, u8 tile, u8 attr);
// Write attributes in bank one at the LCDC background map on CGB, then leave VBK zero; skip on DMG. Use the access-checked write path.
void __settilebgattr(u8 x, u8 y, u8 attr);
// Write attributes in bank one at the LCDC background map on CGB, then leave VBK zero; skip on DMG. No VRAM access waits are inserted.
void __settilebgattr_unsafe(u8 x, u8 y, u8 attr);
// Write tile and CGB attributes at the LCDC background map; DMG receives only the tile write. Use the access-checked write path.
void __settilebgcgb(u8 x, u8 y, u8 tile, u8 attr);
// Write tile and CGB attributes at the LCDC background map; DMG receives only the tile write. No VRAM access waits are inserted.
void __settilebgcgb_unsafe(u8 x, u8 y, u8 tile, u8 attr);
// Copy count attributes to dest in bank one on CGB, then leave VBK zero; skip on DMG. Transfers use access checks.
void __settileattr_bulk(u16 dest, const u8* src, u8 count);
// Copy count attributes to dest in bank one on CGB, then leave VBK zero; skip on DMG. The caller supplies writable VRAM timing.
void __settileattr_bulk_fast(u16 dest, const u8* src, u8 count);
// Copy tile and attribute streams to dest; DMG receives only tiles. Keep both sources readable. Transfers use access checks.
void __settilecgb_bulk(u16 dest, const u8* tile_src, const u8* attr_src, u8 count);
// Copy tile and attribute streams to dest; DMG receives only tiles. Keep both sources readable. The caller supplies writable VRAM timing.
void __settilecgb_bulk_fast(u16 dest, const u8* tile_src, const u8* attr_src, u8 count);kitaqgb/lib/cgb_tile.h
chain.h — Tampons circulaires pour l'historique des positions
#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 — Réserves de projectiles, éventails, impacts et frôlements
#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 — Enregistrements en RAM et assertions
#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 — Rendu filaire monochrome de 128×120 pour 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 — Réserves d'objets fondées sur des tableaux fixes
#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 — Calcul en virgule fixe Q8.8 et rectangles
#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 — État des boutons, appuis, relâchements et répétition
#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 — Communication série et paquets logiques
#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 — Communication DMG-07 avec horloge externe
#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 — Mouvement et collisions en 2D
#pragma once
// Position and velocity use caller-selected integer units with one integration
// step per call; no hidden pixel or time conversion occurs. Keep intermediate
// signed arithmetic in range. World/body storage is owned by the caller.
#include "fixed.h"
// Multiply a signed word by a signed byte; divide by 256, truncating toward zero.
s16 __smul16x8(s16 a, s8 b);
// Lightweight deterministic 2D physics for KITAQGB.
// Integer pixels per step are one possible unit convention; inv_mass is Q8.
typedef struct {
s16 x;
s16 y;
s16 vx;
s16 vy;
s16 half_x;
s16 half_y;
s16 inv_mass_q8; // 0 means static body.
s16 restitution_q8; // 0..255 (reserved for future tuning).
u8 active;
} KQBody2D;
typedef struct {
KQBody2D* bodies;
u8 body_count;
s16 gravity_x;
s16 gravity_y;
u8 solver_iterations;
s16 max_speed;
} KQWorld2D;
// Retain the caller-owned body array without initializing its elements.
// Set gravity to (0,32), four contact iterations and a per-axis speed limit of 512.
// A null world is ignored; the array must outlive subsequent world operations.
void kq2d_world_init(KQWorld2D* world, KQBody2D* bodies, u8 body_count);
// Advance active dynamic bodies, then visit each active unordered pair for
// the configured contact passes (zero means one). Static bodies still participate
// as obstacles. The world borrows its array and shares non-reentrant ASM scratch.
// This is discrete integration; fast bodies can pass through thin obstacles.
void kq2d_step(KQWorld2D* world);
// For one active dynamic body, add gravity, clamp each velocity axis and then
// add velocity to position. Null inputs are ignored; no contacts are solved.
// Use a nonnegative speed limit and keep additions in signed 16-bit range.
void kq2d_integrate_body(KQWorld2D* world, KQBody2D* body);
// Test strict overlap of two centered boxes; touching edges return false.
// Both pointers must be valid. Active/mass flags are ignored, and coordinate
// differences and extent sums must fit the signed 16-bit calculations.
u8 kq2d_overlap_aabb(const KQBody2D* a, const KQBody2D* b);
// Initialize an active unit-inverse-mass body at the supplied center and half
// extents, with zero velocity and reserved restitution set to zero. Null is ignored.
void kq2d_body_init(KQBody2D* body, s16 x, s16 y, s16 half_x, s16 half_y);
// Replace the center without altering velocity, extents or activity. Null is ignored.
void kq2d_body_set_pos(KQBody2D* body, s16 x, s16 y);
// Replace velocity without clamping or checking activity/mass. Null is ignored.
void kq2d_body_set_velocity(KQBody2D* body, s16 vx, s16 vy);
// Add gravity and clamp each velocity axis separately for an active dynamic
// body. Null, inactive and static bodies are ignored. Supply a nonnegative limit
// and avoid overflow in the additions before clamping; position is unchanged.
void kq2d_body_apply_gravity(KQBody2D* body, s16 gravity_x, s16 gravity_y, s16 max_speed);
// Scale both velocities through the signed 8-bit coefficient intrinsic.
// Despite the unsigned parameter, values 128..255 become negative coefficients;
// this is not a full-range unsigned Q8 damping helper. Null is ignored.
void kq2d_body_apply_friction(KQBody2D* body, u8 friction_q8);
// Delegate strict rectangle overlap to the fixed-point utility; edge-only
// contact is false. Coordinate-plus-size sums must remain representable as s16.
u8 kq2d_rect_intersect(KQRect a, KQRect b);
// Delegate the half-open point test: include left/top and exclude right/bottom.
// Coordinate-plus-size sums must remain representable as s16.
u8 kq2d_point_in_rect(s16 x, s16 y, KQRect r);
// Opt-in surface solver. Velocities/threshold/kick share the caller's units.
// Normal must be unit length in Q8; coefficients are 0..255.
typedef struct {
s16 nx_q8;
s16 ny_q8;
s16 vx;
s16 vy;
s16 bounce_threshold;
s16 kick;
u8 restitution_q8;
u8 friction_q8;
} KQSurface2D;
// Truncates toward zero, including negative values; coefficient is -256..256.
s16 kq2d_scale_q8(s16 value, s16 coefficient);
// Conservative circular bound, with a shared Q8 scale for both components.
// Quantizes toward zero; very small limits relative to input may yield zero.
// Components and positive max_speed must be <= 16383 in magnitude.
void kq2d_body_limit_speed(KQBody2D* body, s16 max_speed);
// Kinematic surface response; returns incoming normal speed, or zero if separating.
// Caller resolves penetration separately. Relative components must fit +/-8191.
s16 kq2d_body_resolve_surface(KQBody2D* body, const KQSurface2D* surface);
// Linear crossing time in Q8 (0..256); positive separation is outside.
// Returns 0 for initial overlap, 256 for no crossing. Gaps must fit +/-8191.
u16 kq2d_surface_toi_q8(s16 start_gap, s16 end_gap);kitaqgb/lib/physics2d.h
physics2d_circle.h — Physique des cercles
#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 — Physique des AABB en 3D
#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 — Tables de défilement par bandes et lignes
#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 — Nombres aléatoires, texte, cartes, sauvegardes et services RPG/ADV/SLG
#pragma once
// The application supplies frame/cursor/font tiles at these indices; these constants do not load graphics.
#ifndef TEXT_TILE_FILL
#define TEXT_TILE_FILL ((u8)0)
#endif
#ifndef TEXT_TILE_FRAME_TL
#define TEXT_TILE_FRAME_TL ((u8)1)
#endif
#ifndef TEXT_TILE_FRAME_TR
#define TEXT_TILE_FRAME_TR ((u8)2)
#endif
#ifndef TEXT_TILE_FRAME_BL
#define TEXT_TILE_FRAME_BL ((u8)3)
#endif
#ifndef TEXT_TILE_FRAME_BR
#define TEXT_TILE_FRAME_BR ((u8)4)
#endif
#ifndef TEXT_TILE_FRAME_H
#define TEXT_TILE_FRAME_H ((u8)5)
#endif
#ifndef TEXT_TILE_FRAME_V
#define TEXT_TILE_FRAME_V ((u8)6)
#endif
#ifndef TEXT_TILE_CURSOR
#define TEXT_TILE_CURSOR ((u8)7)
#endif
#ifndef TEXT_TILE_PAGE_WAIT
#define TEXT_TILE_PAGE_WAIT ((u8)8)
#endif
#ifndef TEXT_DIGIT_BASE
#define TEXT_DIGIT_BASE ((u8)'0')
#endif
#define TEXT_CTRL_END ((u8)0x00)
#define TEXT_CTRL_NEWLINE ((u8)0x0A)
#define TEXT_CTRL_WAIT ((u8)0x01)
#define TEXT_CTRL_PAGE_WAIT ((u8)0x02)
#define PAD_KEY_RIGHT ((u8)0x01)
#define PAD_KEY_LEFT ((u8)0x02)
#define PAD_KEY_UP ((u8)0x04)
#define PAD_KEY_DOWN ((u8)0x08)
#define PAD_KEY_A ((u8)0x10)
#define PAD_KEY_B ((u8)0x20)
#define PAD_KEY_SELECT ((u8)0x40)
#define PAD_KEY_START ((u8)0x80)
// Default layout: four 512-byte slots, each with a six-byte header and at most 506 payload bytes.
#define SAVE_SLOT_COUNT ((u8)4)
#define SAVE_SLOT_SIZE ((u16)512)
#define SAVE_MAGIC0 ((u8)0x4B)
#define SAVE_MAGIC1 ((u8)0x51)
#define SAVE_VERSION ((u8)1)
#define SAVE_OK ((u8)1)
#define SAVE_ERR ((u8)0)
// A bank byte plus a CPU-visible address forms this data reference; it does not switch banks by itself.
typedef __packed struct {
u8 bank;
const u8* ptr;
} far_ptr_t;
typedef __packed struct {
u8 x;
u8 y;
u8 w;
u8 h;
const u8* const* items;
u8 count;
u8 cursor;
} menu_t;
typedef __packed struct {
u8 id;
u8 qty;
const u8* name;
} item_t;
// Packed nine-byte ordinary-map descriptor. Tile IDs use bank_tiles; collision bits and event bytes
// use the descriptor bank. Width/height are tile cells, with row-major data.
typedef __packed struct {
u8 width;
u8 height;
u8 bank_tiles;
const u8* tiles;
const u8* collision_bits;
const void* events;
} map_t;
// One 2x2 metatile: four tile IDs plus collision, palette metadata and event ID.
// The map drawing routine uses tile IDs only; it does not apply palette attributes.
typedef __packed struct {
u8 tile_tl;
u8 tile_tr;
u8 tile_bl;
u8 tile_br;
u8 collision;
u8 palette;
u8 event;
} metatile_t;
// Metatile dimensions count 2x2 cells. bank_tiles=0 means use the descriptor bank;
// nonzero bank_tiles supplies both ID-array and definition-table reads.
typedef __packed struct {
u8 width;
u8 height;
u8 bank_tiles;
const u8* metatile_ids;
const metatile_t* metatiles;
} metatile_map_t;
typedef __packed struct {
u8 x;
u8 y;
u8 w;
u8 h;
const u8* const* items;
u8 count;
u8 cursor;
u8 prev_keys;
u8 selected;
u8 cancelled;
} menu_state_t;
typedef __packed struct {
u8 x;
u8 y;
u8 hp;
u8 move;
u8 atk_min;
u8 atk_max;
u8 team;
u8 acted;
} unit_t;
void __wait_vblank();
u16 __readpadex(u8 prev_keys);
u16 __getbgmapbase();
void __memset(void* dst, u8 value, u16 count);
void __memcpy(void* dst, const void* src, u16 count);
void __settile(u8 x, u8 y, u8 tile);
void __settilebg(u8 x, u8 y, u8 tile);
void __settileat(u16 base, u8 x, u8 y, u8 tile);
void __vram_memcpy(u16 dst, const void* src, u16 len);
void __vram_memset(u16 dst, u8 value, u16 len);
void __far_memcpy(void* dst, u8 bank, const void* src, u16 len);
u8 __rng8();
void __rng_seed(u16 seed);
void __scroll_bg_set(u8 scx, u8 scy);
void __settile_xy(u8 x, u8 y, u8 tile);
void __settile_rect(u8 x, u8 y, u8 w, u8 h, u8 tile);
void __settile_row(u8 x, u8 y, const u8* src, u8 len);
void __settile_col(u8 x, u8 y, const u8* src, u8 len);
void __fill_tilemap(u16 base, u8 tile, u16 count);
void __settilemap_rect(u16 base, u8 x, u8 y, u8 w, u8 h, const u8* src);
void __vram_copy(u16 dst, const void* src, u16 len);
void __vram_fill(u16 dst, u8 value, u16 len);
void __vram_copy_hblank(u16 dst, const void* src, u16 len);
void __vram_copy_dma(u16 dst, const void* src, u16 len);
u8 __farpeek8(u8 bank, const void* addr);
u16 __farpeek16(u8 bank, const void* addr);
void __farmemcpy(void* dst, u8 bank, const void* src, u16 len);
// The current GB backend evaluates/discards these arguments but emits no indirect call.
void __farcall_ptr(u8 bank, const void* func);
#define far_read8(p) __farpeek8((p).bank, (p).ptr)
#define far_read16(p) __farpeek16((p).bank, (p).ptr)
#define far_read_block(dst, p, len) __farmemcpy((dst), (p).bank, (p).ptr, (len))
void __memcpy_small(void* dst, const void* src, u8 len);
void __memset_small(void* dst, u8 value, u8 len);
void __copy16(void* dst, const void* src);
void __copy32(void* dst, const void* src);
u16 __tile_addr(u16 base, u8 x, u8 y);
u16 __map_index(u8 x, u8 y, u8 width);
u8 __xy_in_rect(u8 x, u8 y, u8 rx, u8 ry, u8 rw, u8 rh);
u8 __manhattan(u8 x1, u8 y1, u8 x2, u8 y2);
u8 __bit_test(const u8* p, u16 bit_index);
void __bit_set(u8* p, u16 bit_index);
void __bit_clear(u8* p, u16 bit_index);
void __bit_toggle(u8* p, u16 bit_index);
// Compiler intrinsic, separate from the RAM rle_decode helpers below; it is not a bounded-stream API.
u16 __rle_decode_vram(u16 dst, u8 bank, const void* src);
// Advance the compiler-provided pseudorandom generator and return one byte.
u8 rng8();
// Consume two generator bytes in high-byte/low-byte order to form a 16-bit value.
u16 rng16();
// Reduce a random byte modulo max; zero returns zero without consuming randomness.
// Modulo reduction is biased unless max divides the generator range.
u8 rand_range(u8 max);
// Select an index from cumulative byte weights using a 16-bit random draw.
// A zero total, including an empty list, returns zero; callers must distinguish
// that case from a valid index. Modulo reduction can introduce a small bias.
u8 weighted_choice(const u8* weights, u8 count);
// Replace the generator seed so subsequent calls can reproduce a sequence.
void rng_seed(u16 seed);
// Alias the byte generator; this consumes one generator step.
u8 rng_next8();
// Alias the two-step 16-bit generator.
u16 rng_next16();
// Alias rand_range and return a value in [0,max), or zero when max is zero.
u8 rng_range(u8 max);
// Return false for zero and true for values at least 100. Intermediate values
// use the modulo-based range generator, so percentages are approximate.
u8 rng_chance(u8 percent);
// Set the tile-space window, reset its cursor and redraw it immediately.
// Opening does not reset the existing character speed or load font tiles.
void text_open(u8 x, u8 y, u8 w, u8 h);
// Erase the open window with the fill tile and disable windowed character output.
void text_close();
// Decode an END-terminated stream of tile bytes and newline/wait/page controls.
// WAIT consumes a following frame-count byte. The source must remain readable
// through blocking waits; the routine does not validate stream length.
void text_print(const u8* str);
// Decode the same text controls while fetching each byte from the specified
// ROM bank. The pointer advances within that bank; it does not roll into the next bank.
void text_print_far(u8 bank, const u8* str);
// Redraw choices and block for edge-triggered navigation: UP/DOWN wrap, A
// accepts, and B returns 0xFF. Zero choices also returns 0xFF. Choice strings
// use raw tile bytes, and the caller must fit them inside the available rows.
u8 text_choice(const u8* const* choices, u8 count);
// Set VBlank waits per windowed character; zero prints without character delays.
void text_set_speed(u8 speed);
// Open and redraw a window using the same tile-space arguments as text_open.
void text_window(u8 x, u8 y, u8 w, u8 h);
// Fill the supplied tile rectangle without changing the active text window or cursor.
void text_clear_rect(u8 x, u8 y, u8 w, u8 h);
// Draw a zero-terminated tile string at absolute tile coordinates, without
// window clipping, control codes or the windowed printing delay.
void text_print_xy(u8 x, u8 y, const u8* str);
// Print an unsigned byte in decimal using only the required number of cells.
void text_print_u8(u8 x, u8 y, u8 value);
// Print an unsigned word in decimal using only the required number of cells.
void text_print_u16(u8 x, u8 y, u16 value);
// Print a minus tile for negative values, followed by the unsigned magnitude.
// Positive values use the unsigned decimal path; no plus sign is emitted.
void text_print_s16(u8 x, u8 y, s16 value);
// Replace the active script and clear wait, choice and saved-return state.
void script_run(u8 bank, const u8* script);
// Execute commands until an output/choice yields (0), a wait yields (1), or
// execution ends (2). Control/flag commands continue within the same call, so
// a script loop without a yielding command can block the game loop indefinitely.
u8 script_step();
// Set the number of subsequent script_step calls to spend waiting. Frame-based
// timing requires the application to call script_step once per frame.
void script_wait_frames(u8 n);
// Run a blocking menu loop with wraparound up/down selection, A to accept
// and B to cancel. Return 0xFF for an empty menu or cancellation. Item strings
// and menu dimensions must fit the visible tile area.
u8 menu_run(const menu_t* menu);
// Open a two-choice dialog and return the text-choice result (YES first, NO second).
u8 menu_yesno();
// Run a blocking item menu, drawing names and two-digit quantities. Return
// the selected index or 0xFF on empty input/B; this does not consume an item.
u8 menu_inventory(const item_t* items, u8 count);
// Initialize a nonblocking menu state that borrows the item pointer table.
// Selection starts unset (0xFF), and the cancellation flag starts clear.
void menu_init_state(menu_state_t* state, u8 x, u8 y, u8 w, u8 h, const u8* const* items, u8 count);
// Draw the current menu and cursor without waiting or sampling input. The
// caller schedules suitable display timing and keeps item text within bounds.
void menu_draw(menu_state_t* state);
// Sample new button presses and update cursor/selection state without drawing.
// Selected and cancelled results remain latched; a B press in the same update
// as A clears selection and leaves cancellation set.
void menu_update(menu_state_t* state);
// Read the latched selection without clearing it; null state returns 0xFF.
u8 menu_get_selected(menu_state_t* state);
// Read the latched cancellation flag; null state returns false.
u8 menu_was_cancelled(menu_state_t* state);
// Load the nine-byte ordinary-map descriptor and draw up to 20 by 18 tiles
// from its top-left corner. Drawing does not upload tile graphics or clear
// background cells beyond smaller map dimensions.
void map_load(u8 bank, const map_t* map);
// Use metatile collision when that mode is active; otherwise read one packed
// collision bit. Missing maps/out-of-range cells block movement, but a valid
// ordinary map without a collision array is entirely passable.
u8 map_is_blocked(u8 x, u8 y);
// Report whether an event exists at the cell. Ordinary maps expose a Boolean
// byte-presence test; metatile maps reduce their event ID to a Boolean here.
u8 map_trigger_at(u8 x, u8 y);
// Center an ordinary-map tile coordinate within a 20-by-18 viewport and clamp
// the scroll origin to its edges. This adjusts scroll registers only; it does
// not stream newly exposed map rows into VRAM.
void camera_center(u8 x, u8 y);
// Select metatile mode, copy its descriptor and draw the initial viewport
// with the camera at cell (0,0).
void map_load_metatile(u8 bank, const metatile_map_t* map);
// Draw a 10-by-9 metatile viewport as 20-by-18 individual background tiles.
// Out-of-range cells use definition zero; palette attributes are not written.
// Remember the camera and clear the dirty flag after the full redraw.
void map_draw_visible(u8 camera_tx, u8 camera_ty);
// Read a row-major metatile ID, returning ID zero for inactive or out-of-range
// lookups. Callers must provide a usable definition for metatile zero.
u8 map_get_metatile(u8 tx, u8 ty);
// Return the selected definition's palette byte. An out-of-range coordinate
// uses the metatile-zero fallback; this function does not write CGB attributes.
u8 map_get_attr(u8 tx, u8 ty);
// Treat out-of-range metatile cells as solid; otherwise inspect the definition
// collision flag. In ordinary-map mode, delegate to its packed collision bits.
u8 map_is_solid(u8 tx, u8 ty);
// Return a metatile event ID, or the ordinary-map Boolean trigger result.
// Missing/out-of-range metatile cells have no event.
u8 map_get_event(u8 tx, u8 ty);
// Mark the viewport for a full redraw when a valid metatile cell changes.
// The coordinate is validated but no per-cell dirty list is retained.
void map_mark_dirty(u8 tx, u8 ty);
// Redraw the remembered metatile viewport only when the shared dirty flag is set.
void map_flush_dirty();
// Validate slot and payload length, write payload bytes, then write the header
// and checksum. Return one after completing the writes; interruption can leave
// a partially replaced slot, so this is not transactional save storage.
u8 save_write(u8 slot, const void* data, u16 len);
// Require matching magic/version, exact requested length and a valid checksum
// before copying data into the destination. Validation failure leaves the
// destination unchanged. An invalid slot returns before touching RAM control;
// validation failures after enabling RAM disable it before returning zero.
u8 save_read(u8 slot, void* data, u16 len);
// Validate a slot's header, payload bounds and checksum without copying the
// payload out. A nonzero result means the stored record passes these checks.
u8 save_exists(u8 slot);
// Initialize the expected RAM access state and leave cartridge RAM disabled.
// Existing slot contents are preserved.
void save_init();
// Alias the checked save_read operation.
u8 save_load(u8 slot, void* data, u16 len);
// Alias save_exists, including its header and checksum validation.
u8 save_check(u8 slot);
// Zero the complete selected slot, including header and payload; invalid slot
// IDs are ignored. Cartridge RAM is disabled when clearing finishes.
void save_clear(u8 slot);
// Build movement costs, then convert reachable cells to one and unreachable
// 0xFF cells to zero. The caller provides one output byte per current-map cell
// and a valid unit origin; path-search workspace limits also apply.
u8 unit_move_range(unit_t* u, u8* out_mask);
// Mark cells whose Manhattan distance falls within the inclusive attack range.
// This geometric mask does not test obstacles, line of sight or other units.
u8 unit_attack_range(unit_t* u, u8* out_mask);
// A unit can act only while HP is nonzero and its acted flag is clear.
// The unit pointer must refer to a valid record.
u8 unit_can_act(const unit_t* u);
// Find a shortest cardinal path with BFS and write direction codes 0=up,
// 1=right, 2=down, 3=left. Return its byte length, or zero for failure or an
// already-reached goal. The caller supplies max_len output bytes and respects
// the shared workspace/distance limits; excessive paths are not truncated.
u8 path_find_bfs(u8 sx, u8 sy, u8 gx, u8 gy, u8* out_path, u8 max_len);
// Flood cardinal neighbors at unit cost, stopping expansion at the movement
// limit and rejecting blocked destinations. Initialize output to 0xFF only
// after validating the map and origin; invalid input leaves output unchanged.
void range_fill_move(u8 sx, u8 sy, u8 move, u8* out_costmap);
// Read a bit from the flag array. Callers must keep id below 2048.
u8 flag_get(u16 id);
// Set a flag bit without disturbing adjacent flags; id must be below 2048.
void flag_set(u16 id);
// Clear a flag bit; id must be below 2048.
void flag_clear(u16 id);
// Read a quest-state byte; quest_id must be below 64.
u8 quest_state(u8 quest_id);
// Replace a quest-state byte without validating its game-specific meaning.
// The caller must keep quest_id below 64.
void quest_set_state(u8 quest_id, u8 state);
// Expand count/value byte pairs until a zero count terminates the stream.
// The caller must provide a valid terminator and sufficient destination storage;
// there are no source or destination bounds parameters. Return the 16-bit byte count.
u16 rle_decode(void* dst, const void* src);
// Decode the same count/value format using bank-qualified reads for every source
// byte. Keep the encoded stream within the supplied bank/address mapping and
// provide enough destination space; a zero count ends the stream.
u16 rle_decode_far(void* dst, u8 bank, const void* src);
// Return the active map width in its own cell units, or zero when no map is loaded.
u8 map_current_width();
// Return the active map height in its own cell units, or zero when no map is loaded.
u8 map_current_height();kitaqgb/lib/rpg.h
scene.h — Enregistrement, changement et mise à jour des scènes
#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 — Arrière-plan, fenêtre et défilement fractionné
#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 — Plateaux, listes de coups et annulation
#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 — Allocation d'OBJ, placement, métasprites et 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 — Sélection des sprites par priorité et 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 — Démarrage, compteurs d'images, attentes et interruptions
#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 — Mises à jour et transferts VRAM en file
#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 — Rendu filaire pour 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 — Rendu filaire couleur pour 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 — Rendu filaire pour 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







