KITAQ SERIES • ÉDITION DE RÉFÉRENCE
BIBLIOTHÈQUE KITAQFC
Bibliothèques et périphériques NES
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.
kitaqfc · 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 fc_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
.\kitaqfc\kitaqfc.exe kitaq-docs/samples/fc_font.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_font.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Display the letters, digits and punctuation from the supplied ascii.c font.
// Expected: Uppercase, lowercase, numbers and all 30 supplied punctuation glyphs
#include "fc_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(void) {
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 fc_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
.\kitaqfc\kitaqfc.exe kitaq-docs/samples/fc_hello.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_hello.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Display a first message on screen.
// Expected: HELLO WORLD and 042
#include "fc_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(void) {
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 fc_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
.\kitaqfc\kitaqfc.exe kitaq-docs/samples/fc_arithmetic.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_arithmetic.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Variables, arithmetic and type conversion.
// Expected: 030
#include "fc_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(void) {
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 fc_control.c
Objectif : Essaie for, continue, while et if/else dans un petit calcul.
Fonctionnement : La boucle for additionne les valeurs de 0 à 7 en sautant 3, ce qui donne 25. La boucle while avance jusqu’à 32 ; le if suivant affecte 42 lorsque cette valeur est atteinte.
Commandes et résultat attendu : 042 est le résultat final. Ce programme utilise un branchement if/else.

Télécharger le source / État de la vérification
.\kitaqfc\kitaqfc.exe kitaq-docs/samples/fc_control.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_control.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Conditional branches and loops.
// Expected: 042
#include "fc_common.h"
// Exercise loop control and a final branch, then display the selected value 42.
void main(void) {
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<32) { sum++; }
if (sum==32) sum=42; else sum=0;
m_number(sum);
while (1) { m_wait(); }
}Fonctions, tableaux, structures et pointeurs fc_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/fc_aggregate.png)
Télécharger le source / État de la vérification
.\kitaqfc\kitaqfc.exe kitaq-docs/samples/fc_aggregate.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_aggregate.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Functions, arrays, structures and pointers.
// Expected: 042
#include "fc_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(void) {
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 fc_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
.\kitaqfc\kitaqfc.exe kitaq-docs/samples/fc_bits_memory.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_bits_memory.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Bit operations and memory copying.
// Expected: 010
#include "fc_common.h"
// Clear the source bytes, set bits 3 and 1, copy the buffer, and display 8 + 2 = 10.
void main(void) {
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 fc_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
.\kitaqfc\kitaqfc.exe kitaqfc/lib/input.c kitaq-docs/samples/fc_input.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_input.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Distinguish a new button press from a held button.
// Expected: 000 initially; A increments once per press
#include "fc_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(void) {
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 fc_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
.\kitaqfc\kitaqfc.exe kitaqfc/lib/fixed.c kitaq-docs/samples/fc_fixed.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_fixed.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Calculate with signed Q8.8 fixed-point values.
// Expected: 012
#include "fc_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(void) {
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 fc_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
.\kitaqfc\kitaqfc.exe kitaqfc/lib/entity.c kitaq-docs/samples/fc_entity.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_entity.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Allocate an entity from a fixed-capacity object pool.
// Expected: 001
#include "fc_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(void) {
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 fc_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
.\kitaqfc\kitaqfc.exe kitaqfc/lib/debug.c kitaq-docs/samples/fc_debug.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_debug.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Record diagnostic values in the debug trace.
// Expected: 001; trace log contains HP=42
#include "fc_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(void) {
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 fc_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
.\kitaqfc\kitaqfc.exe kitaqfc/lib/chain.c kitaq-docs/samples/fc_chain.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_chain.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Store a position history in a ring buffer.
// Expected: 042; history contains (20,30)
#include "fc_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(void) {
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 fc_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
.\kitaqfc\kitaqfc.exe kitaqfc/lib/system.c kitaq-docs/samples/fc_system.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_system.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Count completed frame waits.
// Expected: 002
#include "fc_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(void) {
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 fc_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
.\kitaqfc\kitaqfc.exe kitaqfc/lib/runtime.c kitaqfc/lib/scene.c kitaq-docs/samples/fc_scene.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_scene.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// The scene streaming module shares runtime.c queue symbols, even though this demo only changes IDs.
#define MANUAL_FC_RUNTIME 1
// Switch the current scene ID.
// Expected: 001; no callbacks registered
#include "fc_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(void) {
m_init();
m_text(2,3,"SCENE");
scene_init(manual_scenes,2); scene_change(1);
m_number(scene_get_current());
while (1) { m_wait(); }
}Cumuler un déplacement fractionnaire Q5.3 fc_subpixel.c
Objectif : Conserve le déplacement inférieur au pixel sous forme de reste et reporte les pixels entiers dans la position.
Fonctionnement : À partir de X=40, la boucle ajoute huit fois 2/8 de pixel. Un décalage à droite extrait les pixels entiers ; un masque conserve le reste.
Commandes et résultat attendu : le déplacement total est de deux pixels, donc X=42 s’affiche sous la forme 042. Cet exemple d’intégration manuelle traite les déplacements positifs ; les négatifs nécessitent une gestion correspondante de l’emprunt.

Télécharger le source / État de la vérification
.\kitaqfc\kitaqfc.exe kitaq-docs/samples/fc_subpixel.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_subpixel.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Accumulate Q5.3 eighth-pixel motion into an integer coordinate.
// Expected: 042; explicit game-side integration using header constants
#include "fc_common.h"
#include "physics2d.h"
// Integrate eight increments of 2/8 pixel. Carry whole pixels into X and
// retain the fractional remainder with the supplied mask, moving X from 40 to 42.
void main(void) {
m_init();
m_text(2,3,"SUBPIXEL");
KQ2DPosition x; KQ2DFraction frac; KQ2DSpeed speed; u8 i;
// This example demonstrates positive motion only; signed negative motion needs a matching carry/borrow path.
x=40; frac=0; speed=2;
for(i=0;i<8;i++) {
frac=(u8)(frac+speed);
x=(u8)(x+(frac>>KQ2D_SUBPIXEL_BITS));
frac=(u8)(frac & KQ2D_SUBPIXEL_MASK);
}
m_number(x);
while (1) { m_wait(); }
}Faire défiler le fond NES fc_scroll.c
Objectif : Déplace le fond en modifiant la position de défilement du PPU.
Fonctionnement : À partir de __scroll_set(0,0), le programme incrémente phase une fois par image et l’utilise comme position horizontale.
Commandes et résultat attendu : Le mot SCROLL change de position horizontale. phase revient de 255 à 0. Ce n’est pas un exemple de grande carte couvrant plusieurs tables de noms.

Télécharger le source / État de la vérification
.\kitaqfc\kitaqfc.exe kitaq-docs/samples/fc_scroll.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_scroll.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Scroll the NES background horizontally.
// Expected: title scrolls horizontally
#include "fc_common.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(void) {
m_init();
m_text(2,3,"SCROLL");
__scroll_set(0,0);
while (1) { m_wait(); phase++; __scroll_set(phase,0); }
}Appliquer une mise à jour de tuile par NMI fc_vram_queue.c
Objectif : Soumet une mise à jour PPU depuis le programme principal pour que le traitement NMI l’applique.
Fonctionnement : __vramq_put met en file la tuile 52 à l’adresse de table de noms 0x2103, puis __vramq_commit la soumet. Cette adresse correspond à la coordonnée de tuile (3,8).
Commandes et résultat attendu : Un seul 4 apparaît à la coordonnée du fond (3,8). La tuile 52 est le chiffre 4 dans la police fournie.

Télécharger le source / État de la vérification
.\kitaqfc\kitaqfc.exe kitaq-docs/samples/fc_vram_queue.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_vram_queue.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Submit a VRAM update for the NMI handler.
// Expected: 4 at (3,8)
#include "fc_common.h"
// Queue tile 52 at nametable address 0x2103, corresponding to (3,8), and
// commit the queue so the NMI update path displays the digit 4.
void main(void) {
m_init();
m_text(2,3,"VRAM QUEUE");
__vramq_put(0x2103,52); __vramq_commit();
while (1) { m_wait(); }
}Afficher un sprite OAM NES fc_sprite.c
Objectif : Prépare les couleurs des sprites et les données OAM pour dessiner une image indépendamment du fond.
Fonctionnement : Le programme charge la palette des sprites, règle l’entrée 0 sur la position (70,80), la tuile 65 et les attributs 0, active le rendu et répète le DMA OAM.
Commandes et résultat attendu : Une lettre A immobile apparaît comme sprite. L’exemple montre la configuration et le transfert OAM, pas une animation.

Télécharger le source / État de la vérification
.\kitaqfc\kitaqfc.exe kitaq-docs/samples/fc_sprite.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_sprite.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Display a sprite using NES OAM.
// Expected: A sprite on screen
#include "fc_common.h"
// Load the sprite palette, assign font tile 65 to OAM slot zero, enable
// background/sprite display, and transfer OAM after each frame wait.
void main(void) {
m_init();
m_text(2,3,"SPRITE");
__palette_sp_load(manual_pal); __sprite_set(0,70,80,65,0);
__ppu_mask_set(0x1E);
while (1) { m_wait(); __oam_dma(); }
}Jouer un son pulsé avec l’APU fc_sound.c
Objectif : Règle les valeurs de contrôle, de temporisation et de longueur du canal pulsé intégré de la NES.
Fonctionnement : Après nes_apu_init, le programme appelle nes_sfx_square1(0xBF,400,20). Le contrôle 0xBF choisit un volume constant et arrête le compteur de longueur ; le son se prolonge donc. 20 est un indice de table de longueurs, pas une durée de 20 images.
Commandes et résultat attendu : Un son pulsé soutenu joue pendant l’affichage de 042. Appelez nes_apu_silence_all pour l’arrêter. Le repère affiché seul ne vérifie pas la sortie sonore.

Télécharger le source / État de la vérification
.\kitaqfc\kitaqfc.exe kitaqfc/lib/audio.c kitaq-docs/samples/fc_sound.c -I kitaqfc/lib -I kitaq-docs/samples -o out/fc_sound.nes --mapper=nrom --nes-chr=kitaq-docs/samples/font.chr// Play a pulse-channel effect on the built-in NES APU.
// Expected: 042 and a pulse tone
#include "fc_common.h"
#include "audio.h"
// Initialize the APU, trigger pulse channel 1 with the chosen timer/length
// values, and leave the screen displaying 42 while the hardware plays the tone.
void main(void) {
m_init();
m_text(2,3,"SOUND");
// Control BF selects constant volume and halts the length counter, so this tone sustains.
// Call nes_apu_silence_all when the game should stop it; 20 is a length-table index, not frames.
nes_apu_init(); nes_sfx_square1(0xBF,400,20);
m_number(42);
while (1) { m_wait(); }
}Dictionnaire de l'API de bibliothèque
294 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.
actor.h — Tableaux d'acteurs du jeu
NesActor regroupe position dans le monde, position à l’écran et taille du rectangle. Les fonctions auxiliaires projettent via la caméra, écrivent les métasprites en OAM et testent les chevauchements dans le monde. Le jeu gère vitesse, élimination hors écran et DMA OAM.
nes_actor_collide
Teste le chevauchement des rectangles d’acteurs alignés sur les axes dans les coordonnées du monde.
Syntaxe
unsigned char nes_actor_collide(struct NesActor* a, struct NesActor* b);Paramètres
aPremier acteur.
bSecond acteur.
Valeur renvoyée
Renvoie 1 en cas de chevauchement, 0 si les rectangles sont séparés ou si leurs bords se touchent seulement.
Conditions et limites
Utilisez des largeurs et hauteurs positives et gardez position+taille≤65535. Les coordonnées d’écran, attr et flags sont ignorés.
Exemple d’utilisation
result[3]=nes_actor_collide(&a,&b);nes_actor_set_world(&b,315,95);result[4]=nes_actor_collide(&a,&b);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Projetez (300,95) du monde via la caméra (268,32) : les parties rouges et bleues de 8×8 apparaissent en (32,64) et (40,64). Cela montre que le Y OAM brut 63 apparaît à 64, et que la collision passe de zéro pour des bords jointifs à un pour un chevauchement d’un pixel.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_actor.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_actor.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/actor.h:29
Test overlap in world coordinates with exclusive right/bottom edges. Keep position-plus-size sums within u16; touching edges are not collisions. Require positive widths and heights; zero extents are not rejected before the edge tests.
kitaqfc/lib/actor.c:49
unsigned char nes_actor_collide(struct NesActor* a, struct NesActor* b)
{
unsigned short a_right;
unsigned short b_right;
unsigned short a_bottom;
unsigned short b_bottom;
a_right = (unsigned short)(a->world_x + a->width);
b_right = (unsigned short)(b->world_x + b->width);
a_bottom = (unsigned short)(a->world_y + a->height);
b_bottom = (unsigned short)(b->world_y + b->height);
if (a_right <= b->world_x)
{
return 0;
}
if (b_right <= a->world_x)
{
return 0;
}
if (a_bottom <= b->world_y)
{
return 0;
}
if (b_bottom <= a->world_y)
{
return 0;
}
return 1;
}nes_actor_draw_metasprite
Écrit un métasprite dans le miroir OAM à l’aide des coordonnées d’écran mises en cache de l’acteur.
Syntaxe
unsigned char nes_actor_draw_metasprite(struct NesActor* actor, unsigned char oam_index, unsigned char* metasprite);Paramètres
actorPointeur vers un NesActor accessible en écriture.
oam_indexPremier emplacement, de 0 à 63 ; réservez de la place pour toutes les parties.
metaspriteEnregistrements de quatre octets dx,dy,tile,attr ; dx=255 termine la liste.
Valeur renvoyée
Renvoie l’indice du prochain emplacement OAM, avec rebouclage après les 64 emplacements.
Conditions et limites
Liez runtime.c. La file copie les données pour une NMI ultérieure ou une application sûre avec le rendu désactivé. Sérialisez la production et la consommation. Si une opération multiligne manque de place, les lignes déjà acceptées restent en file.
N’applique pas les champs attr/flags de l’acteur. Y est un octet OAM brut : le haut visible est donc un pixel plus bas. Un DMA OAM est nécessaire pour afficher le miroir.
Exemple d’utilisation
result[5]=nes_actor_draw_metasprite(&a,0,parts);result[6]=nes_oam_shadow[3];result[7]=nes_oam_shadow[7];nes_oam_dma(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
Projetez (300,95) du monde via la caméra (268,32) : les parties rouges et bleues de 8×8 apparaissent en (32,64) et (40,64). Cela montre que le Y OAM brut 63 apparaît à 64, et que la collision passe de zéro pour des bords jointifs à un pour un chevauchement d’un pixel.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_actor.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_actor.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/actor.h:25
Draw the byte-stream metasprite at cached screen coordinates and return its next OAM index. Actor attr/flags are not applied by this wrapper.
kitaqfc/lib/actor.c:41
unsigned char nes_actor_draw_metasprite(struct NesActor* actor, unsigned char oam_index, unsigned char* metasprite)
{
return nes_metasprite_draw(oam_index, actor->screen_x, actor->screen_y, metasprite);
}nes_actor_set_world
Définit le X/Y d’un acteur dans le monde.
Syntaxe
void nes_actor_set_world(struct NesActor* actor, unsigned short x, unsigned short y);Paramètres
actorPointeur vers un NesActor accessible en écriture.
xX du monde, de 0 à 65535 pixels.
yY du monde, de 0 à 65535 pixels.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Ne met pas screen_x/screen_y à jour. Appelez update_screen pour projeter la position à travers la caméra.
Exemple d’utilisation
nes_actor_set_world(&a,300,95);nes_actor_set_world(&b,316,95);result[0]=a.world_x;Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Projetez (300,95) du monde via la caméra (268,32) : les parties rouges et bleues de 8×8 apparaissent en (32,64) et (40,64). Cela montre que le Y OAM brut 63 apparaît à 64, et que la collision passe de zéro pour des bords jointifs à un pour un chevauchement d’un pixel.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_actor.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_actor.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/actor.h:19
Set the actor's 16-bit world position without updating cached screen coordinates.
kitaqfc/lib/actor.c:19
void nes_actor_set_world(struct NesActor* actor, unsigned short x, unsigned short y)
{
actor->world_x = x;
actor->world_y = y;
}nes_actor_update_screen
Soustrait les coordonnées de la caméra à celles du monde et met en cache les octets faibles comme coordonnées d’écran.
Syntaxe
void nes_actor_update_screen(struct NesActor* actor, unsigned short camera_x, unsigned short camera_y);Paramètres
actorPointeur vers un NesActor accessible en écriture.
camera_xX de la caméra dans le monde.
camera_yY de la caméra dans le monde.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Les résultats négatifs ou ≥256 rebouclent. Les acteurs hors écran ne sont pas masqués ; le jeu doit les écarter avant le dessin.
Exemple d’utilisation
nes_actor_update_screen(&a,268,32);result[1]=a.screen_x;result[2]=a.screen_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
Projetez (300,95) du monde via la caméra (268,32) : les parties rouges et bleues de 8×8 apparaissent en (32,64) et (40,64). Cela montre que le Y OAM brut 63 apparaît à 64, et que la collision passe de zéro pour des bords jointifs à un pour un chevauchement d’un pixel.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_actor.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_actor.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/actor.h:22
Subtract the camera and retain only the low coordinate bytes. This performs wrapping projection, not clipping; callers must hide actors outside the viewport.
kitaqfc/lib/actor.c:27
void nes_actor_update_screen(struct NesActor* actor, unsigned short camera_x, unsigned short camera_y)
{
unsigned short dx;
unsigned short dy;
dx = (unsigned short)(actor->world_x - camera_x);
dy = (unsigned short)(actor->world_y - camera_y);
actor->screen_x = (unsigned char)dx;
actor->screen_y = (unsigned char)dy;
}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, sélectionne sa banque ROM et transfère toutes les données avec __vram_write, par blocs de 128 octets au maximum. Elle rétablit ensuite la banque mémorisée par bank_get_current(). Le découpage n’attend pas l’image suivante.
Utilisez de la CHR RAM accessible en écriture et désactivez le rendu pour les longs transferts. Pendant VBlank, toute l’opération doit tenir dans le temps disponible ; les blocs de 128 octets ne le garantissent pas. L’exemple utilise --mapper=mmc1 --board=surom512. Sur les cartes génériques, omettre --nes-chr produit une CHR ROM vide, pas de la CHR RAM.
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 FC, la paire bleue en (16,64) montre __far_memcpy ; la verte en (16,96), asset_load_raw suivi d’un transfert en CHR. Chaque paire occupe 16×8 pixels sur fond noir. Ces rangées montrent les données graphiques copiées, pas seulement des valeurs d’état numériques.
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\asset_banks.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\asset_banks.nes --mapper=mmc1 --board=surom512 --no-cache --no-disasmImplémentation et source
kitaqfc/lib/asset.h:25
Copy a descriptor from its ROM bank into caller storage. Null output or an out-of-range ID returns zero without reading the table.
kitaqfc/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;
__far_memcpy((u8*)out_desc, asset_table_bank, (u16)(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 FC, la paire bleue en (16,64) montre __far_memcpy ; la verte en (16,96), asset_load_raw suivi d’un transfert en CHR. Chaque paire occupe 16×8 pixels sur fond noir. Ces rangées montrent les données graphiques copiées, pas seulement des valeurs d’état numériques.
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\asset_banks.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\asset_banks.nes --mapper=mmc1 --board=surom512 --no-cache --no-disasmImplémentation et source
kitaqfc/lib/asset.h:33
Return the asset bank or zero on lookup failure; bank zero may also be valid.
kitaqfc/lib/asset.c:74
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 FC, la paire bleue en (16,64) montre __far_memcpy ; la verte en (16,96), asset_load_raw suivi d’un transfert en CHR. Chaque paire occupe 16×8 pixels sur fond noir. Ces rangées montrent les données graphiques copiées, pas seulement des valeurs d’état numériques.
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\asset_banks.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\asset_banks.nes --mapper=mmc1 --board=surom512 --no-cache --no-disasmImplémentation et source
kitaqfc/lib/asset.h:38
Return the descriptor byte length, or zero for an invalid ID.
kitaqfc/lib/asset.c:91
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 FC, la paire bleue en (16,64) montre __far_memcpy ; la verte en (16,96), asset_load_raw suivi d’un transfert en CHR. Chaque paire occupe 16×8 pixels sur fond noir. Ces rangées montrent les données graphiques copiées, pas seulement des valeurs d’état numériques.
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\asset_banks.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\asset_banks.nes --mapper=mmc1 --board=surom512 --no-cache --no-disasmImplémentation et source
kitaqfc/lib/asset.h:36
Return the stored address without switching banks. Pair it with the descriptor bank before reading banked ROM; a failed lookup returns null.
kitaqfc/lib/asset.c:83
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 FC, la paire bleue en (16,64) montre __far_memcpy ; la verte en (16,96), asset_load_raw suivi d’un transfert en CHR. Chaque paire occupe 16×8 pixels sur fond noir. Ces rangées montrent les données graphiques copiées, pas seulement des valeurs d’état numériques.
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\asset_banks.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\asset_banks.nes --mapper=mmc1 --board=surom512 --no-cache --no-disasmImplémentation et source
kitaqfc/lib/asset.h:28
Copy the smaller of the asset length and max_len using a bank-aware transfer. Return one for a valid ID even when the payload is truncated.
kitaqfc/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;
__far_memcpy((u8*)dst, desc.bank, (u16)desc.ptr, len);
return 1;
}asset_load_tiles
Recherche une ressource RAW ou TILES, sélectionne sa banque ROM et transfère toutes les données avec __vram_write, par blocs de 128 octets au maximum. Elle rétablit ensuite la banque mémorisée par bank_get_current(). Le découpage n’attend pas l’image suivante.
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 du PPU, et non adresse CPU ou numéro de tuile. Les motifs sont chargés en CHR RAM accessible en écriture, entre
$0000et$1FFF, à raison de 16 octets par tuile. Le transfert doit rester dans la zone PPU prévue.
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.
asset_load_tiles rétablit la banque suivie par bank.c, sans relire le mapper. Initialisez et maintenez cet état avec bank_switch ; les écritures directes et les appels isolés à __bankswitch ne mettent pas à jour la bibliothèque. La copie intrinsèque rétablit séparément l’état du compilateur.
Utilisez de la CHR RAM accessible en écriture et désactivez le rendu pour les longs transferts. Pendant VBlank, toute l’opération doit tenir dans le temps disponible ; les blocs de 128 octets ne le garantissent pas. L’exemple utilise --mapper=mmc1 --board=surom512. Sur les cartes génériques, omettre --nes-chr produit une CHR ROM vide, pas de la CHR RAM.
Exemple d’utilisation
loaded=asset_load_tiles(0,0x0010); // 144 bytes: library uploads chunks of 128 and 16 bytes.
expect(loaded==1 && bank_get_current()==1 && *asset_bank_marker==0xA1,24);
// LCD and NMI are off; CHR RAM is writable. The library selects payload bank 2 and restores bank 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 FC, la paire bleue en (16,64) montre __far_memcpy ; la verte en (16,96), asset_load_raw suivi d’un transfert en CHR. Chaque paire occupe 16×8 pixels sur fond noir. Ces rangées montrent les données graphiques copiées, pas seulement des valeurs d’état numériques.
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\asset_banks.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\asset_banks.nes --mapper=mmc1 --board=surom512 --no-cache --no-disasmImplémentation et source
kitaqfc/lib/asset.h:31
Switch to the asset bank, upload tile/raw data in chunks of at most 128 bytes, then restore the bank recorded by this library. The caller supplies safe PPU timing.
kitaqfc/lib/asset.c:41
u8 asset_load_tiles(u8 asset_id, u16 vram_dst)
{
AssetDesc desc;
const u8* src;
u16 len;
u8 chunk;
u8 old_bank;
if (asset_get(asset_id, &desc) == 0) return 0;
if (desc.type != ASSET_TYPE_TILES && desc.type != ASSET_TYPE_RAW) return 0;
// Restoration uses the library shadow, not a mapper readback; initialize and maintain that shadow.
old_bank = bank_get_current();
bank_switch(desc.bank);
src = desc.ptr;
len = desc.len;
// This loop uploads the entire asset synchronously. Chunking does not wait for another frame.
// Use writable CHR RAM for tile data and keep the source bank visible throughout the transfer.
while (len != 0) {
if (len > 128) chunk = 128;
else chunk = (u8)len;
__vram_write(vram_dst, src, chunk);
vram_dst = (u16)(vram_dst + chunk);
src = src + chunk;
len = (u16)(len - chunk);
}
bank_switch(old_bank);
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 FC, la paire bleue en (16,64) montre __far_memcpy ; la verte en (16,96), asset_load_raw suivi d’un transfert en CHR. Chaque paire occupe 16×8 pixels sur fond noir. Ces rangées montrent les données graphiques copiées, pas seulement des valeurs d’état numériques.
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\asset_banks.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\asset_banks.nes --mapper=mmc1 --board=surom512 --no-cache --no-disasmImplémentation et source
kitaqfc/lib/asset.h:22
Retain a bank-qualified descriptor table; the caller keeps its storage valid.
kitaqfc/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;
}attribute.h — Attributs des tables de noms
Le miroir d’attributs partagé de 64 octets occupe la RAM CPU $03E0..$041F ; réservez cette zone. Un octet d’attribut couvre 4×4 tuiles ; chaque champ de deux bits choisit la palette d’un quadrant de 2×2 tuiles.
Modifie les quadrants de palette par rectangle et ne met en file que les octets d’attributs concernés, avec vérification des limites de 32×30 tuiles. L’entrée palette_map est une table d’attributs complète de 64 octets, pas une couleur par tuile.
nes_attr_queue_rect
Copie dans la file les lignes d’octets d’attributs couvrant un rectangle de tuiles.
Syntaxe
unsigned char nes_attr_queue_rect(unsigned short nt_base, unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height);Paramètres
nt_baseBase logique de table de noms $2000/$2400/$2800/$2C00 ; le miroir détermine leur indépendance physique.
tile_xColonne de tuile gauche, plage visible de 0 à 31.
tile_yLigne de tuile supérieure, plage visible de 0 à 29.
widthLargeur en tuiles.
heightHauteur en tuiles.
Valeur renvoyée
Renvoie 1 si tout est accepté ou si le rectangle est vide, 0 si les limites sont invalides ou la capacité insuffisante. Des limites invalides ne mettent rien en file.
Conditions et limites
Le miroir d’attributs partagé de 64 octets occupe la RAM CPU $03E0..$041F ; réservez cette zone. Un octet d’attribut couvre 4×4 tuiles ; chaque champ de deux bits choisit la palette d’un quadrant de 2×2 tuiles.
Liez runtime.c. La file copie les données pour une NMI ultérieure ou une application sûre avec le rendu désactivé. Sérialisez la production et la consommation. Si une opération multiligne manque de place, les lignes déjà acceptées restent en file.
Un octet d’attribut couvre 4×4 tuiles. Les octets qui intersectent la zone sont transférés en entier ; conservez donc les bonnes valeurs des quadrants voisins dans le miroir.
Exemple d’utilisation
result[5]=nes_attr_queue_rect(0x2000,2,4,4,4);result[6]=nes_vram_queue_used;result[7]=nes_attr_queue_rect(0x2000,10,4,4,4);result[8]=nes_attr_queue_rect(0x2000,30,28,2,2);nes_vram_queue_nmi_flush();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Découvrez les transferts d’attributs rectangulaires : rouge 32×32 en (16,32), bleu 32×32 en (80,32), vert 16×16 en bas à droite (240,224). L’exemple préserve les quadrants voisins et atteint correctement le dernier octet d’attributs.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_attributes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_attributes.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/attribute.h:15
Queue the attribute bytes covering a tile rectangle within 32x30 tiles. Empty rectangles succeed; invalid bounds fail without queuing. Capacity failure may leave earlier rows queued.
kitaqfc/lib/attribute.c:81
unsigned char nes_attr_queue_rect(unsigned short nt_base, unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height)
{
unsigned char qx0;
unsigned char qy0;
unsigned char qx1;
unsigned char qy1;
unsigned char row;
unsigned char col;
// The runtime queue copies these local bytes before return; they are not retained pointers.
// Caller coordinates must keep each computed row length within eight bytes.
unsigned char line[8];
unsigned short ppu_addr;
unsigned char len;
if (width == 0 || height == 0) return 1;
if (tile_x >= 32 || tile_y >= 30) return 0;
if (width > (unsigned char)(32 - tile_x) || height > (unsigned char)(30 - tile_y)) return 0;
qx0 = (unsigned char)(tile_x >> 2);
qy0 = (unsigned char)(tile_y >> 2);
qx1 = (unsigned char)((tile_x + width - 1) >> 2);
qy1 = (unsigned char)((tile_y + height - 1) >> 2);
row = qy0;
while (1)
{
len = (unsigned char)(qx1 - qx0 + 1);
col = 0;
while (col != len)
{
line[col] = nes_attr_shadow[(unsigned char)(row * 8 + qx0 + col)];
col = (unsigned char)(col + 1);
}
ppu_addr = (unsigned short)(nes_attr_base_from_nt(nt_base) + (unsigned short)(row * 8 + qx0));
if (nes_vram_queue_try_write(ppu_addr, line, len) == 0)
{
return 0;
}
if (row == qy1)
{
break;
}
row = (unsigned char)(row + 1);
}
return 1;
}nes_attr_shadow_build_from_palette_map
Copie 64 octets d’attributs déjà compactés dans le miroir partagé.
Syntaxe
void nes_attr_shadow_build_from_palette_map(unsigned char* src64);Paramètres
src64Table d’attributs compactée de 64 octets lisibles, et non tableau d’identifiants de palette par tuile.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Le miroir d’attributs partagé de 64 octets occupe la RAM CPU $03E0..$041F ; réservez cette zone. Un octet d’attribut couvre 4×4 tuiles ; chaque champ de deux bits choisit la palette d’un quadrant de 2×2 tuiles.
Exemple d’utilisation
for(i=0;i<64;i++)table[i]=0;table[0]=0xE4;nes_attr_shadow_build_from_palette_map(table);result[0]=nes_attr_shadow[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
Découvrez les transferts d’attributs rectangulaires : rouge 32×32 en (16,32), bleu 32×32 en (80,32), vert 16×16 en bas à droite (240,224). L’exemple préserve les quadrants voisins et atteint correctement le dernier octet d’attributs.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_attributes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_attributes.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/attribute.h:8
KITAQFC phase15 attribute patch helpers. Copy 64 already-packed attribute bytes into shadow storage. This does not convert one palette ID per tile into NES attribute bitfields. The source must expose all 64 packed bytes and stay readable for the duration of this copy.
kitaqfc/lib/attribute.c:26
void nes_attr_shadow_build_from_palette_map(unsigned char* src64)
{
unsigned char i;
i = 0;
while (i != 64)
{
nes_attr_shadow[i] = (unsigned char)(src64[i] & 0xFF);
i = (unsigned char)(i + 1);
}
}nes_attr_shadow_fill_rect
Remplace les champs de palette de chaque quadrant de 2×2 tuiles touché par un rectangle.
Syntaxe
void nes_attr_shadow_fill_rect(unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height, unsigned char pal_index);Paramètres
tile_xColonne de tuile gauche, plage visible de 0 à 31.
tile_yLigne de tuile supérieure, plage visible de 0 à 29.
widthLargeur en tuiles.
heightHauteur en tuiles.
pal_indexIndice de palette ; seuls les deux bits de poids faible sont utilisés.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Le miroir d’attributs partagé de 64 octets occupe la RAM CPU $03E0..$041F ; réservez cette zone. Un octet d’attribut couvre 4×4 tuiles ; chaque champ de deux bits choisit la palette d’un quadrant de 2×2 tuiles.
Gardez tout le rectangle dans les 32×30 tuiles. Les rectangles vides ou invalides ne changent rien. Les limites impaires sont étendues aux limites des quadrants ; des tuiles voisines extérieures au rectangle peuvent donc recevoir la nouvelle palette.
Exemple d’utilisation
nes_attr_shadow_fill_rect(2,4,4,4,1);nes_attr_shadow_fill_rect(10,4,4,4,2);nes_attr_shadow_fill_rect(30,28,2,2,3);result[1]=nes_attr_shadow[8];result[2]=nes_attr_shadow[9];result[3]=nes_attr_shadow[15];result[4]=nes_attr_shadow[63];Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Découvrez les transferts d’attributs rectangulaires : rouge 32×32 en (16,32), bleu 32×32 en (80,32), vert 16×16 en bas à droite (240,224). L’exemple préserve les quadrants voisins et atteint correctement le dernier octet d’attributs.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_attributes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_attributes.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/attribute.h:11
Apply a palette to every two-by-two tile quadrant touched by the rectangle. Empty or out-of-range rectangles leave the shadow unchanged.
kitaqfc/lib/attribute.c:39
void nes_attr_shadow_fill_rect(unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height, unsigned char pal_index)
{
unsigned char qx0;
unsigned char qy0;
unsigned char qx1;
unsigned char qy1;
unsigned char qx;
unsigned char qy;
if (width == 0 || height == 0) return;
if (tile_x >= 32 || tile_y >= 30) return;
if (width > (unsigned char)(32 - tile_x) || height > (unsigned char)(30 - tile_y)) return;
qx0 = nes_attr_rect_left(tile_x);
qy0 = nes_attr_rect_top(tile_y);
qx1 = nes_attr_rect_left((unsigned char)(tile_x + width - 1));
qy1 = nes_attr_rect_top((unsigned char)(tile_y + height - 1));
qy = qy0;
while (1)
{
qx = qx0;
while (1)
{
nes_attr_shadow_set_quad((unsigned char)(qx << 1), (unsigned char)(qy << 1), pal_index);
if (qx == qx1)
{
break;
}
qx = (unsigned char)(qx + 1);
}
if (qy == qy1)
{
break;
}
qy = (unsigned char)(qy + 1);
}
}audio.h — Musique, effets sonores et commandes audio
Contrôle directement les deux impulsions, le triangle, le bruit et le DMC de l’APU standard. Ce n’est ni un séquenceur musical ni un mélangeur automatique ; le jeu gère le minutage et l’occupation des voix.
Cette fonction écrit un masque APU_STATUS à un seul canal, désactivant les autres voix. Ce n’est pas un mélangeur multivoix. Pour les impulsions et le triangle, period est une valeur de minuterie : plus elle est petite, plus le son est aigu. Les hauteurs et durées de l’exemple ont été vérifiées en NTSC.
Le DMC lit la ROM sur une frontière de 64 octets entre $C000 et $FFC0. La longueur est de 16*n+1 octets, de 1 à 4081. Ces fonctions ne vérifient ni alignement ni plages et ne changent pas de banque. L’exemple place des données originales dans la banque fixe 0 avec __aligned(64) et vérifie leur emplacement à l’exécution.
nes_apu_channel_enable
Remplace l’état d’activation des cinq canaux APU par le masque fourni.
Syntaxe
void nes_apu_channel_enable(u8 mask);Paramètres
maskMasque d’activation APU_STATUS complet. Les bits 0..4 sélectionnent pulse1, pulse2, triangle, noise et DMC ; les bits supérieurs sont ignorés.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Exemple d’utilisation
// NTSC: pulse A4 (~440 Hz), triangle A3 (~220 Hz), noise, then two short effects.
#include "fc_sound_example.h"
void main(void) {
sound_begin("APU CHANNELS AND BLIPS");
// Constant volume 12, length halt and 50% duty. Each helper replaces 4015.
nes_sfx_square1(0xBC,253,0);
sound_result[0]=(u8)(APU_STATUS&0x1F);
sound_wait(30);
nes_apu_channel_enable(0); sound_wait(15);
nes_sfx_square2(0x7C,253,0);
sound_result[1]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_triangle(0xFF,253,0);
sound_result[2]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_noise(0x3C,5,0);
sound_result[3]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_tick_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_move_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
sound_end();
}Résultat attendu
Écoutez pulse1, pulse2, triangle, noise, tick puis move. En NTSC, un timer de 253 produit des impulsions d’environ 440 Hz et un triangle de 220 Hz. Tick est à environ 111 Hz ; move, à 174 Hz, finit plus tôt. Le dernier intervalle est silencieux.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_channels.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-channels.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio.h:17
Replace all five channel-enable bits in APU_STATUS; this is not an additive enable.
kitaqfc/lib/audio.c:43
void nes_apu_channel_enable(u8 mask)
{
APU_STATUS = (u8)(mask & 0x1F);
}nes_apu_init
Désactive l’IRQ de trame, active quatre voix et installe des réglages silencieux. Le DMC reste désactivé.
Syntaxe
void nes_apu_init(void);Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Exemple d’utilisation
// NTSC: pulse A4 (~440 Hz), triangle A3 (~220 Hz), noise, then two short effects.
#include "fc_sound_example.h"
void main(void) {
sound_begin("APU CHANNELS AND BLIPS");
// Constant volume 12, length halt and 50% duty. Each helper replaces 4015.
nes_sfx_square1(0xBC,253,0);
sound_result[0]=(u8)(APU_STATUS&0x1F);
sound_wait(30);
nes_apu_channel_enable(0); sound_wait(15);
nes_sfx_square2(0x7C,253,0);
sound_result[1]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_triangle(0xFF,253,0);
sound_result[2]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_noise(0x3C,5,0);
sound_result[3]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_tick_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_move_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
sound_end();
}Résultat attendu
Écoutez pulse1, pulse2, triangle, noise, tick puis move. En NTSC, un timer de 253 produit des impulsions d’environ 440 Hz et un triangle de 220 Hz. Tick est à environ 111 Hz ; move, à 174 Hz, finit plus tôt. Le dernier intervalle est silencieux.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_channels.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-channels.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio.h:15
Disable frame IRQs, enable the four tonal/noise channels and install quiet control defaults. DMC remains disabled.
kitaqfc/lib/audio.c:28
void nes_apu_init(void)
{
APU_FRAME = 0x40;
APU_STATUS = 0x0F;
SQ1_VOL = 0x10;
SQ1_SWEEP = 0x08;
SQ2_VOL = 0x10;
SQ2_SWEEP = 0x08;
TRI_LINEAR = 0x80;
NOISE_VOL = 0x10;
DMC_FREQ = 0x00;
DMC_RAW = 0x00;
}nes_apu_silence_all
Désactive tous les canaux et remet à zéro les volumes impulsion/bruit et la sortie DMC.
Syntaxe
void nes_apu_silence_all(void);Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Exemple d’utilisation
// NTSC: pulse A4 (~440 Hz), triangle A3 (~220 Hz), noise, then two short effects.
#include "fc_sound_example.h"
void main(void) {
sound_begin("APU CHANNELS AND BLIPS");
// Constant volume 12, length halt and 50% duty. Each helper replaces 4015.
nes_sfx_square1(0xBC,253,0);
sound_result[0]=(u8)(APU_STATUS&0x1F);
sound_wait(30);
nes_apu_channel_enable(0); sound_wait(15);
nes_sfx_square2(0x7C,253,0);
sound_result[1]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_triangle(0xFF,253,0);
sound_result[2]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_noise(0x3C,5,0);
sound_result[3]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_tick_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_move_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
sound_end();
}Résultat attendu
Écoutez pulse1, pulse2, triangle, noise, tick puis move. En NTSC, un timer de 253 produit des impulsions d’environ 440 Hz et un triangle de 220 Hz. Tick est à environ 111 Hz ; move, à 174 Hz, finit plus tôt. Le dernier intervalle est silencieux.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_channels.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-channels.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio.h:19
Disable every channel and clear volume/DMC output settings used by this helper.
kitaqfc/lib/audio.c:49
void nes_apu_silence_all(void)
{
APU_STATUS = 0x00;
SQ1_VOL = 0x10;
SQ2_VOL = 0x10;
TRI_LINEAR = 0x80;
NOISE_VOL = 0x10;
DMC_FREQ = 0x00;
DMC_RAW = 0x00;
}nes_dmc_config
Configure contrôle/sortie DMC et convertit l’adresse et la longueur de l’échantillon en unités de registre.
Syntaxe
void nes_dmc_config(u8 flags_rate, u8 output_level, u16 sample_addr, u16 sample_len);Paramètres
flags_rateDMC : bit 7 IRQ, bit 6 boucle, demi-octet bas indice de cadence. L’exemple n’active pas IRQ.
output_levelCompteur de sortie DMC initial, de 0 à 127 ; seuls les sept bits bas sont écrits.
sample_addrAdresse CPU des données DMC, sur une frontière de 64 octets entre $C000 et $FFC0.
sample_lenLongueur de 16*n+1 octets, de 1 à 4081. Ne passez ni zéro ni une longueur non représentable.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Le DMC lit la ROM sur une frontière de 64 octets entre $C000 et $FFC0. La longueur est de 16*n+1 octets, de 1 à 4081. Ces fonctions ne vérifient ni alignement ni plages et ne changent pas de banque. L’exemple place des données originales dans la banque fixe 0 avec __aligned(64) et vérifie leur emplacement à l’exécution.
Exemple d’utilisation
// A 17-byte original delta pattern, aligned to a 64-byte DMC start boundary.
#include "fc_sound_example.h"
#pragma bank 0
__aligned(64) __prg_rom u8 delta[17]={0xFF,0xFF,0,0,0xFF,0xFF,0,0,0xFF,0xFF,0,0,0xFF,0xFF,0,0,0xAA};
void main(void) {
sound_begin("DMC ORIGINAL DELTAS");
sound_result[0]=(u8)(((u16)delta&63)==0);
sound_result[1]=(u8)((u16)delta>=0xC000);
// Loop at NTSC rate index 10; start the output accumulator at its midpoint.
nes_dmc_config(0x4A,64,(u16)delta,17);
nes_dmc_start();
sound_wait(60);
nes_dmc_stop(); sound_wait(30);
nes_dmc_play(0x4C,64,(u16)delta,17);
sound_wait(60);
nes_dmc_stop(); sound_wait(30);
sound_end();
}Résultat attendu
Un motif delta original joue à la cadence 10, s’interrompt, puis reprend plus vite à 12. L’arrêt DMC conserve le compteur de sortie ; la pause peut donc contenir un transitoire. L’opération finale coupe toute l’APU.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_dmc.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-dmc.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio.h:38
Convert a CPU sample address and byte length to DMC register units. Supply an address in 0xC000-0xFFC0 aligned to 64 bytes and a representable length 16*n+1 in 1..4081; inputs are narrowed without validation or bank management.
kitaqfc/lib/audio.c:115
void nes_dmc_config(u8 flags_rate, u8 output_level, u16 sample_addr, u16 sample_len)
{
DMC_FREQ = flags_rate;
DMC_RAW = (u8)(output_level & 0x7F);
// Keep the sample bytes mapped at these CPU addresses during playback; this does not select a ROM bank.
DMC_START = (u8)((sample_addr - 0xC000) >> 6);
DMC_LEN = (u8)((sample_len - 1) >> 4);
}nes_dmc_play
Configure l’échantillon DMC et lance immédiatement sa lecture.
Syntaxe
void nes_dmc_play(u8 flags_rate, u8 output_level, u16 sample_addr, u16 sample_len);Paramètres
flags_rateDMC : bit 7 IRQ, bit 6 boucle, demi-octet bas indice de cadence. L’exemple n’active pas IRQ.
output_levelCompteur de sortie DMC initial, de 0 à 127 ; seuls les sept bits bas sont écrits.
sample_addrAdresse CPU des données DMC, sur une frontière de 64 octets entre $C000 et $FFC0.
sample_lenLongueur de 16*n+1 octets, de 1 à 4081. Ne passez ni zéro ni une longueur non représentable.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Le DMC lit la ROM sur une frontière de 64 octets entre $C000 et $FFC0. La longueur est de 16*n+1 octets, de 1 à 4081. Ces fonctions ne vérifient ni alignement ni plages et ne changent pas de banque. L’exemple place des données originales dans la banque fixe 0 avec __aligned(64) et vérifie leur emplacement à l’exécution.
Exemple d’utilisation
// A 17-byte original delta pattern, aligned to a 64-byte DMC start boundary.
#include "fc_sound_example.h"
#pragma bank 0
__aligned(64) __prg_rom u8 delta[17]={0xFF,0xFF,0,0,0xFF,0xFF,0,0,0xFF,0xFF,0,0,0xFF,0xFF,0,0,0xAA};
void main(void) {
sound_begin("DMC ORIGINAL DELTAS");
sound_result[0]=(u8)(((u16)delta&63)==0);
sound_result[1]=(u8)((u16)delta>=0xC000);
// Loop at NTSC rate index 10; start the output accumulator at its midpoint.
nes_dmc_config(0x4A,64,(u16)delta,17);
nes_dmc_start();
sound_wait(60);
nes_dmc_stop(); sound_wait(30);
nes_dmc_play(0x4C,64,(u16)delta,17);
sound_wait(60);
nes_dmc_stop(); sound_wait(30);
sound_end();
}Résultat attendu
Un motif delta original joue à la cadence 10, s’interrompt, puis reprend plus vite à 12. L’arrêt DMC conserve le compteur de sortie ; la pause peut donc contenir un transitoire. L’opération finale coupe toute l’APU.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_dmc.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-dmc.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio.h:44
Install sample parameters, then start DMC using the full-channel enable mask.
kitaqfc/lib/audio.c:137
void nes_dmc_play(u8 flags_rate, u8 output_level, u16 sample_addr, u16 sample_len)
{
nes_dmc_config(flags_rate, output_level, sample_addr, sample_len);
nes_dmc_start();
}nes_dmc_start
Écrit APU_STATUS=0x1F pour activer le DMC et les quatre autres voix.
Syntaxe
void nes_dmc_start(void);Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Le DMC lit la ROM sur une frontière de 64 octets entre $C000 et $FFC0. La longueur est de 16*n+1 octets, de 1 à 4081. Ces fonctions ne vérifient ni alignement ni plages et ne changent pas de banque. L’exemple place des données originales dans la banque fixe 0 avec __aligned(64) et vérifie leur emplacement à l’exécution.
Exemple d’utilisation
// A 17-byte original delta pattern, aligned to a 64-byte DMC start boundary.
#include "fc_sound_example.h"
#pragma bank 0
__aligned(64) __prg_rom u8 delta[17]={0xFF,0xFF,0,0,0xFF,0xFF,0,0,0xFF,0xFF,0,0,0xFF,0xFF,0,0,0xAA};
void main(void) {
sound_begin("DMC ORIGINAL DELTAS");
sound_result[0]=(u8)(((u16)delta&63)==0);
sound_result[1]=(u8)((u16)delta>=0xC000);
// Loop at NTSC rate index 10; start the output accumulator at its midpoint.
nes_dmc_config(0x4A,64,(u16)delta,17);
nes_dmc_start();
sound_wait(60);
nes_dmc_stop(); sound_wait(30);
nes_dmc_play(0x4C,64,(u16)delta,17);
sound_wait(60);
nes_dmc_stop(); sound_wait(30);
sound_end();
}Résultat attendu
Un motif delta original joue à la cadence 10, s’interrompt, puis reprend plus vite à 12. L’arrêt DMC conserve le compteur de sortie ; la pause peut donc contenir un transitoire. L’opération finale coupe toute l’APU.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_dmc.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-dmc.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio.h:40
Enable DMC together with all four other channels by replacing the status mask.
kitaqfc/lib/audio.c:125
void nes_dmc_start(void)
{
APU_STATUS = 0x1F;
}nes_dmc_stop
Écrit APU_STATUS=0x0F pour arrêter le DMC tout en activant les bits des quatre autres voix.
Syntaxe
void nes_dmc_stop(void);Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Le DMC lit la ROM sur une frontière de 64 octets entre $C000 et $FFC0. La longueur est de 16*n+1 octets, de 1 à 4081. Ces fonctions ne vérifient ni alignement ni plages et ne changent pas de banque. L’exemple place des données originales dans la banque fixe 0 avec __aligned(64) et vérifie leur emplacement à l’exécution.
Exemple d’utilisation
// A 17-byte original delta pattern, aligned to a 64-byte DMC start boundary.
#include "fc_sound_example.h"
#pragma bank 0
__aligned(64) __prg_rom u8 delta[17]={0xFF,0xFF,0,0,0xFF,0xFF,0,0,0xFF,0xFF,0,0,0xFF,0xFF,0,0,0xAA};
void main(void) {
sound_begin("DMC ORIGINAL DELTAS");
sound_result[0]=(u8)(((u16)delta&63)==0);
sound_result[1]=(u8)((u16)delta>=0xC000);
// Loop at NTSC rate index 10; start the output accumulator at its midpoint.
nes_dmc_config(0x4A,64,(u16)delta,17);
nes_dmc_start();
sound_wait(60);
nes_dmc_stop(); sound_wait(30);
nes_dmc_play(0x4C,64,(u16)delta,17);
sound_wait(60);
nes_dmc_stop(); sound_wait(30);
sound_end();
}Résultat attendu
Un motif delta original joue à la cadence 10, s’interrompt, puis reprend plus vite à 12. L’arrêt DMC conserve le compteur de sortie ; la pause peut donc contenir un transitoire. L’opération finale coupe toute l’APU.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_dmc.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-dmc.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio.h:42
Disable DMC while leaving all four other channel-enable bits set.
kitaqfc/lib/audio.c:131
void nes_dmc_stop(void)
{
APU_STATUS = 0x0F;
}nes_sfx_move_blip
Déclenche l’impulsion 1 avec contrôle 0x5A, timer 0x0280 et indice de longueur 2 pour un bip de déplacement plus aigu et plus court.
Syntaxe
void nes_sfx_move_blip(void);Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Cette fonction écrit un masque APU_STATUS à un seul canal, désactivant les autres voix. Ce n’est pas un mélangeur multivoix. Pour les impulsions et le triangle, period est une valeur de minuterie : plus elle est petite, plus le son est aigu. Les hauteurs et durées de l’exemple ont été vérifiées en NTSC.
Exemple d’utilisation
// NTSC: pulse A4 (~440 Hz), triangle A3 (~220 Hz), noise, then two short effects.
#include "fc_sound_example.h"
void main(void) {
sound_begin("APU CHANNELS AND BLIPS");
// Constant volume 12, length halt and 50% duty. Each helper replaces 4015.
nes_sfx_square1(0xBC,253,0);
sound_result[0]=(u8)(APU_STATUS&0x1F);
sound_wait(30);
nes_apu_channel_enable(0); sound_wait(15);
nes_sfx_square2(0x7C,253,0);
sound_result[1]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_triangle(0xFF,253,0);
sound_result[2]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_noise(0x3C,5,0);
sound_result[3]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_tick_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_move_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
sound_end();
}Résultat attendu
Écoutez pulse1, pulse2, triangle, noise, tick puis move. En NTSC, un timer de 253 produit des impulsions d’environ 440 Hz et un triangle de 220 Hz. Tick est à environ 111 Hz ; move, à 174 Hz, finit plus tôt. Le dernier intervalle est silencieux.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_channels.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-channels.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio.h:33
Trigger the predefined pulse-1 movement effect.
kitaqfc/lib/audio.c:107
void nes_sfx_move_blip(void)
{
nes_sfx_square1(0x5A, 0x0280, 2);
}nes_sfx_noise
Active seulement le bruit et écrit enveloppe, période/mode et indice de longueur.
Syntaxe
void nes_sfx_noise(u8 volume, u8 period_mode, u8 length_index);Paramètres
volumeContrôle de bruit brut : bit 5 arrêt du compteur de longueur, bit 4 volume constant, demi-octet bas volume ou période d’enveloppe.
period_modeRegistre de bruit : bit 7 pour le mode court, demi-octet bas pour l’indice de période.
length_indexIndice de table de longueur de 0 à 31, pas un nombre d’images. Seuls les cinq bits bas atteignent le registre.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Cette fonction écrit un masque APU_STATUS à un seul canal, désactivant les autres voix. Ce n’est pas un mélangeur multivoix. Pour les impulsions et le triangle, period est une valeur de minuterie : plus elle est petite, plus le son est aigu. Les hauteurs et durées de l’exemple ont été vérifiées en NTSC.
Exemple d’utilisation
// NTSC: pulse A4 (~440 Hz), triangle A3 (~220 Hz), noise, then two short effects.
#include "fc_sound_example.h"
void main(void) {
sound_begin("APU CHANNELS AND BLIPS");
// Constant volume 12, length halt and 50% duty. Each helper replaces 4015.
nes_sfx_square1(0xBC,253,0);
sound_result[0]=(u8)(APU_STATUS&0x1F);
sound_wait(30);
nes_apu_channel_enable(0); sound_wait(15);
nes_sfx_square2(0x7C,253,0);
sound_result[1]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_triangle(0xFF,253,0);
sound_result[2]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_noise(0x3C,5,0);
sound_result[3]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_tick_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_move_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
sound_end();
}Résultat attendu
Écoutez pulse1, pulse2, triangle, noise, tick puis move. En NTSC, un timer de 253 produit des impulsions d’environ 440 Hz et un triangle de 220 Hz. Tick est à environ 111 Hz ; move, à 174 Hz, finit plus tôt. Le dernier intervalle est silencieux.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_channels.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-channels.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio.h:29
Enable only noise and load envelope/control, period/mode and length fields.
kitaqfc/lib/audio.c:92
void nes_sfx_noise(u8 volume, u8 period_mode, u8 length_index)
{
APU_STATUS = 0x08;
NOISE_VOL = volume;
NOISE_LO = period_mode;
NOISE_HI = (u8)(length_index << 3);
}nes_sfx_square1
Active seulement l’impulsion 1, désactive le balayage et écrit contrôle, timer et indice de longueur.
Syntaxe
void nes_sfx_square1(u8 duty_volume, u16 period, u8 length_index);Paramètres
duty_volumeContrôle d’impulsion brut : bits 7..6 pour le rapport cyclique, bit 5 pour l’arrêt du compteur de longueur, bit 4 pour le volume constant, demi-octet bas pour le volume ou la période d’enveloppe.
periodTimer sur 11 bits, de 0 à 2047. La fréquence d’impulsion vaut horloge CPU/[16*(period+1)] ; celle du triangle, horloge CPU/[32*(period+1)].
length_indexIndice de table de longueur de 0 à 31, pas un nombre d’images. Seuls les cinq bits bas atteignent le registre.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Cette fonction écrit un masque APU_STATUS à un seul canal, désactivant les autres voix. Ce n’est pas un mélangeur multivoix. Pour les impulsions et le triangle, period est une valeur de minuterie : plus elle est petite, plus le son est aigu. Les hauteurs et durées de l’exemple ont été vérifiées en NTSC.
Exemple d’utilisation
// NTSC: pulse A4 (~440 Hz), triangle A3 (~220 Hz), noise, then two short effects.
#include "fc_sound_example.h"
void main(void) {
sound_begin("APU CHANNELS AND BLIPS");
// Constant volume 12, length halt and 50% duty. Each helper replaces 4015.
nes_sfx_square1(0xBC,253,0);
sound_result[0]=(u8)(APU_STATUS&0x1F);
sound_wait(30);
nes_apu_channel_enable(0); sound_wait(15);
nes_sfx_square2(0x7C,253,0);
sound_result[1]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_triangle(0xFF,253,0);
sound_result[2]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_noise(0x3C,5,0);
sound_result[3]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_tick_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_move_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
sound_end();
}Résultat attendu
Écoutez pulse1, pulse2, triangle, noise, tick puis move. En NTSC, un timer de 253 produit des impulsions d’environ 440 Hz et un triangle de 220 Hz. Tick est à environ 111 Hz ; move, à 174 Hz, finit plus tôt. Le dernier intervalle est silencieux.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_channels.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-channels.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio.h:23
Enable only pulse 1, disable its sweep and load control, 11-bit timer and length-table index. Starting this effect disables the other APU channels.
kitaqfc/lib/audio.c:62
void nes_sfx_square1(u8 duty_volume, u16 period, u8 length_index)
{
APU_STATUS = 0x01;
SQ1_SWEEP = 0x08;
SQ1_VOL = duty_volume;
SQ1_LO = (u8)period;
// Only the low five length-index bits and low eleven timer bits reach the registers.
SQ1_HI = (u8)((u8)(length_index << 3) | (u8)((period >> 8) & 0x07));
}nes_sfx_square2
Active seulement l’impulsion 2, désactive le balayage et écrit contrôle, timer et indice de longueur.
Syntaxe
void nes_sfx_square2(u8 duty_volume, u16 period, u8 length_index);Paramètres
duty_volumeContrôle d’impulsion brut : bits 7..6 pour le rapport cyclique, bit 5 pour l’arrêt du compteur de longueur, bit 4 pour le volume constant, demi-octet bas pour le volume ou la période d’enveloppe.
periodTimer sur 11 bits, de 0 à 2047. La fréquence d’impulsion vaut horloge CPU/[16*(period+1)] ; celle du triangle, horloge CPU/[32*(period+1)].
length_indexIndice de table de longueur de 0 à 31, pas un nombre d’images. Seuls les cinq bits bas atteignent le registre.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Cette fonction écrit un masque APU_STATUS à un seul canal, désactivant les autres voix. Ce n’est pas un mélangeur multivoix. Pour les impulsions et le triangle, period est une valeur de minuterie : plus elle est petite, plus le son est aigu. Les hauteurs et durées de l’exemple ont été vérifiées en NTSC.
Exemple d’utilisation
// NTSC: pulse A4 (~440 Hz), triangle A3 (~220 Hz), noise, then two short effects.
#include "fc_sound_example.h"
void main(void) {
sound_begin("APU CHANNELS AND BLIPS");
// Constant volume 12, length halt and 50% duty. Each helper replaces 4015.
nes_sfx_square1(0xBC,253,0);
sound_result[0]=(u8)(APU_STATUS&0x1F);
sound_wait(30);
nes_apu_channel_enable(0); sound_wait(15);
nes_sfx_square2(0x7C,253,0);
sound_result[1]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_triangle(0xFF,253,0);
sound_result[2]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_noise(0x3C,5,0);
sound_result[3]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_tick_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_move_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
sound_end();
}Résultat attendu
Écoutez pulse1, pulse2, triangle, noise, tick puis move. En NTSC, un timer de 253 produit des impulsions d’environ 440 Hz et un triangle de 220 Hz. Tick est à environ 111 Hz ; move, à 174 Hz, finit plus tôt. Le dernier intervalle est silencieux.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_channels.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-channels.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio.h:25
Enable only pulse 2 and load its control/timer/length fields, disabling other channels.
kitaqfc/lib/audio.c:73
void nes_sfx_square2(u8 duty_volume, u16 period, u8 length_index)
{
APU_STATUS = 0x02;
SQ2_SWEEP = 0x08;
SQ2_VOL = duty_volume;
SQ2_LO = (u8)period;
SQ2_HI = (u8)((u8)(length_index << 3) | (u8)((period >> 8) & 0x07));
}nes_sfx_tick_blip
Déclenche l’impulsion 1 avec contrôle 0x9A, timer 0x03F0 et indice de longueur 4 pour un clic bref et grave.
Syntaxe
void nes_sfx_tick_blip(void);Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Cette fonction écrit un masque APU_STATUS à un seul canal, désactivant les autres voix. Ce n’est pas un mélangeur multivoix. Pour les impulsions et le triangle, period est une valeur de minuterie : plus elle est petite, plus le son est aigu. Les hauteurs et durées de l’exemple ont été vérifiées en NTSC.
Exemple d’utilisation
// NTSC: pulse A4 (~440 Hz), triangle A3 (~220 Hz), noise, then two short effects.
#include "fc_sound_example.h"
void main(void) {
sound_begin("APU CHANNELS AND BLIPS");
// Constant volume 12, length halt and 50% duty. Each helper replaces 4015.
nes_sfx_square1(0xBC,253,0);
sound_result[0]=(u8)(APU_STATUS&0x1F);
sound_wait(30);
nes_apu_channel_enable(0); sound_wait(15);
nes_sfx_square2(0x7C,253,0);
sound_result[1]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_triangle(0xFF,253,0);
sound_result[2]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_noise(0x3C,5,0);
sound_result[3]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_tick_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_move_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
sound_end();
}Résultat attendu
Écoutez pulse1, pulse2, triangle, noise, tick puis move. En NTSC, un timer de 253 produit des impulsions d’environ 440 Hz et un triangle de 220 Hz. Tick est à environ 111 Hz ; move, à 174 Hz, finit plus tôt. Le dernier intervalle est silencieux.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_channels.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-channels.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio.h:31
Trigger the predefined pulse-1 tick effect; it inherits the exclusive-channel behavior.
kitaqfc/lib/audio.c:101
void nes_sfx_tick_blip(void)
{
nes_sfx_square1(0x9A, 0x03F0, 4);
}nes_sfx_triangle
Active seulement le triangle et écrit compteur linéaire, timer et indice de longueur.
Syntaxe
void nes_sfx_triangle(u8 linear, u16 period, u8 length_index);Paramètres
linearCompteur linéaire du triangle : bit 7 pour le contrôle/arrêt de longueur, sept bits bas pour la valeur de rechargement.
periodTimer sur 11 bits, de 0 à 2047. La fréquence d’impulsion vaut horloge CPU/[16*(period+1)] ; celle du triangle, horloge CPU/[32*(period+1)].
length_indexIndice de table de longueur de 0 à 31, pas un nombre d’images. Seuls les cinq bits bas atteignent le registre.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Cette fonction écrit un masque APU_STATUS à un seul canal, désactivant les autres voix. Ce n’est pas un mélangeur multivoix. Pour les impulsions et le triangle, period est une valeur de minuterie : plus elle est petite, plus le son est aigu. Les hauteurs et durées de l’exemple ont été vérifiées en NTSC.
Exemple d’utilisation
// NTSC: pulse A4 (~440 Hz), triangle A3 (~220 Hz), noise, then two short effects.
#include "fc_sound_example.h"
void main(void) {
sound_begin("APU CHANNELS AND BLIPS");
// Constant volume 12, length halt and 50% duty. Each helper replaces 4015.
nes_sfx_square1(0xBC,253,0);
sound_result[0]=(u8)(APU_STATUS&0x1F);
sound_wait(30);
nes_apu_channel_enable(0); sound_wait(15);
nes_sfx_square2(0x7C,253,0);
sound_result[1]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_triangle(0xFF,253,0);
sound_result[2]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_noise(0x3C,5,0);
sound_result[3]=(u8)(APU_STATUS&0x1F);
sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_tick_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
nes_sfx_move_blip(); sound_wait(30); nes_apu_silence_all(); sound_wait(15);
sound_end();
}Résultat attendu
Écoutez pulse1, pulse2, triangle, noise, tick puis move. En NTSC, un timer de 253 produit des impulsions d’environ 440 Hz et un triangle de 220 Hz. Tick est à environ 111 Hz ; move, à 174 Hz, finit plus tôt. Le dernier intervalle est silencieux.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_channels.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-channels.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio.h:27
Enable only triangle and load linear-counter, timer and length fields.
kitaqfc/lib/audio.c:83
void nes_sfx_triangle(u8 linear, u16 period, u8 length_index)
{
APU_STATUS = 0x04;
TRI_LINEAR = linear;
TRI_LO = (u8)period;
TRI_HI = (u8)((u8)(length_index << 3) | (u8)((period >> 8) & 0x07));
}audio_vblank.h — Musique à quatre canaux pilotée par NMI
La musique à quatre canaux avance dans la NMI. Initialisez le pilote, associez un morceau et préremplissez la file, puis activez la NMI et poursuivez le remplissage depuis le programme principal. La NMI lit une file RAM : une petite quantité de RAM suffit pour un long flux, à condition de la réalimenter à temps. Chaque canal dispose de commandes HOLD/STOP indépendantes.
Un enregistrement contient cinq octets : delay, CH1, CH2, CH3, CH4. Une durée de 1 à 255 indique le nombre de ticks NMI pendant lesquels le nouvel état reste actif. Zéro termine la lecture et les quatre autres octets sont ignorés. Les notes de 0 à 71 correspondent à C2–B7 (24=C4). Pour le bruit, les valeurs 0 à 15 sélectionnent une période en mode long, et 16 à 31 le mode court. Sur tous les canaux, 255=NES_AUDIO_HOLD conserve l’état et 254=NES_AUDIO_STOP coupe le son.
Ce pilote à quatre canaux est réglé pour le NTSC : CH1=impulsion 1, CH2=impulsion 2, CH3=triangle et CH4=bruit, avec des indices de 0 à 3. Il ne gère ni le DMC ni les extensions audio. Ne l’utilisez pas en parallèle avec du code écrivant directement dans l’APU, comme les effets de audio.c. Il ne fournit ni table de fréquences PAL ni correction de tempo pour le PAL.
Si la durée expire sans nouvel enregistrement BGM, les notes BGM s’arrêtent ; la lecture reprend lors d’une NMI après l’arrivée de données. Un effet sonore indépendant continue. Le compteur mesure les entrées en manque de données, pas chaque image passée à attendre. Insérer uniquement des valeurs HOLD ne rétablit pas les anciennes notes BGM. En général, remplissez la file à chaque image et préparez une durée de lecture suffisante avant un traitement long.
| Délai | CH1 : impulsion 1 | CH2 : impulsion 2 | CH3 : triangle | CH4 : bruit |
|---|---|---|---|---|
| 24 | 24 (C4) | 12 (C3) | 0 (C2) | 2 |
Point d’appel NMI raccordé par le compilateur
nes_audio_vblank_init
Initialise l’APU et la file, en réinitialisant la lecture, l’état d’alimentation et le compteur de manque de données.
Syntaxe
void nes_audio_vblank_init(void);Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Incluez audio_vblank.h et ajoutez audio_vblank.c à la compilation exactement une fois. Le compilateur appelle son point d’entrée une fois depuis le gestionnaire NMI, qu’il soit standard ou personnalisé. Activez la NMI du PPU. La boucle principale n’appelle pas de routine de mise à jour musicale.
Ce pilote à quatre canaux est réglé pour le NTSC : CH1=impulsion 1, CH2=impulsion 2, CH3=triangle et CH4=bruit, avec des indices de 0 à 3. Il ne gère ni le DMC ni les extensions audio. Ne l’utilisez pas en parallèle avec du code écrivant directement dans l’APU, comme les effets de audio.c. Il ne fournit ni table de fréquences PAL ni correction de tempo pour le PAL.
Désactive les IRQ de trame de l’APU, le DMC et le balayage des canaux à impulsions. Par défaut, l’impulsion 1 utilise un rapport cyclique de 50 % et un volume de 12, l’impulsion 2 un rapport de 25 % et un volume de 10, le triangle est autorisé à jouer des notes et le bruit a un volume de 8. L’initialisation ne démarre ni la musique ni la NMI.
Exemple d’utilisation
nes_audio_vblank_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
L’exemple joue une fois une phrase originale à quatre canaux. La musique continue pendant que le programme principal effectue des calculs entiers durant 90 images sans remplir la file. « PHRASE COMPLETE / SILENT » et « UNDERRUNS 0 / MATH OK » indiquent que la lecture est terminée, qu’aucun manque de données n’a eu lieu et que les calculs ont donné les résultats attendus. Écoutez l’enregistrement pour reconnaître la mélodie et l’accompagnement à impulsions, la basse triangulaire et le bruit. La fin est silencieuse. L’image présente les résultats du contrôle ; l’audio permet d’évaluer le son.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio_vblank.h:19
Reset the queue, feeder and diagnostic counters; silence and initialize the APU. Owns the four basic channels and disables DMC and APU frame IRQs.
kitaqfc/lib/audio_vblank.c:67
void nes_audio_vblank_init(void){
nes_audio_vblank_stop();nav_underruns=0;nav_frame=0x40;
nav_sweep1=8;nav_sweep2=8;nav_dmc_flags=0;nav_dmc_level=0;
nav_timbre[0]=0xBC;nav_timbre[1]=0x7A;nav_timbre[2]=0xFF;nav_timbre[3]=0x38;
}nes_audio_vblank_enqueue
Vérifie et copie un enregistrement dans la file RAM. Utilisez cette fonction pour produire la musique dans le code du jeu sans alimentation depuis la ROM.
Syntaxe
u8 nes_audio_vblank_enqueue(const u8* record);Paramètres
recordAdresse de cinq octets lisibles, valide jusqu’au retour de l’appel. Le tableau source peut ensuite être réutilisé. Un pointeur nul est refusé.
Valeur renvoyée
Renvoie 1 si l’enregistrement est accepté. Une file pleine, un pointeur nul ou des valeurs de note ou de bruit invalides renvoient 0 sans modifier la file. Les quatre octets de canaux d’un terminateur ne sont pas vérifiés.
Conditions et limites
Incluez audio_vblank.h et ajoutez audio_vblank.c à la compilation exactement une fois. Le compilateur appelle son point d’entrée une fois depuis le gestionnaire NMI, qu’il soit standard ou personnalisé. Activez la NMI du PPU. La boucle principale n’appelle pas de routine de mise à jour musicale.
Ce pilote à quatre canaux est réglé pour le NTSC : CH1=impulsion 1, CH2=impulsion 2, CH3=triangle et CH4=bruit, avec des indices de 0 à 3. Il ne gère ni le DMC ni les extensions audio. Ne l’utilisez pas en parallèle avec du code écrivant directement dans l’APU, comme les effets de audio.c. Il ne fournit ni table de fréquences PAL ni correction de tempo pour le PAL.
Le tampon circulaire de 40 octets en RAM possède huit emplacements physiques, dont un reste vide pour distinguer un tampon plein d’un tampon vide. La capacité utile est donc de sept enregistrements. Utilisez un seul producteur dans le programme principal ; n’insérez rien, ne remplissez pas la file et ne l’initialisez pas depuis la NMI. Le producteur ne publie la position d’écriture sur un octet qu’après avoir copié l’enregistrement entier, ce qui empêche la NMI de lire un enregistrement partiel.
Un enregistrement contient cinq octets : delay, CH1, CH2, CH3, CH4. Une durée de 1 à 255 indique le nombre de ticks NMI pendant lesquels le nouvel état reste actif. Zéro termine la lecture et les quatre autres octets sont ignorés. Les notes de 0 à 71 correspondent à C2–B7 (24=C4). Pour le bruit, les valeurs 0 à 15 sélectionnent une période en mode long, et 16 à 31 le mode court. Sur tous les canaux, 255=NES_AUDIO_HOLD conserve l’état et 254=NES_AUDIO_STOP coupe le son.
Exemple d’utilisation
result[6]=nes_audio_vblank_enqueue(quiet_record); // Copy five bytes into RAM.Cet extrait montre l’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 une fois une phrase originale à quatre canaux. La musique continue pendant que le programme principal effectue des calculs entiers durant 90 images sans remplir la file. « PHRASE COMPLETE / SILENT » et « UNDERRUNS 0 / MATH OK » indiquent que la lecture est terminée, qu’aucun manque de données n’a eu lieu et que les calculs ont donné les résultats attendus. Écoutez l’enregistrement pour reconnaître la mélodie et l’accompagnement à impulsions, la basse triangulaire et le bruit. La fin est silencieuse. L’image présente les résultats du contrôle ; l’audio permet d’évaluer le son.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio_vblank.h:22
Copy one complete validated record to RAM and publish it atomically last. Return 1 on success, 0 for null/invalid/full. Call from one foreground producer.
kitaqfc/lib/audio_vblank.c:74
u8 nes_audio_vblank_enqueue(const u8* record){
u8 next;u8 i;u8 value;
nav_invalid=0;
if(record==0){nav_invalid=1;return 0;}
next=nav_head+5;if(next==40)next=0;
if(next==nav_tail)return 0;
if(record[0]!=0){
for(i=1;i<5;i++){
value=record[i];
if(value<254){
if(i<4){if(value>71){nav_invalid=1;return 0;}}
else{if(value>31){nav_invalid=1;return 0;}}
}
}
}
for(i=0;i<5;i++)nav_queue[(__safe_index u8)(nav_head+i)]=record[i];
nav_head=next;return 1;
}nes_audio_vblank_queued
Renvoie le nombre d’enregistrements que la NMI n’a pas encore consommés.
Syntaxe
u8 nes_audio_vblank_queued(void);Valeur renvoyée
Renvoie le nombre d’enregistrements BGM en attente, de 0 à 7, sans compter la durée en cours ni les enregistrements SFX. La NMI consomme les données ; le résultat n’est donc qu’un instantané.
Conditions et limites
Incluez audio_vblank.h et ajoutez audio_vblank.c à la compilation exactement une fois. Le compilateur appelle son point d’entrée une fois depuis le gestionnaire NMI, qu’il soit standard ou personnalisé. Activez la NMI du PPU. La boucle principale n’appelle pas de routine de mise à jour musicale.
Ce pilote à quatre canaux est réglé pour le NTSC : CH1=impulsion 1, CH2=impulsion 2, CH3=triangle et CH4=bruit, avec des indices de 0 à 3. Il ne gère ni le DMC ni les extensions audio. Ne l’utilisez pas en parallèle avec du code écrivant directement dans l’APU, comme les effets de audio.c. Il ne fournit ni table de fréquences PAL ni correction de tempo pour le PAL.
Le tampon circulaire de 40 octets en RAM possède huit emplacements physiques, dont un reste vide pour distinguer un tampon plein d’un tampon vide. La capacité utile est donc de sept enregistrements. Utilisez un seul producteur dans le programme principal ; n’insérez rien, ne remplissez pas la file et ne l’initialisez pas depuis la NMI. Le producteur ne publie la position d’écriture sur un octet qu’après avoir copié l’enregistrement entier, ce qui empêche la NMI de lire un enregistrement partiel.
Exemple d’utilisation
result[1]=nes_audio_vblank_queued(); // Seven records after prefill.Cet extrait montre l’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 une fois une phrase originale à quatre canaux. La musique continue pendant que le programme principal effectue des calculs entiers durant 90 images sans remplir la file. « PHRASE COMPLETE / SILENT » et « UNDERRUNS 0 / MATH OK » indiquent que la lecture est terminée, qu’aucun manque de données n’a eu lieu et que les calculs ont donné les résultats attendus. Écoutez l’enregistrement pour reconnaître la mélodie et l’accompagnement à impulsions, la basse triangulaire et le bruit. La fin est silencieuse. L’image présente les résultats du contrôle ; l’audio permet d’évaluer le son.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio_vblank.h:24
Return queued records (0..7), excluding the record whose delay is in progress.
kitaqfc/lib/audio_vblank.c:94
u8 nes_audio_vblank_queued(void){
u8 head;u8 tail;head=nav_head;tail=nav_tail;
if(head<tail)head=head+40;
return (head-tail)/5;
}nes_audio_vblank_free
Renvoie le nombre d’emplacements libres dans la file.
Syntaxe
u8 nes_audio_vblank_free(void);Valeur renvoyée
Renvoie le nombre d’emplacements BGM libres, de 0 à 7, égal à 7−queued(). Il s’agit d’un nombre d’emplacements, chacun contenant cinq octets. Le tampon SFX distinct de 35 octets ne fait pas partie de cette file.
Conditions et limites
Incluez audio_vblank.h et ajoutez audio_vblank.c à la compilation exactement une fois. Le compilateur appelle son point d’entrée une fois depuis le gestionnaire NMI, qu’il soit standard ou personnalisé. Activez la NMI du PPU. La boucle principale n’appelle pas de routine de mise à jour musicale.
Ce pilote à quatre canaux est réglé pour le NTSC : CH1=impulsion 1, CH2=impulsion 2, CH3=triangle et CH4=bruit, avec des indices de 0 à 3. Il ne gère ni le DMC ni les extensions audio. Ne l’utilisez pas en parallèle avec du code écrivant directement dans l’APU, comme les effets de audio.c. Il ne fournit ni table de fréquences PAL ni correction de tempo pour le PAL.
Le tampon circulaire de 40 octets en RAM possède huit emplacements physiques, dont un reste vide pour distinguer un tampon plein d’un tampon vide. La capacité utile est donc de sept enregistrements. Utilisez un seul producteur dans le programme principal ; n’insérez rien, ne remplissez pas la file et ne l’initialisez pas depuis la NMI. Le producteur ne publie la position d’écriture sur un octet qu’après avoir copié l’enregistrement entier, ce qui empêche la NMI de lire un enregistrement partiel.
Exemple d’utilisation
result[2]=nes_audio_vblank_free(); // No free slots immediately after prefill.Cet extrait montre l’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 une fois une phrase originale à quatre canaux. La musique continue pendant que le programme principal effectue des calculs entiers durant 90 images sans remplir la file. « PHRASE COMPLETE / SILENT » et « UNDERRUNS 0 / MATH OK » indiquent que la lecture est terminée, qu’aucun manque de données n’a eu lieu et que les calculs ont donné les résultats attendus. Écoutez l’enregistrement pour reconnaître la mélodie et l’accompagnement à impulsions, la basse triangulaire et le bruit. La fin est silencieuse. L’image présente les résultats du contrôle ; l’audio permet d’évaluer le son.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio_vblank.h:26
Return available record slots (0..7), not bytes.
kitaqfc/lib/audio_vblank.c:99
u8 nes_audio_vblank_free(void){return 7-nes_audio_vblank_queued();}nes_audio_vblank_start
Active la consommation de la file RAM. Le premier enregistrement est pris à la prochaine NMI.
Syntaxe
void nes_audio_vblank_start(void);Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Incluez audio_vblank.h et ajoutez audio_vblank.c à la compilation exactement une fois. Le compilateur appelle son point d’entrée une fois depuis le gestionnaire NMI, qu’il soit standard ou personnalisé. Activez la NMI du PPU. La boucle principale n’appelle pas de routine de mise à jour musicale.
Ce pilote à quatre canaux est réglé pour le NTSC : CH1=impulsion 1, CH2=impulsion 2, CH3=triangle et CH4=bruit, avec des indices de 0 à 3. Il ne gère ni le DMC ni les extensions audio. Ne l’utilisez pas en parallèle avec du code écrivant directement dans l’APU, comme les effets de audio.c. Il ne fournit ni table de fréquences PAL ni correction de tempo pour le PAL.
Initialisez le pilote et remplissez d’abord la file. Cet appel n’active pas la NMI et ne modifie ni la durée en cours ni la position de lecture. Pour reprendre un pilote en pause, utilisez pause(0) ; start seul ne lève pas la pause.
Si la durée expire sans nouvel enregistrement BGM, les notes BGM s’arrêtent ; la lecture reprend lors d’une NMI après l’arrivée de données. Un effet sonore indépendant continue. Le compteur mesure les entrées en manque de données, pas chaque image passée à attendre. Insérer uniquement des valeurs HOLD ne rétablit pas les anciennes notes BGM. En général, remplissez la file à chaque image et préparez une durée de lecture suffisante avant un traitement long.
Exemple d’utilisation
nes_audio_vblank_start(); // Consume the copied record on the next NMI.Cet extrait montre l’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 une fois une phrase originale à quatre canaux. La musique continue pendant que le programme principal effectue des calculs entiers durant 90 images sans remplir la file. « PHRASE COMPLETE / SILENT » et « UNDERRUNS 0 / MATH OK » indiquent que la lecture est terminée, qu’aucun manque de données n’a eu lieu et que les calculs ont donné les résultats attendus. Écoutez l’enregistrement pour reconnaître la mélodie et l’accompagnement à impulsions, la basse triangulaire et le bruit. La fin est silencieuse. L’image présente les résultats du contrôle ; l’audio permet d’évaluer le son.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio_vblank.h:28
Enable consumption at the next NMI. Does not enable PPU NMI itself.
kitaqfc/lib/audio_vblank.c:100
void nes_audio_vblank_start(void){nav_active=1;}nes_audio_vblank_stop
Désactive la lecture, coupe les quatre canaux et supprime la file ainsi que l’état d’alimentation ROM.
Syntaxe
void nes_audio_vblank_stop(void);Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Incluez audio_vblank.h et ajoutez audio_vblank.c à la compilation exactement une fois. Le compilateur appelle son point d’entrée une fois depuis le gestionnaire NMI, qu’il soit standard ou personnalisé. Activez la NMI du PPU. La boucle principale n’appelle pas de routine de mise à jour musicale.
Ce pilote à quatre canaux est réglé pour le NTSC : CH1=impulsion 1, CH2=impulsion 2, CH3=triangle et CH4=bruit, avec des indices de 0 à 3. Il ne gère ni le DMC ni les extensions audio. Ne l’utilisez pas en parallèle avec du code écrivant directement dans l’APU, comme les effets de audio.c. Il ne fournit ni table de fréquences PAL ni correction de tempo pour le PAL.
Arrête la BGM et les SFX, en supprimant la file, l’état d’alimentation, les deux positions de lecture et l’état de pause. Conserve les timbres et le compteur de manque de données, sans désactiver la NMI. Utilisez pause pour conserver la position. set_music et play_music effectuent aussi cet arrêt en interne et annulent donc les SFX.
Exemple d’utilisation
nes_audio_vblank_stop(); // Clear the feeder and queued records; silence 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
L’exemple joue une fois une phrase originale à quatre canaux. La musique continue pendant que le programme principal effectue des calculs entiers durant 90 images sans remplir la file. « PHRASE COMPLETE / SILENT » et « UNDERRUNS 0 / MATH OK » indiquent que la lecture est terminée, qu’aucun manque de données n’a eu lieu et que les calculs ont donné les résultats attendus. Écoutez l’enregistrement pour reconnaître la mélodie et l’accompagnement à impulsions, la basse triangulaire et le bruit. La fin est silencieuse. L’image présente les résultats du contrôle ; l’audio permet d’évaluer le son.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio_vblank.h:30
Disable consumption, silence, discard queued records and clear the feeder.
kitaqfc/lib/audio_vblank.c:29
void nes_audio_vblank_stop(void){
u8 i;
nav_paused=1;nav_active=0;nav_sfx_active=0;nav_status=0;
nav_delay=0;nav_enabled=0;nav_head=0;nav_tail=0;
nav_source=0;nav_cursor=0;nav_count=0;nav_left=0;nav_starved=0;
nav_previous_mask=0;nav_effective_mask=0;nav_refresh=0;
for(i=0;i<4;i++){nav_notes[(__safe_index u8)i]=254;nav_sfx_notes[(__safe_index u8)i]=254;}
nav_paused=0;
}nes_audio_vblank_set_music
Arrête la lecture et associe un flux comme source d’alimentation. La copie dans la file et le démarrage de la lecture sont des opérations distinctes.
Syntaxe
u8 nes_audio_vblank_set_music(const u8* records,u16 count,u8 loop);Paramètres
recordsDébut du flux dans une ROM ou une RAM lisible. Conservez ces données jusqu’à la fin de l’alimentation de la file. Aucune commutation de banque n’est effectuée : mappez la bonne banque ROM pendant les appels à refill. La NMI ne lit que les enregistrements copiés en RAM.
countNombre d’enregistrements lisibles de cinq octets, de 1 à 13107 ; ce n’est pas un nombre d’octets. Les count×5 octets doivent tous se trouver dans une plage d’adresses CPU valide et contiguë.
loopZéro sélectionne une lecture unique ; toute valeur non nulle répète le flux depuis le début. N’insérez pas de terminateur de durée zéro dans un flux en boucle.
Valeur renvoyée
Renvoie 1 pour un pointeur et un nombre valides, ou 0 si le pointeur est nul, si le nombre est nul ou s’il dépasse 13107. Même en cas d’échec, la lecture actuelle est arrêtée et les données en attente sont supprimées. Le contenu des enregistrements est vérifié lors du remplissage.
Conditions et limites
Incluez audio_vblank.h et ajoutez audio_vblank.c à la compilation exactement une fois. Le compilateur appelle son point d’entrée une fois depuis le gestionnaire NMI, qu’il soit standard ou personnalisé. Activez la NMI du PPU. La boucle principale n’appelle pas de routine de mise à jour musicale.
Ce pilote à quatre canaux est réglé pour le NTSC : CH1=impulsion 1, CH2=impulsion 2, CH3=triangle et CH4=bruit, avec des indices de 0 à 3. Il ne gère ni le DMC ni les extensions audio. Ne l’utilisez pas en parallèle avec du code écrivant directement dans l’APU, comme les effets de audio.c. Il ne fournit ni table de fréquences PAL ni correction de tempo pour le PAL.
Un enregistrement contient cinq octets : delay, CH1, CH2, CH3, CH4. Une durée de 1 à 255 indique le nombre de ticks NMI pendant lesquels le nouvel état reste actif. Zéro termine la lecture et les quatre autres octets sont ignorés. Les notes de 0 à 71 correspondent à C2–B7 (24=C4). Pour le bruit, les valeurs 0 à 15 sélectionnent une période en mode long, et 16 à 31 le mode court. Sur tous les canaux, 255=NES_AUDIO_HOLD conserve l’état et 254=NES_AUDIO_STOP coupe le son.
Exemple d’utilisation
result[5]=nes_audio_vblank_set_music(song,8,0); // Attach without starting.Cet extrait montre l’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 une fois une phrase originale à quatre canaux. La musique continue pendant que le programme principal effectue des calculs entiers durant 90 images sans remplir la file. « PHRASE COMPLETE / SILENT » et « UNDERRUNS 0 / MATH OK » indiquent que la lecture est terminée, qu’aucun manque de données n’a eu lieu et que les calculs ont donné les résultats attendus. Écoutez l’enregistrement pour reconnaître la mélodie et l’accompagnement à impulsions, la basse triangulaire et le bruit. La fin est silencieuse. L’image présente les résultats du contrôle ; l’audio permet d’évaluer le son.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio_vblank.h:33
Stop and attach a readable five-byte-record stream; return 0 for null, zero count or a count above 13107. Nonzero loop repeats the stream. Does not start.
kitaqfc/lib/audio_vblank.c:110
u8 nes_audio_vblank_set_music(const u8* records,u16 count,u8 loop){
nes_audio_vblank_stop();
if(records==0||count==0||count>13107)return 0;
nav_source=records;nav_cursor=records;nav_count=count;nav_left=count;nav_loop=loop;
return 1;
}nes_audio_vblank_refill
Alimente les emplacements libres avec jusqu’à sept enregistrements du flux associé. Cette opération du programme principal permet de jouer un long morceau avec une petite file RAM.
Syntaxe
u8 nes_audio_vblank_refill(void);Valeur renvoyée
Renvoie de 0 à 7 enregistrements acceptés, en comptant le terminateur ajouté automatiquement pour une lecture unique. Sans source ou si la file est pleine, renvoie 0. Un enregistrement invalide arrête la lecture, supprime la file et l’état d’alimentation, puis entraîne un retour de 0.
Conditions et limites
Incluez audio_vblank.h et ajoutez audio_vblank.c à la compilation exactement une fois. Le compilateur appelle son point d’entrée une fois depuis le gestionnaire NMI, qu’il soit standard ou personnalisé. Activez la NMI du PPU. La boucle principale n’appelle pas de routine de mise à jour musicale.
Ce pilote à quatre canaux est réglé pour le NTSC : CH1=impulsion 1, CH2=impulsion 2, CH3=triangle et CH4=bruit, avec des indices de 0 à 3. Il ne gère ni le DMC ni les extensions audio. Ne l’utilisez pas en parallèle avec du code écrivant directement dans l’APU, comme les effets de audio.c. Il ne fournit ni table de fréquences PAL ni correction de tempo pour le PAL.
Début du flux dans une ROM ou une RAM lisible. Conservez ces données jusqu’à la fin de l’alimentation de la file. Aucune commutation de banque n’est effectuée : mappez la bonne banque ROM pendant les appels à refill. La NMI ne lit que les enregistrements copiés en RAM.
Zéro sélectionne une lecture unique ; toute valeur non nulle répète le flux depuis le début. N’insérez pas de terminateur de durée zéro dans un flux en boucle.
Si la durée expire sans nouvel enregistrement BGM, les notes BGM s’arrêtent ; la lecture reprend lors d’une NMI après l’arrivée de données. Un effet sonore indépendant continue. Le compteur mesure les entrées en manque de données, pas chaque image passée à attendre. Insérer uniquement des valeurs HOLD ne rétablit pas les anciennes notes BGM. En général, remplissez la file à chaque image et préparez une durée de lecture suffisante avant un traitement long.
L’alimentation depuis la ROM et l’insertion directe utilisent la même file ; ne les combinez qu’en maîtrisant leur ordre. Le remplissage ne joue aucun enregistrement et ne démarre pas le consommateur. En revanche, l’arrêt dû à des données invalides coupe bien le son de l’APU.
Exemple d’utilisation
nes_audio_vblank_refill();Cet extrait montre l’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 une fois une phrase originale à quatre canaux. La musique continue pendant que le programme principal effectue des calculs entiers durant 90 images sans remplir la file. « PHRASE COMPLETE / SILENT » et « UNDERRUNS 0 / MATH OK » indiquent que la lecture est terminée, qu’aucun manque de données n’a eu lieu et que les calculs ont donné les résultats attendus. Écoutez l’enregistrement pour reconnaître la mélodie et l’accompagnement à impulsions, la basse triangulaire et le bruit. La fin est silencieuse. L’image présente les résultats du contrôle ; l’audio permet d’évaluer le son.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio_vblank.h:37
Copy at most seven records from the attached stream. Return copies accepted. A one-shot feeder appends a delay-zero terminator after the last timed record. Keep the stream's ROM bank mapped during this foreground call only.
kitaqfc/lib/audio_vblank.c:118
u8 nes_audio_vblank_refill(void){
u8 copied;copied=0;
while(copied<7&&nav_source!=0){
if(nav_left==0){
if(nav_loop!=0){nav_cursor=nav_source;nav_left=nav_count;}
else {if(nes_audio_vblank_enqueue(nav_end)!=0){copied++;nav_source=0;}return copied;}
}
if(nes_audio_vblank_enqueue(nav_cursor)==0){
// The producer-only flag distinguishes malformed data from full.
// Re-reading occupancy here would race NMI freeing a full queue.
if(nav_invalid!=0){nes_audio_vblank_stop();return 0;}
return copied;
}
copied++;nav_cursor=nav_cursor+5;nav_left--;
}
return copied;
}nes_audio_vblank_play_music
Associe un morceau, préremplit la file et active la lecture en un seul appel. C’est le point d’entrée habituel pour démarrer une phrase.
Syntaxe
u8 nes_audio_vblank_play_music(const u8* records,u16 count,u8 loop);Paramètres
recordsDébut du flux dans une ROM ou une RAM lisible. Conservez ces données jusqu’à la fin de l’alimentation de la file. Aucune commutation de banque n’est effectuée : mappez la bonne banque ROM pendant les appels à refill. La NMI ne lit que les enregistrements copiés en RAM.
countNombre d’enregistrements lisibles de cinq octets, de 1 à 13107 ; ce n’est pas un nombre d’octets. Les count×5 octets doivent tous se trouver dans une plage d’adresses CPU valide et contiguë.
loopZéro sélectionne une lecture unique ; toute valeur non nulle répète le flux depuis le début. N’insérez pas de terminateur de durée zéro dans un flux en boucle.
Valeur renvoyée
Renvoie 1 si la configuration et le premier remplissage réussissent, ou 0 si la configuration est invalide ou si ce remplissage rencontre des données invalides. Un succès ne valide pas tout le morceau : les enregistrements erronés situés plus loin ne seront détectés que lors d’appels ultérieurs à refill.
Conditions et limites
Incluez audio_vblank.h et ajoutez audio_vblank.c à la compilation exactement une fois. Le compilateur appelle son point d’entrée une fois depuis le gestionnaire NMI, qu’il soit standard ou personnalisé. Activez la NMI du PPU. La boucle principale n’appelle pas de routine de mise à jour musicale.
Ce pilote à quatre canaux est réglé pour le NTSC : CH1=impulsion 1, CH2=impulsion 2, CH3=triangle et CH4=bruit, avec des indices de 0 à 3. Il ne gère ni le DMC ni les extensions audio. Ne l’utilisez pas en parallèle avec du code écrivant directement dans l’APU, comme les effets de audio.c. Il ne fournit ni table de fréquences PAL ni correction de tempo pour le PAL.
Appelez d’abord init une fois. play_music conserve les timbres et le compteur de manque de données. Continuez à appeler refill périodiquement pour les flux longs ou en boucle.
Exemple d’utilisation
result[0]=nes_audio_vblank_play_music(song,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
L’exemple joue une fois une phrase originale à quatre canaux. La musique continue pendant que le programme principal effectue des calculs entiers durant 90 images sans remplir la file. « PHRASE COMPLETE / SILENT » et « UNDERRUNS 0 / MATH OK » indiquent que la lecture est terminée, qu’aucun manque de données n’a eu lieu et que les calculs ont donné les résultats attendus. Écoutez l’enregistrement pour reconnaître la mélodie et l’accompagnement à impulsions, la basse triangulaire et le bruit. La fin est silencieuse. L’image présente les résultats du contrôle ; l’audio permet d’évaluer le son.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio_vblank.h:39
Set the stream, prefill the queue and start. Return 0 for invalid setup/data.
kitaqfc/lib/audio_vblank.c:135
u8 nes_audio_vblank_play_music(const u8* records,u16 count,u8 loop){
if(nes_audio_vblank_set_music(records,count,loop)==0)return 0;
if(nes_audio_vblank_refill()==0)return 0;
nes_audio_vblank_start();return 1;
}nes_audio_vblank_is_playing
Indique si la consommation de la file par la NMI est activée.
Syntaxe
u8 nes_audio_vblank_is_playing(void);Valeur renvoyée
Renvoie 1 tant que le consommateur BGM est activé, y compris pendant une pause ou un manque de données, et 0 après un arrêt ou la fin du morceau. Un SFX joué seul renvoie toujours 0. Ce résultat n’indique ni une sortie sonore audible ni l’activité des SFX.
Conditions et limites
Incluez audio_vblank.h et ajoutez audio_vblank.c à la compilation exactement une fois. Le compilateur appelle son point d’entrée une fois depuis le gestionnaire NMI, qu’il soit standard ou personnalisé. Activez la NMI du PPU. La boucle principale n’appelle pas de routine de mise à jour musicale.
Ce pilote à quatre canaux est réglé pour le NTSC : CH1=impulsion 1, CH2=impulsion 2, CH3=triangle et CH4=bruit, avec des indices de 0 à 3. Il ne gère ni le DMC ni les extensions audio. Ne l’utilisez pas en parallèle avec du code écrivant directement dans l’APU, comme les effets de audio.c. Il ne fournit ni table de fréquences PAL ni correction de tempo pour le PAL.
Si la durée expire sans nouvel enregistrement BGM, les notes BGM s’arrêtent ; la lecture reprend lors d’une NMI après l’arrivée de données. Un effet sonore indépendant continue. Le compteur mesure les entrées en manque de données, pas chaque image passée à attendre. Insérer uniquement des valeurs HOLD ne rétablit pas les anciennes notes BGM. En général, remplissez la file à chaque image et préparez une durée de lecture suffisante avant un traitement long.
Exemple d’utilisation
while(nes_audio_vblank_is_playing()!=0){
// example:nes_audio_vblank_refill:start
nes_audio_vblank_refill();
// example:nes_audio_vblank_refill:end
__nmi_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
L’exemple joue une fois une phrase originale à quatre canaux. La musique continue pendant que le programme principal effectue des calculs entiers durant 90 images sans remplir la file. « PHRASE COMPLETE / SILENT » et « UNDERRUNS 0 / MATH OK » indiquent que la lecture est terminée, qu’aucun manque de données n’a eu lieu et que les calculs ont donné les résultats attendus. Écoutez l’enregistrement pour reconnaître la mélodie et l’accompagnement à impulsions, la basse triangulaire et le bruit. La fin est silencieuse. L’image présente les résultats du contrôle ; l’audio permet d’évaluer le son.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio_vblank.h:41
Return 1 while the BGM consumer is enabled, including a recoverable queue underrun.
kitaqfc/lib/audio_vblank.c:101
u8 nes_audio_vblank_is_playing(void){return nav_active;}nes_audio_vblank_underruns
Renvoie le nombre d’épisodes de manque de données dans la file, afin d’évaluer la marge disponible pour le remplissage.
Syntaxe
u8 nes_audio_vblank_underruns(void);Valeur renvoyée
Renvoie de 0 à 255 et reste à 255 une fois cette limite atteinte. Compte les épisodes de manque de données, pas chaque image d’attente. init remet le compteur à zéro ; stop et les changements de morceau le conservent. Un terminateur normal n’est pas un manque de données.
Conditions et limites
Incluez audio_vblank.h et ajoutez audio_vblank.c à la compilation exactement une fois. Le compilateur appelle son point d’entrée une fois depuis le gestionnaire NMI, qu’il soit standard ou personnalisé. Activez la NMI du PPU. La boucle principale n’appelle pas de routine de mise à jour musicale.
Ce pilote à quatre canaux est réglé pour le NTSC : CH1=impulsion 1, CH2=impulsion 2, CH3=triangle et CH4=bruit, avec des indices de 0 à 3. Il ne gère ni le DMC ni les extensions audio. Ne l’utilisez pas en parallèle avec du code écrivant directement dans l’APU, comme les effets de audio.c. Il ne fournit ni table de fréquences PAL ni correction de tempo pour le PAL.
Si la durée expire sans nouvel enregistrement BGM, les notes BGM s’arrêtent ; la lecture reprend lors d’une NMI après l’arrivée de données. Un effet sonore indépendant continue. Le compteur mesure les entrées en manque de données, pas chaque image passée à attendre. Insérer uniquement des valeurs HOLD ne rétablit pas les anciennes notes BGM. En général, remplissez la file à chaque image et préparez une durée de lecture suffisante avant un traitement long.
Exemple d’utilisation
result[4]=nes_audio_vblank_underruns(); // Zero: queued time covered the busy section.Cet extrait montre l’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 une fois une phrase originale à quatre canaux. La musique continue pendant que le programme principal effectue des calculs entiers durant 90 images sans remplir la file. « PHRASE COMPLETE / SILENT » et « UNDERRUNS 0 / MATH OK » indiquent que la lecture est terminée, qu’aucun manque de données n’a eu lieu et que les calculs ont donné les résultats attendus. Écoutez l’enregistrement pour reconnaître la mélodie et l’accompagnement à impulsions, la basse triangulaire et le bruit. La fin est silencieuse. L’image présente les résultats du contrôle ; l’audio permet d’évaluer le son.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio_vblank.h:43
Saturating count of starvation episodes, cleared by init; END is not starvation.
kitaqfc/lib/audio_vblank.c:102
u8 nes_audio_vblank_underruns(void){return nav_underruns;}nes_audio_vblank_set_timbre
Configure le rapport cyclique ou le niveau de la prochaine note d’un canal, sans redéclencher sa note actuelle.
Syntaxe
u8 nes_audio_vblank_set_timbre(u8 channel,u8 control);Paramètres
channel0=CH1 impulsion 1, 1=CH2 impulsion 2, 2=CH3 triangle, 3=CH4 bruit. Les valeurs à partir de 4 sont refusées.
controlPour les impulsions, les bits 7..6 sélectionnent le rapport cyclique (0=12,5 %, 1=25 %, 2=50 %, 3=75 %) et les bits 3..0 fixent le volume constant de 0 à 15. Le bruit utilise normalement les bits 3..0 pour son volume constant. Ajoutez NES_AUDIO_NOISE_ENVELOPE (128) par un OU binaire pour utiliser ces bits comme période de décroissance de 0 à 15 : la prochaine note de bruit commence au volume 15 et décroît une fois. Les périodes plus grandes ralentissent la décroissance ; 15 correspond à environ une seconde. Le compteur de longueur du bruit laisse cette décroissance se terminer. Pour le triangle, zéro rend la prochaine note silencieuse ; toute valeur non nulle la rend audible.
Valeur renvoyée
Renvoie 1 pour un canal valide ; les valeurs à partir de 4 renvoient 0 sans rien modifier.
Conditions et limites
Incluez audio_vblank.h et ajoutez audio_vblank.c à la compilation exactement une fois. Le compilateur appelle son point d’entrée une fois depuis le gestionnaire NMI, qu’il soit standard ou personnalisé. Activez la NMI du PPU. La boucle principale n’appelle pas de routine de mise à jour musicale.
Ce pilote à quatre canaux est réglé pour le NTSC : CH1=impulsion 1, CH2=impulsion 2, CH3=triangle et CH4=bruit, avec des indices de 0 à 3. Il ne gère ni le DMC ni les extensions audio. Ne l’utilisez pas en parallèle avec du code écrivant directement dans l’APU, comme les effets de audio.c. Il ne fournit ni table de fréquences PAL ni correction de tempo pour le PAL.
Exemple d’utilisation
nes_audio_vblank_set_timbre(3,NES_AUDIO_NOISE_ENVELOPE|15);
result[3]=nes_audio_vblank_play_sfx(noise,1,8); // Bit 3 owns CH4; no BGM needed.
// The slow one-shot envelope fades by itself. It does not loop at 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
Aucune entrée n’est nécessaire. CH1 joue la BGM autour de 220 Hz, passe à un SFX autour de 880 Hz pendant 30 images, puis revient à la BGM courante. Après une pause silencieuse de 30 images, la BGM reprend. Un deuxième effet est interrompu explicitement après 15 images. Enfin, le bruit CH4 décroît lentement une fois. COMPLETE / ALL CHANNELS OFF indique la fin. Écoutez l’enregistrement joint pour vérifier les changements de hauteur, la pause silencieuse et la décroissance du bruit.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank_effects.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank_effects.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio_vblank.h:50
Configure the next note: pulse bits 7..6 select duty and 3..0 select volume; noise uses volume 3..0, or NES_AUDIO_NOISE_ENVELOPE | decay_period (0..15) for a one-shot hardware envelope (larger periods decay more slowly). The next noise note starts at volume 15; its length permits a full decay. Triangle uses zero for silent, nonzero for full level. Return 0 for channel >=4. Hardware has no triangle volume control.
kitaqfc/lib/audio_vblank.c:103
u8 nes_audio_vblank_set_timbre(u8 channel,u8 control){
if(channel>=4)return 0;
if(channel<2)nav_timbre[(__safe_index u8)channel]=(control&0xCF)|0x30;
else if(channel==2){if(control==0)nav_timbre[2]=0x80;else nav_timbre[2]=0xFF;}
else {if((control&128)!=0)nav_timbre[3]=control&15;else nav_timbre[3]=(control&15)|0x30;}
return 1;
}nes_audio_vblank_pause
Met en pause ou reprend la BGM et les SFX en conservant leurs positions de lecture.
Syntaxe
void nes_audio_vblank_pause(u8 on);Paramètres
onUne valeur non nulle met en pause ; zéro reprend la lecture. La pause désactive immédiatement les quatre canaux de l’APU.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Incluez audio_vblank.h et ajoutez audio_vblank.c à la compilation exactement une fois. Le compilateur appelle son point d’entrée une fois depuis le gestionnaire NMI, qu’il soit standard ou personnalisé. Activez la NMI du PPU. La boucle principale n’appelle pas de routine de mise à jour musicale.
Ce pilote à quatre canaux est réglé pour le NTSC : CH1=impulsion 1, CH2=impulsion 2, CH3=triangle et CH4=bruit, avec des indices de 0 à 3. Il ne gère ni le DMC ni les extensions audio. Ne l’utilisez pas en parallèle avec du code écrivant directement dans l’APU, comme les effets de audio.c. Il ne fournit ni table de fréquences PAL ni correction de tempo pour le PAL.
Appelez cette fonction depuis le programme principal. La NMI consomme les données SFX copiées. Confiez à cette bibliothèque la gestion de la BGM et des SFX ; n’exécutez pas un autre pilote APU en parallèle.
Pendant la pause, ni la durée et la position de file BGM, ni la durée et la position SFX n’avancent. Le programme principal peut toujours remplir la file. La première NMI après la reprise redéclenche les notes en cours et exécute le tick normal. La phase des formes d’onde et le niveau d’une enveloppe déjà partiellement atténuée ne sont pas sauvegardés. L’indicateur d’activation BGM renvoyé par is_playing reste inchangé. Zéro demande la restauration des notes même si la lecture est déjà en cours ; ne l’appelez donc pas à chaque image.
Exemple d’utilisation
nes_audio_vblank_pause(1); // Freeze BGM and SFX, and mute immediately.
phase=3;wait_frames(30); // Refill may copy data; neither timeline advances.
nes_audio_vblank_pause(0); // Restore held notes on the next NMI.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Aucune entrée n’est nécessaire. CH1 joue la BGM autour de 220 Hz, passe à un SFX autour de 880 Hz pendant 30 images, puis revient à la BGM courante. Après une pause silencieuse de 30 images, la BGM reprend. Un deuxième effet est interrompu explicitement après 15 images. Enfin, le bruit CH4 décroît lentement une fois. COMPLETE / ALL CHANNELS OFF indique la fin. Écoutez l’enregistrement joint pour vérifier les changements de hauteur, la pause silencieuse et la décroissance du bruit.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank_effects.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank_effects.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio_vblank.h:54
Any nonzero argument freezes both timelines and mutes immediately. Zero resumes from the stored delays and restores held notes on the next NMI. BGM is_playing remains enabled during pause. Refill may still fill the queue.
kitaqfc/lib/audio_vblank.c:40
void nes_audio_vblank_pause(u8 on){
if(on!=0){nav_paused=1;nav_status=0;}
else{nav_refresh=1;nav_paused=0;}
}nes_audio_vblank_play_sfx
Copie un effet court en RAM et prend temporairement le contrôle des sorties des canaux sélectionnés à partir de la prochaine NMI.
Syntaxe
u8 nes_audio_vblank_play_sfx(const u8* records,u8 count,u8 mask);Paramètres
recordsDébut des enregistrements de cinq octets. Gardez les count×5 octets lisibles et mappés jusqu’au retour de l’appel. La source peut être réutilisée après la copie.
countDe 1 à 7 enregistrements, soit 35 octets au maximum. Chaque durée doit être comprise entre 1 et 255. Les SFX n’utilisent pas de terminateur de durée zéro ; ils se terminent après le nombre d’enregistrements indiqué.
maskLes quatre bits de poids faible sélectionnent les canaux : 1=CH1, 2=CH2, 4=CH3, 8=CH4. Combinez les bits par un OU pour en sélectionner plusieurs. Les bits de poids fort sont ignorés ; un masque nul sur les quatre bits de poids faible est refusé.
Valeur renvoyée
Renvoie 1 après avoir copié et activé l’effet. Renvoie 0 pour un pointeur nul, un nombre invalide, aucune sélection de canal, une durée nulle ou des valeurs de note ou de bruit invalides. Une entrée invalide laisse l’effet actuel inchangé. Les valeurs des canaux non sélectionnés sont également vérifiées.
Conditions et limites
Incluez audio_vblank.h et ajoutez audio_vblank.c à la compilation exactement une fois. Le compilateur appelle son point d’entrée une fois depuis le gestionnaire NMI, qu’il soit standard ou personnalisé. Activez la NMI du PPU. La boucle principale n’appelle pas de routine de mise à jour musicale.
Ce pilote à quatre canaux est réglé pour le NTSC : CH1=impulsion 1, CH2=impulsion 2, CH3=triangle et CH4=bruit, avec des indices de 0 à 3. Il ne gère ni le DMC ni les extensions audio. Ne l’utilisez pas en parallèle avec du code écrivant directement dans l’APU, comme les effets de audio.c. Il ne fournit ni table de fréquences PAL ni correction de tempo pour le PAL.
Appelez cette fonction depuis le programme principal. La NMI consomme les données SFX copiées. Confiez à cette bibliothèque la gestion de la BGM et des SFX ; n’exécutez pas un autre pilote APU en parallèle.
La BGM continue d’avancer en arrière-plan ; à la fin de l’effet, les sorties reviennent à ses notes actuelles. Il n’existe qu’un flux SFX, remplacé à chaque nouvel appel. Les valeurs HOLD/STOP sont les mêmes que pour la BGM, mais les notes mémorisées d’un effet sont initialement arrêtées : un HOLD initial ne reprend donc pas la note BGM. Un SFX peut jouer sans BGM. Un effet ajouté pendant une pause attend la reprise. Les timbres sont partagés avec la BGM.
Exemple d’utilisation
result[1]=nes_audio_vblank_play_sfx(effect,1,1); // Mask bit 0 owns CH1.
// The BGM timeline keeps advancing; its current CH1 note returns after 30 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
Aucune entrée n’est nécessaire. CH1 joue la BGM autour de 220 Hz, passe à un SFX autour de 880 Hz pendant 30 images, puis revient à la BGM courante. Après une pause silencieuse de 30 images, la BGM reprend. Un deuxième effet est interrompu explicitement après 15 images. Enfin, le bruit CH4 décroît lentement une fois. COMPLETE / ALL CHANNELS OFF indique la fin. Écoutez l’enregistrement joint pour vérifier les changements de hauteur, la pause silencieuse et la décroissance du bruit.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank_effects.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank_effects.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio_vblank.h:62
Copy 1..7 timed records. Bits 0..3 select channels temporarily owned by SFX. BGM continues underneath and its current notes return when the effect ends. Return 1 after copying; 0 for null, invalid count/data or an empty low mask. Ignore mask bits 4..7. All fields are validated, even unselected channels. Delay zero is not accepted for SFX. Invalid input preserves the current SFX. Replacement restarts the effect; the first HOLD starts from a stopped note. The source need only stay mapped/readable until this foreground call returns.
kitaqfc/lib/audio_vblank.c:47
u8 nes_audio_vblank_play_sfx(const u8* records,u8 count,u8 mask){
u8 i;u8 ch;u8 value;u8 bytes;
if(records==0||count==0||count>7||(mask&15)==0)return 0;
bytes=(u8)(count+count+count+count+count);
i=0;
while(i<bytes){
if(records[i]==0)return 0;
ch=1;while(ch<5){
value=records[i+ch];
if(value<254){if(ch<4){if(value>71)return 0;}else{if(value>31)return 0;}}
ch++;
}
i=i+5;
}
nav_sfx_active=0;
for(i=0;i<bytes;i++)nav_sfx_queue[(__safe_index u8)i]=records[i];
for(i=0;i<4;i++)nav_sfx_notes[(__safe_index u8)i]=254;
nav_sfx_mask=mask&15;nav_sfx_cursor=0;nav_sfx_length=bytes;nav_sfx_delay=0;
nav_sfx_active=1;return 1;
}nes_audio_vblank_stop_sfx
Libère les canaux contrôlés par l’effet pour que la prochaine NMI restaure les notes BGM actuelles.
Syntaxe
void nes_audio_vblank_stop_sfx(void);Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Incluez audio_vblank.h et ajoutez audio_vblank.c à la compilation exactement une fois. Le compilateur appelle son point d’entrée une fois depuis le gestionnaire NMI, qu’il soit standard ou personnalisé. Activez la NMI du PPU. La boucle principale n’appelle pas de routine de mise à jour musicale.
Ce pilote à quatre canaux est réglé pour le NTSC : CH1=impulsion 1, CH2=impulsion 2, CH3=triangle et CH4=bruit, avec des indices de 0 à 3. Il ne gère ni le DMC ni les extensions audio. Ne l’utilisez pas en parallèle avec du code écrivant directement dans l’APU, comme les effets de audio.c. Il ne fournit ni table de fréquences PAL ni correction de tempo pour le PAL.
Appelez cette fonction depuis le programme principal. La NMI consomme les données SFX copiées. Confiez à cette bibliothèque la gestion de la BGM et des SFX ; n’exécutez pas un autre pilote APU en parallèle.
Cet appel n’écrit pas dans les registres APU. Il conserve la file, la position et l’état d’activation BGM. Si un SFX jouait seul, la prochaine NMI remet les canaux à l’état de notes arrêtées. Pendant une pause, le changement prend effet à la reprise. Utilisez stop pour couper immédiatement le son et supprimer les deux positions de lecture.
Exemple d’utilisation
nes_audio_vblank_stop_sfx(); // Release effect ownership at the next NMI.
// BGM continues at its current position; this does not restart the song.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Aucune entrée n’est nécessaire. CH1 joue la BGM autour de 220 Hz, passe à un SFX autour de 880 Hz pendant 30 images, puis revient à la BGM courante. Après une pause silencieuse de 30 images, la BGM reprend. Un deuxième effet est interrompu explicitement après 15 images. Enfin, le bruit CH4 décroît lentement une fois. COMPLETE / ALL CHANNELS OFF indique la fin. Écoutez l’enregistrement joint pour vérifier les changements de hauteur, la pause silencieuse et la décroissance du bruit.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio_vblank.c .\kitaq-docs\samples\api-examples\fc\audio_vblank_effects.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr -o .\out\audio_vblank_effects.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/audio_vblank.h:65
Release effect ownership at the next NMI, restoring current BGM notes. This does not stop or restart the BGM and does not write the APU immediately.
kitaqfc/lib/audio_vblank.c:44
void nes_audio_vblank_stop_sfx(void){nav_sfx_active=0;}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 FC utilise les banques logiques MMC3 : la banque 0 contient le code commun en $C000–$FFFF et la banque sélectionnée de 16 KiB apparaît en $8000–$BFFF. Ce sont les numéros du compilateur, pas les valeurs brutes des registres de 8 KiB du mapper. Initialisez l’état de la bibliothèque avec bank_switch. Sur FC, far_call est une macro d’appel par nom ; transmettez la banque de la fonction, de préférence obtenue avec __bankof.
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(void);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 02 : la macro far_call et __farcall invoquent chacun le rappel une fois.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\banked_data_calls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/bank.h:18
Read this wrapper's bank shadow; arbitrary mapper writes do not update it.
kitaqfc/lib/bank.c:14
u8 bank_get_current(void)
{
return kq_bank_current;
}bank_switch
Enregistre la banque demandée dans la bibliothèque, puis la sélectionne avec la routine PRG du compilateur adaptée au mapper.
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.
Les banques FC sont des numéros logiques du compilateur. Zéro désigne la ROM commune, pas une cible de commutation ; la routine le ramène à la banque 1. SUROM512 accepte 1–30 : une constante hors plage transmise directement à l’intrinsèque de commutation provoque une erreur de compilation ; une valeur d’exécution invalide sélectionne 1 et active l’état de défaut du mapper. Lisez directement la ROM commune, sans demander la banque zéro.
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 02 : la macro far_call et __farcall invoquent chacun le rappel une fois.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\banked_data_calls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/bank.h:16
Record the bank in the library shadow and invoke the mapper-aware compiler intrinsic.
kitaqfc/lib/bank.c:7
void bank_switch(u8 bank)
{
kq_bank_current = bank;
__bankswitch(bank);
}far_call
Se développe en __farcall((bank), func). Cette macro conserve la cible sous forme de nom de fonction visible par le compilateur ; il ne s’agit pas d’un appel indirect par pointeur de rappel.
Syntaxe
#define far_call(bank, func) __farcall((bank), 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.
funcNom déclaré d’une fonction sans paramètre. Cet appel intrinsèque par nom n’accepte pas une variable contenant une adresse de fonction. L’argument bank n’est pas transmis au rappel.
Valeur renvoyée
Le résultat suit le type de la fonction appelée. Un rappel void ne renvoie rien ; les rappels u8 et u16 renvoient leur valeur scalaire. L’exemple affiché utilise des rappels 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.
Les banques FC sont des numéros logiques du compilateur. Zéro désigne la ROM commune, pas une cible de commutation ; la routine le ramène à la banque 1. SUROM512 accepte 1–30 : une constante hors plage transmise directement à l’intrinsèque de commutation provoque une erreur de compilation ; une valeur d’exécution invalide sélectionne 1 et active l’état de défaut du mapper. Lisez directement la ROM commune, sans demander la banque zéro.
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 02 : la macro far_call et __farcall invoquent chacun le rappel une fois.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\banked_data_calls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/bank.h:36
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.
Les banques FC sont des numéros logiques du compilateur. Zéro désigne la ROM commune, pas une cible de commutation ; la routine le ramène à la banque 1. SUROM512 accepte 1–30 : une constante hors plage transmise directement à l’intrinsèque de commutation provoque une erreur de compilation ; une valeur d’exécution invalide sélectionne 1 et active l’état de défaut du mapper. Lisez directement la ROM commune, sans demander la banque zéro.
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 02 : la macro far_call et __farcall invoquent chacun le rappel une fois.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\banked_data_calls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/bank.h:24
Copy len bytes from banked ROM to caller-owned writable storage.
kitaqfc/lib/bank.c:32
void far_data_read(u8 bank, const void* addr, void* dst, u16 len)
{
__far_memcpy((u8*)dst, bank, (u16)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.
Les banques FC sont des numéros logiques du compilateur. Zéro désigne la ROM commune, pas une cible de commutation ; la routine le ramène à la banque 1. SUROM512 accepte 1–30 : une constante hors plage transmise directement à l’intrinsèque de commutation provoque une erreur de compilation ; une valeur d’exécution invalide sélectionne 1 et active l’état de défaut du mapper. Lisez directement la ROM commune, sans demander la banque zéro.
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 02 : la macro far_call et __farcall invoquent chacun le rappel une fois.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\banked_data_calls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/bank.h:22
Read a 16-bit value through the bank-aware compiler intrinsic.
kitaqfc/lib/bank.c:26
u16 far_data_read16(u8 bank, const void* addr)
{
return __farpeek16(bank, (u16)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.
Les banques FC sont des numéros logiques du compilateur. Zéro désigne la ROM commune, pas une cible de commutation ; la routine le ramène à la banque 1. SUROM512 accepte 1–30 : une constante hors plage transmise directement à l’intrinsèque de commutation provoque une erreur de compilation ; une valeur d’exécution invalide sélectionne 1 et active l’état de défaut du mapper. Lisez directement la ROM commune, sans demander la banque zéro.
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 02 : la macro far_call et __farcall invoquent chacun le rappel une fois.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\banked_data_calls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/bank.h:20
Read one byte from an explicit ROM bank and 16-bit CPU address.
kitaqfc/lib/bank.c:20
u8 far_data_read8(u8 bank, const void* addr)
{
return __farpeek8(bank, (u16)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 02 : la macro far_call et __farcall invoquent chacun le rappel une fois.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\banked_data_calls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/bank.h:26
Store a bank/address pair without reading memory; null output is ignored.
kitaqfc/lib/bank.c:38
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.
Les banques FC sont des numéros logiques du compilateur. Zéro désigne la ROM commune, pas une cible de commutation ; la routine le ramène à la banque 1. SUROM512 accepte 1–30 : une constante hors plage transmise directement à l’intrinsèque de commutation provoque une erreur de compilation ; une valeur d’exécution invalide sélectionne 1 et active l’état de défaut du mapper. Lisez directement la ROM commune, sans demander la banque zéro.
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 02 : la macro far_call et __farcall invoquent chacun le rappel une fois.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\banked_data_calls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/bank.h:32
Copy len bytes from a far pointer; the caller provides a sufficiently large destination.
kitaqfc/lib/bank.c:58
void farptr_read(BankPtr ptr, void* dst, u16 len)
{
__far_memcpy((u8*)dst, ptr.bank, (u16)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.
Les banques FC sont des numéros logiques du compilateur. Zéro désigne la ROM commune, pas une cible de commutation ; la routine le ramène à la banque 1. SUROM512 accepte 1–30 : une constante hors plage transmise directement à l’intrinsèque de commutation provoque une erreur de compilation ; une valeur d’exécution invalide sélectionne 1 et active l’état de défaut du mapper. Lisez directement la ROM commune, sans demander la banque zéro.
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 02 : la macro far_call et __farcall invoquent chacun le rappel une fois.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\banked_data_calls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/bank.h:30
Read a 16-bit value using both components of the far pointer.
kitaqfc/lib/bank.c:52
u16 farptr_read16(BankPtr ptr)
{
return __farpeek16(ptr.bank, (u16)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.
Les banques FC sont des numéros logiques du compilateur. Zéro désigne la ROM commune, pas une cible de commutation ; la routine le ramène à la banque 1. SUROM512 accepte 1–30 : une constante hors plage transmise directement à l’intrinsèque de commutation provoque une erreur de compilation ; une valeur d’exécution invalide sélectionne 1 et active l’état de défaut du mapper. Lisez directement la ROM commune, sans demander la banque zéro.
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 02 : la macro far_call et __farcall invoquent chacun le rappel une fois.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\banked_data_calls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/bank.h:28
Read one byte using both the bank and address of the supplied far pointer.
kitaqfc/lib/bank.c:46
u8 farptr_read8(BankPtr ptr)
{
return __farpeek8(ptr.bank, (u16)ptr.ptr);
}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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\chain_wrap.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\chain_wrap.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/chain.h:39
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.
kitaqfc/lib/chain.c:103
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 (((u16)delta & 0x8000) != 0) {
if ((u16)(0 - delta) > (u16)half) delta = (s16)(delta + (s16)size);
} else if ((u16)delta > (u16)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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\chain_body.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\chain_body.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\chain_body.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/chain.h:57
Attach three non-overlapping capacity-byte arrays. Return 1 on success. Invalid storage, zero capacity or dimensions outside 1..256 disable the body.
kitaqfc/lib/chain.c:127
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\chain_body.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\chain_body.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\chain_body.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/chain.h:61
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.
kitaqfc/lib/chain.c:143
u8 chain_body_reset(ChainBody* body, u8 count, u8 head_x, u8 head_y, u8 heading)
{
// Cache caller storage once; following math and old-heading propagation
// use these local values. Avoid decoding packed struct pointers per joint.
u8* coord_x;u8* coord_y;u8* directions;u16 width;u16 height;
u8 i;
u8 x;
u8 y;
s16 ox;
s16 oy;
if (body == 0) return 0;
if (count == 0 || count > body->capacity) return 0;
coord_x=body->x;coord_y=body->y;directions=body->heading;
width=body->width;height=body->height;
heading = (u8)(heading & 15);
x = chain_body_wrap((s16)head_x, width);
y = chain_body_wrap((s16)head_y, height);
ox = chain_body_offset_x(heading);
oy = chain_body_offset_y(heading);
i = 0;
while (i < count) {
coord_x[(__safe_index u8)i] = x;
coord_y[(__safe_index u8)i] = y;
directions[(__safe_index u8)i] = heading;
x = chain_body_wrap((s16)((s16)x - ox), width);
y = chain_body_wrap((s16)((s16)y - oy), 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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\chain_body.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\chain_body.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\chain_body.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/chain.h:66
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.
kitaqfc/lib/chain.c:175
void chain_body_step(ChainBody* body, u8 head_x, u8 head_y, u8 heading)
{
// Cache caller storage once; following math and old-heading propagation
// use these local values. Avoid decoding packed struct pointers per joint.
u8* coord_x;u8* coord_y;u8* directions;u16 width;u16 height;
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;
coord_x=body->x;coord_y=body->y;directions=body->heading;
width=body->width;height=body->height;
heading = (u8)(heading & 15);
coord_x[0] = chain_body_wrap((s16)head_x, width);
coord_y[0] = chain_body_wrap((s16)head_y, height);
directions[0] = heading;
pull = heading;
i = 1;
while (i < body->count) {
previous = (u8)(i - 1);
old = directions[(__safe_index u8)i];
x = coord_x[(__safe_index u8)i];
y = coord_y[(__safe_index u8)i];
tx = chain_body_wrap((s16)((s16)coord_x[(__safe_index u8)previous] - chain_body_offset_x(pull)), width);
ty = chain_body_wrap((s16)((s16)coord_y[(__safe_index u8)previous] - chain_body_offset_y(pull)), height);
sx = chain_body_correction(chain_wrap_delta(tx, x, width));
sy = chain_body_correction(chain_wrap_delta(ty, y, height));
directions[(__safe_index u8)i] = pull;
coord_x[(__safe_index u8)i] = chain_body_wrap((s16)((s16)x + sx), width);
coord_y[(__safe_index u8)i] = chain_body_wrap((s16)((s16)y + sy), 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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\chain_body.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\chain_body.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\chain_body.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/chain.h:69
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.
kitaqfc/lib/chain.c:218
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\chain_body.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\chain_body.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\chain_body.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/chain.h:71
Remove all joints while retaining caller-owned storage and playfield settings.
kitaqfc/lib/chain.c:233
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 FC ne fait rien si chain == 0.
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_chain.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_chain.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/chain.h:24
Forget the recorded points without clearing or freeing the backing storage.
kitaqfc/lib/chain.c:16
void chain_clear(Chain* chain)
{
if (chain == 0) return;
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_chain.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_chain.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/chain.h:33
Return the number of stored points, or zero for a null chain.
kitaqfc/lib/chain.c:66
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_chain.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_chain.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/chain.h:31
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.
kitaqfc/lib/chain.c:42
u8 chain_get_segment(const Chain* chain, u8 index, ChainPoint* out)
{
u8 pos;
// Do not alias out with the backing ring: it is cleared before the requested point is read.
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[(__safe_index u8)pos].x;
out->y = chain->points[(__safe_index u8)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 FC ne fait rien si chain == 0.
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_chain.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_chain.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/chain.h:22
Attach caller-owned ring storage and start with no recorded points. The storage must remain valid for the lifetime of the chain.
kitaqfc/lib/chain.c:5
void chain_init(Chain* chain, ChainPoint* storage, u8 capacity)
{
if (chain == 0) return;
// A nonzero capacity requires writable storage for that many complete ChainPoint records.
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_chain.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_chain.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/chain.h:27
Move the ring head backward and store the newest point. Once full, each push replaces the oldest point; zero capacity is a no-op.
kitaqfc/lib/chain.c:25
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 = (u8)(chain->head - 1);
chain->points[(__safe_index u8)chain->head].x = x;
chain->points[(__safe_index u8)chain->head].y = y;
if (chain->count < chain->capacity) chain->count = (u8)(chain->count + 1);
}collision.h — Tests de collision rectangulaire et autres formes
Teste les intersections rectangle/rectangle et rectangle/point dans les coordonnées du monde FC, avec des positions non signées sur 16 bits.
nes_box16_contains_point
Teste si un point appartient à un rectangle FC, bords gauche et supérieur inclus, bords droit et inférieur exclus.
Syntaxe
unsigned char nes_box16_contains_point(struct NesBox16* box, unsigned short px, unsigned short py);Paramètres
boxNesBox16accessible en lecture ; ne passez pas de pointeur nul.pxCoordonnée X du point, sur 16 bits non signés.
pyCoordonnée Y du point, sur 16 bits non signés.
Valeur renvoyée
Renvoie 1 à l’intérieur, 0 à l’extérieur.
Conditions et limites
x, y sont des coordonnées non signées sur 16 bits ; la largeur et la hauteur tiennent chacune sur un octet. Utilisez des dimensions positives et limitez à 65535 la somme de chaque coordonnée et de sa dimension. Les rectangles franchissant le rebouclage des coordonnées ne sont pas pris en charge.
Exemple d’utilisation
result[6]=nes_box16_contains_point(&na,9,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
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_geometry.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_geometry.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/collision.h:18
Test a half-open box: left/top edges are included and right/bottom edges excluded. Callers provide valid pointers and non-overflowing edge coordinates.
kitaqfc/lib/collision.c:49
unsigned char nes_box16_contains_point(struct NesBox16* box, unsigned short px, unsigned short py)
{
unsigned short right;
unsigned short bottom;
right = (unsigned short)(box->x + box->w);
bottom = (unsigned short)(box->y + box->h);
if (px < box->x)
{
return 0;
}
if (py < box->y)
{
return 0;
}
if (px >= right)
{
return 0;
}
if (py >= bottom)
{
return 0;
}
return 1;
}nes_box16_intersects
Teste si deux rectangles FC passés par pointeur se chevauchent sur une surface non nulle.
Syntaxe
unsigned char nes_box16_intersects(struct NesBox16* a, struct NesBox16* b);Paramètres
aPremier
NesBox16accessible en lecture ; ne passez pas de pointeur nul.bSecond
NesBox16accessible en lecture.
Valeur renvoyée
Renvoie 1 en cas de chevauchement, 0 si les rectangles sont séparés ou ne se touchent que par les bords.
Conditions et limites
x, y sont des coordonnées non signées sur 16 bits ; la largeur et la hauteur tiennent chacune sur un octet. Utilisez des dimensions positives et limitez à 65535 la somme de chaque coordonnée et de sa dimension. Les rectangles franchissant le rebouclage des coordonnées ne sont pas pris en charge.
Exemple d’utilisation
result[5]=nes_box16_intersects(&na,&nb);Cet extrait montre l’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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_geometry.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_geometry.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/collision.h:15
Test two axis-aligned world boxes using exclusive right/bottom edges. Coordinate-plus-size sums must fit u16; touching edges return false. Both boxes must have positive dimensions; the overlap test has no separate empty-box guard.
kitaqfc/lib/collision.c:15
unsigned char nes_box16_intersects(struct NesBox16* a, struct NesBox16* b)
{
unsigned short a_right;
unsigned short b_right;
unsigned short a_bottom;
unsigned short b_bottom;
a_right = (unsigned short)(a->x + a->w);
b_right = (unsigned short)(b->x + b->w);
a_bottom = (unsigned short)(a->y + a->h);
b_bottom = (unsigned short)(b->y + b->h);
if (a_right <= b->x)
{
return 0;
}
if (b_right <= a->x)
{
return 0;
}
if (a_bottom <= b->y)
{
return 0;
}
if (b_bottom <= a->y)
{
return 0;
}
return 1;
}danmaku — Pool de 64 projectiles
danmaku est un pool de 64 projectiles en virgule fixe. Initialisez-le, créez des projectiles, appelez step pour les déplacements et les collisions, puis draw pour construire l’OAM, et effectuez le DMA pendant le VBlank. Gérez les entrées du joueur, les dégâts, le score et l’audio dans le code du jeu. L’exemple transfère une tuile originale en losange dans la CHR RAM ; la bibliothèque peut aussi utiliser des sprites en CHR ROM.
danmaku_reset
Désactive tous les projectiles et réinitialise les événements d’impact et de frôlement, les compteurs maximum et cumulés ainsi que les curseurs d’allocation et d’ordre de dessin.
Syntaxe
void danmaku_reset(void);Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
La position du joueur et dm_invulnerable sont conservés. L’OAM et l’affichage ne sont pas effacés : dessinez le pool vide puis effectuez un DMA, ou masquez séparément les entrées OAM, pour faire disparaître les projectiles visibles.
Réservez la plage $6000–$627F (640 octets) de PRG RAM inscriptible de la cartouche pour 64 projectiles. Activez cette RAM dans le mapper de la cartouche. L’état partagé rend cette bibliothèque non réentrante.
dm_count est le nombre de projectiles actifs et dm_peak le maximum atteint. Les compteurs 16 bits dm_spawned et dm_rejected enregistrent les créations réussies et échouées ; ils reviennent à zéro après 65535. dm_x et dm_y sont les coordonnées du centre ; ignorez-les lorsque dm_active vaut zéro.
KUROSAKI vérifie, avec quatre configurations du compilateur, tous les pixels, le nombre et la position des projectiles, l’OAM réservée et la rotation de l’ordre de dessin. Des vérifications numériques distinctes couvrent les impacts, les frôlements, la suppression hors écran et le pool plein. Aucun test sur matériel réel n’a été effectué.
Exemple d’utilisation
danmaku_reset();Cet extrait montre l’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 quatre projectiles jaunes à gauche se sont déplacés de 16 pixels dans les quatre directions cardinales depuis (48,64). Les seize projectiles jaunes à droite forment un anneau à environ 32 pixels de (160,104). Le joueur cyan en (112,192) utilise l’emplacement OAM zéro qui lui est réservé. Cet exemple conserve l’image obtenue après seize mises à jour de la logique.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\danmaku_patterns.c -I .\kitaqfc\lib --mapper=nrom --nes-chr-ram -o .\out\danmaku_patterns.nes --no-cache --no-disasm
.\kurosaki\kurosaki.exe run .\out\danmaku_patterns.nes --headless --frames 180 --png .\out\danmaku_patterns.pngImplémentation et source
kitaqfc/lib/danmaku.h:26
Reset the pool, counters and rotating OAM priority. Player settings survive.
kitaqfc/lib/danmaku.c:40
void danmaku_reset(void) {
danmaku_clear();
dm_peak=0;dm_spawned=0;dm_rejected=0;dm_cursor=0;dm_draw_phase=0;
}danmaku_clear
Désactive tous les projectiles et remet dm_count, dm_hit et dm_graze à zéro. Utilisez cette fonction pour supprimer les projectiles pendant la partie.
Syntaxe
void danmaku_clear(void);Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Conserve dm_peak, dm_spawned, dm_rejected, les curseurs d’allocation et d’ordre de dessin ainsi que les réglages du joueur. L’exemple crée un projectile puis le supprime : le nombre actif devient nul, tandis que le total des créations reste à un. Mettez l’OAM à jour séparément.
Réservez la plage $6000–$627F (640 octets) de PRG RAM inscriptible de la cartouche pour 64 projectiles. Activez cette RAM dans le mapper de la cartouche. L’état partagé rend cette bibliothèque non réentrante.
dm_count est le nombre de projectiles actifs et dm_peak le maximum atteint. Les compteurs 16 bits dm_spawned et dm_rejected enregistrent les créations réussies et échouées ; ils reviennent à zéro après 65535. dm_x et dm_y sont les coordonnées du centre ; ignorez-les lorsque dm_active vaut zéro.
KUROSAKI vérifie, avec quatre configurations du compilateur, tous les pixels, le nombre et la position des projectiles, l’OAM réservée et la rotation de l’ordre de dessin. Des vérifications numériques distinctes couvrent les impacts, les frôlements, la suppression hors écran et le pool plein. Aucun test sur matériel réel n’a été effectué.
Exemple d’utilisation
danmaku_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
Les quatre projectiles jaunes à gauche se sont déplacés de 16 pixels dans les quatre directions cardinales depuis (48,64). Les seize projectiles jaunes à droite forment un anneau à environ 32 pixels de (160,104). Le joueur cyan en (112,192) utilise l’emplacement OAM zéro qui lui est réservé. Cet exemple conserve l’image obtenue après seize mises à jour de la logique.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\danmaku_patterns.c -I .\kitaqfc\lib --mapper=nrom --nes-chr-ram -o .\out\danmaku_patterns.nes --no-cache --no-disasm
.\kurosaki\kurosaki.exe run .\out\danmaku_patterns.nes --headless --frames 180 --png .\out\danmaku_patterns.pngImplémentation et source
kitaqfc/lib/danmaku.h:28
Remove all bullets and step events; preserve lifetime/peak counters.
kitaqfc/lib/danmaku.c:35
void danmaku_clear(void) {
u8 i;
for(i=0;i<64;i++)dm_active[i]=0;
dm_count=0;dm_hit=0;dm_graze=0;
}danmaku_spawn
Recherche cycliquement un emplacement libre dans le pool et initialise sa position, sa vitesse et son état non encore frôlé. La création seule ne déplace pas le projectile et ne teste aucune collision.
Syntaxe
u8 danmaku_spawn(u8 x, u8 y, s8 vx, s8 vy);Paramètres
xCoordonnée horizontale du centre, en pixels ; valeurs admises de 8 à 247.
yCoordonnée verticale du centre, en pixels ; valeurs admises de 24 à 231.
vxVitesse horizontale en Q4.4 signé. La valeur 16 déplace d’un pixel par mise à jour ; −16 déplace d’un pixel en sens inverse. Les valeurs −128 à 127 représentent −8 à +7,9375 pixels.
vyVitesse verticale en Q4.4 signé. La valeur 16 déplace d’un pixel par mise à jour ; −16 déplace d’un pixel en sens inverse. Les valeurs −128 à 127 représentent −8 à +7,9375 pixels.
Valeur renvoyée
Renvoie 1 en cas de succès, ou 0 si la position est invalide ou si les 64 emplacements sont occupés. Un succès incrémente dm_count et dm_spawned et met dm_peak à jour si nécessaire ; un échec incrémente dm_rejected.
Conditions et limites
Réservez la plage $6000–$627F (640 octets) de PRG RAM inscriptible de la cartouche pour 64 projectiles. Activez cette RAM dans le mapper de la cartouche. L’état partagé rend cette bibliothèque non réentrante.
dm_count est le nombre de projectiles actifs et dm_peak le maximum atteint. Les compteurs 16 bits dm_spawned et dm_rejected enregistrent les créations réussies et échouées ; ils reviennent à zéro après 65535. dm_x et dm_y sont les coordonnées du centre ; ignorez-les lorsque dm_active vaut zéro.
KUROSAKI vérifie, avec quatre configurations du compilateur, tous les pixels, le nombre et la position des projectiles, l’OAM réservée et la rotation de l’ordre de dessin. Des vérifications numériques distinctes couvrent les impacts, les frôlements, la suppression hors écran et le pool plein. Aucun test sur matériel réel n’a été effectué.
Exemple d’utilisation
danmaku_spawn(48,64,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 quatre projectiles jaunes à gauche se sont déplacés de 16 pixels dans les quatre directions cardinales depuis (48,64). Les seize projectiles jaunes à droite forment un anneau à environ 32 pixels de (160,104). Le joueur cyan en (112,192) utilise l’emplacement OAM zéro qui lui est réservé. Cet exemple conserve l’image obtenue après seize mises à jour de la logique.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\danmaku_patterns.c -I .\kitaqfc\lib --mapper=nrom --nes-chr-ram -o .\out\danmaku_patterns.nes --no-cache --no-disasm
.\kurosaki\kurosaki.exe run .\out\danmaku_patterns.nes --headless --frames 180 --png .\out\danmaku_patterns.pngImplémentation et source
kitaqfc/lib/danmaku.h:31
Allocate a bullet at pixel-center x/y with signed 1/16-pixel velocities. Return one on success, zero outside the playfield or when all 64 slots are full.
kitaqfc/lib/danmaku.c:44
u8 danmaku_spawn(u8 x,u8 y,s8 vx,s8 vy) {
u8 i,n;
if(x<8 || x>=248 || y<24 || y>=232){dm_rejected++;return 0;}
i=dm_cursor;
for(n=0;n<64;n++) {
if(dm_active[i]==0) {
dm_x[i]=x;dm_y[i]=y;dm_fraction_x[i]=0;dm_fraction_y[i]=0;
// Expand signed Q4.4 to a two-byte two's-complement Q8.8 step.
dm_vx_integer[i]=(u8)((s16)vx>>4);dm_vx_fraction[i]=(u8)((u8)vx<<4);
dm_vy_integer[i]=(u8)((s16)vy>>4);dm_vy_fraction[i]=(u8)((u8)vy<<4);
dm_grazed[i]=0;dm_active[i]=1;dm_cursor=(u8)((i+1)&63);
dm_count++;if(dm_count>dm_peak)dm_peak=dm_count;
dm_spawned++;return 1;
}
i=(u8)((i+1)&63);
}
dm_rejected++;return 0;
}danmaku_fan
Crée des projectiles en faisant avancer la direction d’un pas fixe. Le pas et le nombre permettent de former un éventail ou un anneau complet.
Syntaxe
void danmaku_fan(u8 x, u8 y, u8 direction, u8 step, u8 count, u8 speed);Paramètres
xCoordonnée horizontale du centre, en pixels ; valeurs admises de 8 à 247.
yCoordonnée verticale du centre, en pixels ; valeurs admises de 24 à 231.
directionDirection initiale sur 32 pas par tour : 0 vers la droite, 8 vers le bas, 16 vers la gauche et 24 vers le haut. Seuls les cinq bits de poids faible sont utilisés.
stepIncrément de direction après chaque projectile, avec retour modulo 32. Zéro envoie tous les projectiles dans la même direction.
countNombre de tentatives de création. Les valeurs supérieures à 64 sont limitées à 64 ; zéro ne fait rien.
speedNorme de la vitesse, en seizièmes de pixel par mise à jour : 16 vaut un pixel et 32 en vaut deux. Les valeurs supérieures à 64 sont limitées à 64.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Les vitesses proviennent d’une table de sinus entière et sont tronquées vers zéro ; les vitesses diagonales et les rayons sont donc quantifiés. Un pool plein n’annule pas les tentatives restantes : chaque échec incrémente dm_rejected.
Réservez la plage $6000–$627F (640 octets) de PRG RAM inscriptible de la cartouche pour 64 projectiles. Activez cette RAM dans le mapper de la cartouche. L’état partagé rend cette bibliothèque non réentrante.
dm_count est le nombre de projectiles actifs et dm_peak le maximum atteint. Les compteurs 16 bits dm_spawned et dm_rejected enregistrent les créations réussies et échouées ; ils reviennent à zéro après 65535. dm_x et dm_y sont les coordonnées du centre ; ignorez-les lorsque dm_active vaut zéro.
KUROSAKI vérifie, avec quatre configurations du compilateur, tous les pixels, le nombre et la position des projectiles, l’OAM réservée et la rotation de l’ordre de dessin. Des vérifications numériques distinctes couvrent les impacts, les frôlements, la suppression hors écran et le pool plein. Aucun test sur matériel réel n’a été effectué.
Exemple d’utilisation
danmaku_fan(160,104,0,2,16,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
Les quatre projectiles jaunes à gauche se sont déplacés de 16 pixels dans les quatre directions cardinales depuis (48,64). Les seize projectiles jaunes à droite forment un anneau à environ 32 pixels de (160,104). Le joueur cyan en (112,192) utilise l’emplacement OAM zéro qui lui est réservé. Cet exemple conserve l’image obtenue après seize mises à jour de la logique.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\danmaku_patterns.c -I .\kitaqfc\lib --mapper=nrom --nes-chr-ram -o .\out\danmaku_patterns.nes --no-cache --no-disasm
.\kurosaki\kurosaki.exe run .\out\danmaku_patterns.nes --headless --frames 180 --png .\out\danmaku_patterns.pngImplémentation et source
kitaqfc/lib/danmaku.h:34
Emit up to 64 bullets. Angles wrap in 32 steps: 0 right, 8 down, 16 left, 24 up. Speed is in 1/16 pixel, clamped to 64. Each failed allocation counts.
kitaqfc/lib/danmaku.c:62
void danmaku_fan(u8 x,u8 y,u8 direction,u8 step,u8 count,u8 speed) {
u8 i,angle;s16 vx,vy;
if(count>64)count=64;if(speed>64)speed=64;
angle=(u8)(direction&31);
for(i=0;i<count;i++) {
vx=(s16)Danmaku_Sin[(u8)((angle+8)&31)]*(s16)speed;
vy=(s16)Danmaku_Sin[angle]*(s16)speed;
danmaku_spawn(x,y,(s8)(vx/64),(s8)(vy/64));
angle=(u8)((angle+step)&31);
}
}danmaku_step
Fait avancer chaque projectile actif une fois, supprime ceux qui sortent de l’écran et évalue les impacts et frôlements du joueur. Le temps des projectiles avance au rythme des appels, pas selon le temps réel écoulé.
Syntaxe
void danmaku_step(void);Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Avant l’appel, affectez les coordonnées du centre du joueur à dm_player_x et dm_player_y. Après le déplacement, une distance d’au plus trois pixels sur chacun des deux axes compte comme un impact. Si dm_invulnerable vaut zéro, dm_hit passe à un et le projectile est supprimé ; l’invulnérabilité le laisse actif.
En dehors de la zone d’impact, une distance d’au plus onze pixels sur chaque axe produit un frôlement par projectile. dm_hit et dm_graze sont remis à zéro à l’entrée et ne décrivent que cette mise à jour. Un projectile dans la zone d’impact alors que le joueur est invulnérable ne compte pas comme un frôlement.
Cette fonction n’écrit pas dans l’OAM et n’appelle aucun rappel de dégâts ou de son. Lisez dm_hit et dm_graze pour mettre à jour l’état du joueur ou le score dans le code du jeu.
Réservez la plage $6000–$627F (640 octets) de PRG RAM inscriptible de la cartouche pour 64 projectiles. Activez cette RAM dans le mapper de la cartouche. L’état partagé rend cette bibliothèque non réentrante.
dm_count est le nombre de projectiles actifs et dm_peak le maximum atteint. Les compteurs 16 bits dm_spawned et dm_rejected enregistrent les créations réussies et échouées ; ils reviennent à zéro après 65535. dm_x et dm_y sont les coordonnées du centre ; ignorez-les lorsque dm_active vaut zéro.
KUROSAKI vérifie, avec quatre configurations du compilateur, tous les pixels, le nombre et la position des projectiles, l’OAM réservée et la rotation de l’ordre de dessin. Des vérifications numériques distinctes couvrent les impacts, les frôlements, la suppression hors écran et le pool plein. Aucun test sur matériel réel n’a été effectué.
Exemple d’utilisation
danmaku_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
Les quatre projectiles jaunes à gauche se sont déplacés de 16 pixels dans les quatre directions cardinales depuis (48,64). Les seize projectiles jaunes à droite forment un anneau à environ 32 pixels de (160,104). Le joueur cyan en (112,192) utilise l’emplacement OAM zéro qui lui est réservé. Cet exemple conserve l’image obtenue après seize mises à jour de la logique.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\danmaku_patterns.c -I .\kitaqfc\lib --mapper=nrom --nes-chr-ram -o .\out\danmaku_patterns.nes --no-cache --no-disasm
.\kurosaki\kurosaki.exe run .\out\danmaku_patterns.nes --headless --frames 180 --png .\out\danmaku_patterns.pngImplémentation et source
kitaqfc/lib/danmaku.h:38
Move all live bullets once. Remove offscreen/hitting bullets. Hit uses a +/-3-pixel box; graze uses +/-11, once per bullet. Events describe this step. This updates logic only; it neither writes OAM nor calls a game damage handler.
kitaqfc/lib/danmaku.c:73
void danmaku_step(void) {
// Byte arrays let the 6502 move every slot without multiplying a structure
// index. Carry propagates fractional motion into the signed integer step.
__asm {
LDX #0
STX dm_count
STX dm_hit
STX dm_graze
dm_tick_loop:
LDA dm_active,X
BNE dm_tick_live
JMP dm_tick_next
dm_tick_live:
CLC
LDA dm_fraction_x,X
ADC dm_vx_fraction,X
STA dm_fraction_x,X
LDA dm_x,X
ADC dm_vx_integer,X
STA dm_x,X
CMP #8
BCC dm_tick_kill
CMP #248
BCS dm_tick_kill
CLC
LDA dm_fraction_y,X
ADC dm_vy_fraction,X
STA dm_fraction_y,X
LDA dm_y,X
ADC dm_vy_integer,X
STA dm_y,X
CMP #24
BCC dm_tick_kill
CMP #232
BCS dm_tick_kill
// Unsigned absolute distances avoid false collisions across screen wrap.
LDA dm_x,X
SEC
SBC dm_player_x
BCS dm_tick_dx
EOR #255
CLC
ADC #1
dm_tick_dx:
STA dm_distance_x
LDA dm_y,X
SEC
SBC dm_player_y
BCS dm_tick_dy
EOR #255
CLC
ADC #1
dm_tick_dy:
STA dm_distance_y
CMP #4
BCS dm_tick_graze
LDA dm_distance_x
CMP #4
BCS dm_tick_graze
LDA dm_invulnerable
BNE dm_tick_count
LDA #1
STA dm_hit
dm_tick_kill:
LDA #0
STA dm_active,X
JMP dm_tick_next
dm_tick_graze:
LDA dm_grazed,X
BNE dm_tick_count
LDA dm_distance_x
CMP #12
BCS dm_tick_count
LDA dm_distance_y
CMP #12
BCS dm_tick_count
LDA #1
STA dm_grazed,X
INC dm_graze
dm_tick_count:
INC dm_count
dm_tick_next:
INX
CPX #64
BEQ dm_tick_done
JMP dm_tick_loop
dm_tick_done:
}
}danmaku_draw
Construit des sprites 8×8 à partir du centre des projectiles et les écrit dans la plage demandée de l’OAM en RAM, sans déplacer les projectiles ni tester les collisions.
Syntaxe
u8 danmaku_draw(u8 first_oam, u8 slots, u8 tile, u8 attributes);Paramètres
first_oamPremier emplacement OAM (0 à 63). Une valeur à partir de 64 renvoie zéro sans écrire. L’exemple commence à un pour réserver l’emplacement zéro au joueur.
slotsNombre d’emplacements consécutifs disponibles, limité à 64−first_oam. Zéro n’écrit rien, mais fait tout de même avancer la priorité de dessin.
tileTuile de motif 8×8 commune à tous les projectiles. Configurez le mode sprite 8×8 ; cet appel utilise la même forme pour chaque projectile.
attributesAttributs de sprite NES communs à tous les projectiles : bits 0–1 pour la palette, bit 5 pour le placement derrière le fond, bit 6 pour le retournement horizontal et bit 7 pour le retournement vertical.
Valeur renvoyée
Renvoie le nombre de projectiles écrits dans l’OAM : le minimum entre le nombre actif et les emplacements disponibles.
Conditions et limites
Avance le premier emplacement de projectile de 13 modulo 64 à chaque appel, afin que les mêmes projectiles ne soient pas toujours prioritaires. Masque les emplacements inutilisés de la plage demandée avec Y=240, sans modifier l’OAM en dehors de cette plage.
Soustrait quatre au centre X et cinq au centre Y ; le matériel ajoute un à la coordonnée Y de l’OAM, ce qui centre le sprite. Appelez vous-même __oam_dma pendant le VBlank. La limite matérielle de huit sprites par ligne de balayage reste applicable.
Réservez la plage $6000–$627F (640 octets) de PRG RAM inscriptible de la cartouche pour 64 projectiles. Activez cette RAM dans le mapper de la cartouche. L’état partagé rend cette bibliothèque non réentrante.
dm_count est le nombre de projectiles actifs et dm_peak le maximum atteint. Les compteurs 16 bits dm_spawned et dm_rejected enregistrent les créations réussies et échouées ; ils reviennent à zéro après 65535. dm_x et dm_y sont les coordonnées du centre ; ignorez-les lorsque dm_active vaut zéro.
KUROSAKI vérifie, avec quatre configurations du compilateur, tous les pixels, le nombre et la position des projectiles, l’OAM réservée et la rotation de l’ordre de dessin. Des vérifications numériques distinctes couvrent les impacts, les frôlements, la suppression hors écran et le pool plein. Aucun test sur matériel réel n’a été effectué.
Exemple d’utilisation
bullet_result[9]=danmaku_draw(1,24,1,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 quatre projectiles jaunes à gauche se sont déplacés de 16 pixels dans les quatre directions cardinales depuis (48,64). Les seize projectiles jaunes à droite forment un anneau à environ 32 pixels de (160,104). Le joueur cyan en (112,192) utilise l’emplacement OAM zéro qui lui est réservé. Cet exemple conserve l’image obtenue après seize mises à jour de la logique.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\danmaku_patterns.c -I .\kitaqfc\lib --mapper=nrom --nes-chr-ram -o .\out\danmaku_patterns.nes --no-cache --no-disasm
.\kurosaki\kurosaki.exe run .\out\danmaku_patterns.nes --headless --frames 180 --png .\out\danmaku_patterns.pngImplémentation et source
kitaqfc/lib/danmaku.h:43
Write up to slots consecutive shadow-OAM entries starting at first_oam. Rotate bullet priority by 13 modulo 64 and hide unused entries in that range. tile is an 8x8 sprite centered at (4,4). Return the number emitted. DMA is caller-owned and belongs in VBlank. Hardware's eight-per-scanline limit remains.
kitaqfc/lib/danmaku.c:162
u8 danmaku_draw(u8 first_oam,u8 slots,u8 tile,u8 attributes) {
u8 i,n,drawn;
if(first_oam>=64)return 0;
if(slots>(u8)(64-first_oam))slots=(u8)(64-first_oam);
dm_draw_phase=(u8)((dm_draw_phase+13)&63);i=dm_draw_phase;drawn=0;
for(n=0;n<64;n++) {
if(dm_active[i]!=0 && drawn<slots) {
__sprite_set((u8)(first_oam+drawn),(u8)(dm_x[i]-4),(u8)(dm_y[i]-5),tile,attributes);
drawn++;
}
i=(u8)((i+1)&63);
}
for(n=drawn;n<slots;n++)__sprite_hide((u8)(first_oam+n));
return drawn;
}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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/debug.h:36
Store the assertion code even if the log is full, then attempt an ASSERT entry. The helper records failure but does not stop execution.
kitaqfc/lib/debug.c:67
void debug_assert_fail(u16 code)
{
kq_debug_last_assert = code;
debug_push(debug_assert_label, 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(void);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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/debug.h:42
Read the latest assertion code, initially zero after debug_init.
kitaqfc/lib/debug.c:86
u16 debug_get_last_assert(void)
{
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(void);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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/debug.h:38
Read the number of valid entries in the fixed trace buffer.
kitaqfc/lib/debug.c:74
u8 debug_get_trace_count(void)
{
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(void);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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/debug.h:40
Borrow the internal trace array; bound inspection by debug_get_trace_count.
kitaqfc/lib/debug.c:80
const DebugTraceEntry* debug_get_trace_log(void)
{
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(void);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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/debug.h:25
Build the RAM-resident ASSERT label and reset log length, frame tag and last assertion code. Old log storage bytes are not erased.
kitaqfc/lib/debug.c:14
void debug_init(void)
{
debug_assert_label[0] = 'A';
debug_assert_label[1] = 'S';
debug_assert_label[2] = 'S';
debug_assert_label[3] = 'E';
debug_assert_label[4] = 'R';
debug_assert_label[5] = 'T';
debug_assert_label[6] = 0;
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/debug.h:29
Append a named marker with the reserved marker value 0xFFFF.
kitaqfc/lib/debug.c:48
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/debug.h:27
Choose the frame tag stored in subsequent debug entries.
kitaqfc/lib/debug.c:29
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/debug.h:33
Append a 16-bit value with the current frame tag.
kitaqfc/lib/debug.c:60
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/debug.h:31
Widen a byte value into the trace entry's 16-bit value field.
kitaqfc/lib/debug.c:54
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/debug.h:48
#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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/debug.h:49
#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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/debug.h:47
#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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/debug.h:46
#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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/debug.h:45
#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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_debug.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_debug.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/debug.h:44
#define KITAQGB_TRACE_U8(name, value) debug_trace_u8((const u8*)(name), (u8)(value))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.
Placez le rappel dans la banque PRG commune 0, ou maintenez sa banque mappée pendant tout l’appel. Le pointeur contient une adresse CPU sur 16 bits et ne sélectionne pas de banque. Les paramètres et variables locales des fonctions FC occupent des emplacements fixes : n’appelez pas le parcours des entités récursivement et n’y entrez pas à nouveau depuis une interruption.
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(void);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 FC 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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\entity.c .\kitaq-docs\samples\api-examples\fc\entity_pool.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\entity_pool.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasmImplémentation et source
kitaqfc/lib/entity.h:47
Release every entity and restore deterministic defaults, including the no-sprite sentinel.
kitaqfc/lib/entity.c:14
void entity_clear_all(void)
{
u8 i;
i = 0;
while (i < ENTITY_MAX) {
entity_pool[(__safe_index u8)i].active = 0;
entity_pool[(__safe_index u8)i].type = 0;
entity_pool[(__safe_index u8)i].x = 0;
entity_pool[(__safe_index u8)i].y = 0;
entity_pool[(__safe_index u8)i].vx = 0;
entity_pool[(__safe_index u8)i].vy = 0;
entity_pool[(__safe_index u8)i].state = 0;
entity_pool[(__safe_index u8)i].timer = 0;
entity_pool[(__safe_index u8)i].sprite = 0xFF;
i = (u8)(i + 1);
}
}entity_count_active
Compte les emplacements d’entités occupés sans les modifier.
Syntaxe
u8 entity_count_active(void);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 FC 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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\entity.c .\kitaq-docs\samples\api-examples\fc\entity_pool.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\entity_pool.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasmImplémentation et source
kitaqfc/lib/entity.h:45
Count occupied slots without changing entity state.
kitaqfc/lib/entity.c:94
u8 entity_count_active(void)
{
u8 i;
u8 count;
i = 0;
count = 0;
while (i < ENTITY_MAX) {
if (entity_pool[(__safe_index u8)i].active != 0) count = (u8)(count + 1);
i = (u8)(i + 1);
}
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 FC 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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\entity.c .\kitaq-docs\samples\api-examples\fc\entity_pool.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\entity_pool.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasmImplémentation et source
kitaqfc/lib/entity.h:32
Returns a reusable slot ID, or 0xFF if no slot is free.
kitaqfc/lib/entity.c:34
u8 entity_create(u8 type, s16 x, s16 y)
{
u8 i;
i = 0;
while (i < ENTITY_MAX) {
if (entity_pool[(__safe_index u8)i].active == 0) {
entity_pool[(__safe_index u8)i].active = 1;
entity_pool[(__safe_index u8)i].type = type;
entity_pool[(__safe_index u8)i].x = x;
entity_pool[(__safe_index u8)i].y = y;
entity_pool[(__safe_index u8)i].vx = 0;
entity_pool[(__safe_index u8)i].vy = 0;
entity_pool[(__safe_index u8)i].state = 0;
entity_pool[(__safe_index u8)i].timer = 0;
entity_pool[(__safe_index u8)i].sprite = 0xFF;
return i;
}
i = (u8)(i + 1);
}
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 FC 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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\entity.c .\kitaq-docs\samples\api-examples\fc\entity_pool.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\entity_pool.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasmImplémentation et source
kitaqfc/lib/entity.h:35
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.
kitaqfc/lib/entity.c:58
void entity_destroy(u8 id)
{
if (id >= ENTITY_MAX) return;
entity_pool[(__safe_index u8)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.
Placez le rappel dans la banque PRG commune 0, ou maintenez sa banque mappée pendant tout l’appel. Le pointeur contient une adresse CPU sur 16 bits et ne sélectionne pas de banque. Les paramètres et variables locales des fonctions FC occupent des emplacements fixes : n’appelez pas le parcours des entités récursivement et n’y entrez pas à nouveau depuis une interruption.
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 FC 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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\entity.c .\kitaq-docs\samples\api-examples\fc\entity_pool.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\entity_pool.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasmImplémentation et source
kitaqfc/lib/entity.h:43
Call the drawing callback for each active slot, using the same traversal rules as update. The callback submits drawing data; the pool does not allocate sprites.
kitaqfc/lib/entity.c:88
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 FC 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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\entity.c .\kitaq-docs\samples\api-examples\fc\entity_pool.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\entity_pool.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasmImplémentation et source
kitaqfc/lib/entity.h:37
Returns null for an invalid or inactive ID; the returned pointer aliases reusable pool storage.
kitaqfc/lib/entity.c:66
Entity* entity_get(u8 id)
{
if (id >= ENTITY_MAX) return 0;
if (entity_pool[(__safe_index u8)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(void);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 FC 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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\entity.c .\kitaq-docs\samples\api-examples\fc\entity_pool.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\entity_pool.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasmImplémentation et source
kitaqfc/lib/entity.h:30
Reset every slot before the game starts using the pool.
kitaqfc/lib/entity.c:8
void entity_init(void)
{
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.
Placez le rappel dans la banque PRG commune 0, ou maintenez sa banque mappée pendant tout l’appel. Le pointeur contient une adresse CPU sur 16 bits et ne sélectionne pas de banque. Les paramètres et variables locales des fonctions FC occupent des emplacements fixes : n’appelez pas le parcours des entités récursivement et n’y entrez pas à nouveau depuis une interruption.
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 FC 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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\entity.c .\kitaq-docs\samples\api-examples\fc\entity_pool.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\entity_pool.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasmImplémentation et source
kitaqfc/lib/entity.h:40
Call fn(id) for each active slot in ascending order. A null callback does nothing. Changes to later slots take effect during the same traversal. Do not reenter this traversal.
kitaqfc/lib/entity.c:75
void entity_update_all(EntityFn fn)
{
u8 i;
if (fn == 0) return;
i = 0;
while (i < ENTITY_MAX) {
if (entity_pool[(__safe_index u8)i].active != 0) fn(i);
i = (u8)(i + 1);
}
}Fichiers FDS et emplacements de sauvegarde de taille fixe
fds_file.h permet de charger des fichiers dans les tampons du jeu et d’écrire dans un emplacement de sauvegarde réservé sur disque. fds_save.h inclut les mêmes déclarations. Utilisez fds_overlay.h pour appeler du code d’overlay.
__fds_load_file() / __fds_save_file()
fds_file_io.c fds_file_io_manifest.json fds_file_io_payload.bin
fds_sound.h
Déclare les intrinsèques du compilateur pour l’onde de 64 pas, la table de modulation, la hauteur, le volume et les enveloppes. KITAQFC génère leurs implémentations.
Construisez une image .fds avec --mapper=fds. Cette leçon utilise le son sans entrées/sorties disque. L’enregistrement passe par le démarrage direct en RAM et le modèle audio de KUROSAKI. Le micrologiciel de test vide n’implémente aucune routine BIOS et n’est pas distribué. Le démarrage disque normal et le matériel réel nécessitent un environnement d’amorçage adapté.
Référence des fonctions : __fds_sound_enable, __fds_wave_load, __fds_mod_load, __fds_freq_set, __fds_volume_set, __fds_env_set
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_math.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_math.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/fixed.h:35
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.
kitaqfc/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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_math.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_math.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/fixed.h:26
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.
kitaqfc/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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_math.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_math.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/fixed.h:38
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.
kitaqfc/lib/fixed.c:34
fix8 fix_lerp(fix8 a, fix8 b, u8 t_q8)
{
fix8 d;
// The endpoint difference must fit s16 before the reduced-precision interpolation.
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_math.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_math.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/fixed.h:31
Approximate 8.8 multiplication by discarding four low bits from each operand before multiplying. This trades precision for a smaller intermediate product.
kitaqfc/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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_math.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_math.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/fixed.h:28
Discard the eight fractional bits using a signed right shift.
kitaqfc/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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_math_limits.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_math_limits.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/fixed.h:41
Return the magnitude in s16. The most-negative s16 has no positive s16 representation and must be excluded by callers needing a nonnegative result.
kitaqfc/lib/fixed.c:44
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_math_limits.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_math_limits.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/fixed.h:47
Clamp to an inclusive interval; callers must provide lo <= hi.
kitaqfc/lib/fixed.c:65
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_math_limits.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_math_limits.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/fixed.h:45
Select the larger signed value.
kitaqfc/lib/fixed.c:58
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_math_limits.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_math_limits.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/fixed.h:43
Select the smaller signed value.
kitaqfc/lib/fixed.c:51
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);__vramq_commit();__vramq_exec();
}}Cet extrait montre l’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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_geometry.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_geometry.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/fixed.h:54
Test a half-open rectangle: left/top edges are included, right/bottom excluded. The coordinate-plus-size sums must remain representable as s16.
kitaqfc/lib/fixed.c:86
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch_geometry.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_geometry.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/fixed.h:51
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.
kitaqfc/lib/fixed.c:75
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.
Lit le contrôleur 1 avec __pad_read1_safe, convertit l’ordre des bits NES au format commun BTN_*, mémorise l’état précédent et calcule les masques d’appui, de relâchement et de répétition. Le contrôleur 2 n’est pas concerné. Appelez-la une fois par cycle d’entrée.
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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\input.c .\kitaq-docs\samples\api-examples\fc\input_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_aliases.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cacheImplémentation et source
kitaqfc/lib/input.h:53
#define btn_down input_downkitaqfc/lib/input.c:85
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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\input.c .\kitaq-docs\samples\api-examples\fc\input_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_aliases.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cacheImplémentation et source
kitaqfc/lib/input.h:54
#define btn_pressed input_pressedkitaqfc/lib/input.c:87
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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\input.c .\kitaq-docs\samples\api-examples\fc\input_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_aliases.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cacheImplémentation et source
kitaqfc/lib/input.h:55
#define btn_released input_releasedkitaqfc/lib/input.c:89
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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\input.c .\kitaq-docs\samples\api-examples\fc\input_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_aliases.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cacheImplémentation et source
kitaqfc/lib/input.h:56
#define btn_repeat input_repeatkitaqfc/lib/input.c:91
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(void);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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\input.c .\kitaq-docs\samples\api-examples\fc\input_edges.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_edges.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cacheImplémentation et source
kitaqfc/lib/input.h:49
Read the complete translated held-button mask.
kitaqfc/lib/input.c:93
u8 input_current(void) { 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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\input.c .\kitaq-docs\samples\api-examples\fc\input_edges.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_edges.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cacheImplémentation et source
kitaqfc/lib/input.h:41
Return true when any masked logical button is held.
kitaqfc/lib/input.c:85
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(void);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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\input.c .\kitaq-docs\samples\api-examples\fc\input_edges.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_edges.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cacheImplémentation et source
kitaqfc/lib/input.h:35
Clear held/edge/repeat masks and reset each independent repeat countdown.
kitaqfc/lib/input.c:34
void input_init(void)
{
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 = (u8)(i + 1);
}
}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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\input.c .\kitaq-docs\samples\api-examples\fc\input_edges.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_edges.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cacheImplémentation et source
kitaqfc/lib/input.h:43
Return true when any masked button became pressed in the latest input update.
kitaqfc/lib/input.c:87
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(void);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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\input.c .\kitaq-docs\samples\api-examples\fc\input_edges.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_edges.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cacheImplémentation et source
kitaqfc/lib/input.h:51
Read the translated held-button mask from before the latest update.
kitaqfc/lib/input.c:95
u8 input_previous(void) { 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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\input.c .\kitaq-docs\samples\api-examples\fc\input_edges.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_edges.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cacheImplémentation et source
kitaqfc/lib/input.h:45
Return true when any masked button became released in the latest update.
kitaqfc/lib/input.c:89
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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\input.c .\kitaq-docs\samples\api-examples\fc\input_edges.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_edges.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cacheImplémentation et source
kitaqfc/lib/input.h:47
Return true for a masked initial press or scheduled repeat pulse.
kitaqfc/lib/input.c:91
u8 input_repeat(u8 mask) { return (u8)((kq_input_repeat_keys & mask) != 0); }input_update
Lit le contrôleur 1 avec __pad_read1_safe, convertit l’ordre des bits NES au format commun BTN_*, mémorise l’état précédent et calcule les masques d’appui, de relâchement et de répétition. Le contrôleur 2 n’est pas concerné. Appelez-la une fois par cycle d’entrée.
Syntaxe
void input_update(void);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.
La lecture sûre répète des paires de lectures complètes jusqu’à obtenir deux masques identiques. Chaque lecture active le strobe de $4016 et redémarre la lecture série des deux contrôleurs. Le nombre d’essais n’est pas limité. Ce contrôle ne prouve pas la compatibilité avec toutes les combinaisons DMC/périphériques.
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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\input.c .\kitaq-docs\samples\api-examples\fc\input_edges.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_edges.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cacheImplémentation et source
kitaqfc/lib/input.h:39
Read controller 1 through the safe intrinsic, translate its bit order and derive press/release edges. Repeat delays count calls to this function, so call it once per intended input tick.
kitaqfc/lib/input.c:52
void input_update(void)
{
u8 i;
u8 raw;
kq_input_prev_keys = kq_input_keys;
raw = __pad_read1_safe();
kq_input_keys = input_translate_pad(raw);
kq_input_press_keys = (u8)(kq_input_keys & (u8)(kq_input_keys ^ kq_input_prev_keys));
kq_input_release_keys = (u8)(kq_input_prev_keys & (u8)(kq_input_keys ^ kq_input_prev_keys));
kq_input_repeat_keys = kq_input_press_keys;
i = 0;
while (i < 8) {
u8 mask;
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] = (u8)(input_repeat_timer[i] - 1);
} 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 = (u8)(i + 1);
}
}input_repeat.h — Répétition d'un bouton maintenu
Ce complément de pad.c ajoute des compteurs de répétition indépendants pour le contrôleur 1. Configurez délai et intervalle à l’exécution, lisez le contrôleur, puis avancez la répétition une fois par cycle. Les consultations d’appui, de relâchement et de maintien utilisent l’état du contrôleur ; seule la répétition dépend de nes_pad_repeat_step().
Compte initial de 0 à 255. Après l’événement immédiat d’un nouvel appui, le suivant arrive delay + 1 étapes plus tard. L’unité est l’appel à nes_pad_repeat_step(), pas l’image, sauf si vous l’appelez exactement une fois par image.
Compte entre répétitions ultérieures, de 0 à 255. L’intervalle réel est interval + 1 étapes ; 0 produit un événement à chaque étape maintenue après le délai initial. Les huit boutons ont des compteurs indépendants.
nes_pad_held
Filtre les boutons maintenus à la dernière lecture du contrôleur 1. Sert aux actions continues tant que les boutons sélectionnés restent appuyés. Lit l’état mémorisé sans interroger à nouveau le matériel.
Syntaxe
unsigned char nes_pad_held(unsigned char mask);Paramètres
maskBoutons à conserver dans l’ordre des bits NES, combinés avec
|si nécessaire. Zéro ne sélectionne rien. Il s’agit d’un filtre, pas du numéro de port du contrôleur.
Valeur renvoyée
Les bits correspondants du masque mémorisé, à leur position d’origine. La valeur peut être différente de 1 ; 0 signifie aucune correspondance. La lecture ne consomme pas l’événement.
Conditions et limites
Format NES brut : A=0x01, B=0x02, SELECT=0x04, START=0x08, UP=0x10, DOWN=0x20, LEFT=0x40, RIGHT=0x80. Un bit à 1 indique un appui. Utilisez ces valeurs avec nes_pad_* et les résultats bruts de __pad_*, et non les masques communs BTN_* de input.h.
Initialisez les quatre octets d’état nes_pad1_* à 0 avant la première lecture. Ensuite, lisez une fois par cycle. pressed = current & ~previous et released = previous & ~current décrivent la dernière lecture. La répétition se met à jour séparément avec nes_pad_repeat_step().
Exemple d’utilisation
if (nes_pad_held(0x02)!=0) held_ticks++; // B is bit 1 in NES raw format.Cet extrait montre l’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 enseigne l’ordre lecture → mise à jour de la répétition → consultation et montre que les fonctions NES renvoient les bits sélectionnés, et non la valeur booléenne 1. Avec nes_pad_repeat_config(3, 1), maintenez B pendant 40 mises à jour, puis relâchez-le. FIRST HELD, FIRST TRIGGER et FIRST REPEAT valent 2 ; HELD TICKS vaut 40, PULSE COUNT vaut 19 et RELEASE BITS vaut 2. La première répétition survient quatre mises à jour après l’appui initial ; les suivantes sont espacées de deux mises à jour. FAILED CHECKS doit valoir 0. Une autre durée modifie le nombre d’impulsions.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\pad.c .\kitaqfc\lib\input_repeat.c .\kitaq-docs\samples\api-examples\fc\pad_repeat.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\pad_repeat.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cacheImplémentation et source
kitaqfc/lib/input_repeat.h:28
Return the requested currently-held bits in the NES pad layout.
kitaqfc/lib/input_repeat.c:103
unsigned char nes_pad_held(unsigned char mask)
{
return (unsigned char)(nes_pad1_cur & mask);
}nes_pad_release
Filtre les relâchements du contrôleur 1 : boutons sélectionnés maintenus à la lecture précédente et relâchés à la lecture courante. Les laisser relâchés ne crée pas de nouvel événement à la lecture suivante.
Syntaxe
unsigned char nes_pad_release(unsigned char mask);Paramètres
maskBoutons à conserver dans l’ordre des bits NES, combinés avec
|si nécessaire. Zéro ne sélectionne rien. Il s’agit d’un filtre, pas du numéro de port du contrôleur.
Valeur renvoyée
Les bits correspondants du masque mémorisé, à leur position d’origine. La valeur peut être différente de 1 ; 0 signifie aucune correspondance. La lecture ne consomme pas l’événement.
Conditions et limites
Format NES brut : A=0x01, B=0x02, SELECT=0x04, START=0x08, UP=0x10, DOWN=0x20, LEFT=0x40, RIGHT=0x80. Un bit à 1 indique un appui. Utilisez ces valeurs avec nes_pad_* et les résultats bruts de __pad_*, et non les masques communs BTN_* de input.h.
Initialisez les quatre octets d’état nes_pad1_* à 0 avant la première lecture. Ensuite, lisez une fois par cycle. pressed = current & ~previous et released = previous & ~current décrivent la dernière lecture. La répétition se met à jour séparément avec nes_pad_repeat_step().
Exemple d’utilisation
if (nes_pad_release(0x02)!=0) {
release_bits=nes_pad_release(0x02); // Returns the released B bit, 2.
if (nes_pad_held(0x02)!=0 || nes_pad_trigger(0x02)!=0 || nes_pad_repeat(0x02)!=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 enseigne l’ordre lecture → mise à jour de la répétition → consultation et montre que les fonctions NES renvoient les bits sélectionnés, et non la valeur booléenne 1. Avec nes_pad_repeat_config(3, 1), maintenez B pendant 40 mises à jour, puis relâchez-le. FIRST HELD, FIRST TRIGGER et FIRST REPEAT valent 2 ; HELD TICKS vaut 40, PULSE COUNT vaut 19 et RELEASE BITS vaut 2. La première répétition survient quatre mises à jour après l’appui initial ; les suivantes sont espacées de deux mises à jour. FAILED CHECKS doit valoir 0. Une autre durée modifie le nombre d’impulsions.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\pad.c .\kitaqfc\lib\input_repeat.c .\kitaq-docs\samples\api-examples\fc\pad_repeat.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\pad_repeat.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cacheImplémentation et source
kitaqfc/lib/input_repeat.h:26
Return the requested newly-released bits from the latest pad poll.
kitaqfc/lib/input_repeat.c:97
unsigned char nes_pad_release(unsigned char mask)
{
return (unsigned char)(nes_pad1_released & mask);
}nes_pad_repeat
Filtre les événements du dernier nes_pad_repeat_step(). Inclut le nouvel appui et les répétitions programmées pendant le maintien. Cette consultation n’avance pas les compteurs.
Syntaxe
unsigned char nes_pad_repeat(unsigned char mask);Paramètres
maskBoutons à conserver dans l’ordre des bits NES, combinés avec
|si nécessaire. Zéro ne sélectionne rien. Il s’agit d’un filtre, pas du numéro de port du contrôleur.
Valeur renvoyée
Les bits correspondants du masque mémorisé, à leur position d’origine. La valeur peut être différente de 1 ; 0 signifie aucune correspondance. La lecture ne consomme pas l’événement.
Conditions et limites
Format NES brut : A=0x01, B=0x02, SELECT=0x04, START=0x08, UP=0x10, DOWN=0x20, LEFT=0x40, RIGHT=0x80. Un bit à 1 indique un appui. Utilisez ces valeurs avec nes_pad_* et les résultats bruts de __pad_*, et non les masques communs BTN_* de input.h.
Initialisez les quatre octets d’état nes_pad1_* à 0 avant la première lecture. Ensuite, lisez une fois par cycle. pressed = current & ~previous et released = previous & ~current décrivent la dernière lecture. La répétition se met à jour séparément avec nes_pad_repeat_step().
Exemple d’utilisation
if (nes_pad_repeat(0x02)!=0) {
if (pulse_count==1 && held_ticks-previous_pulse!=4) failures++;
if (pulse_count>1 && held_ticks-previous_pulse!=2) failures++;
previous_pulse=held_ticks; pulse_count++;
if (nes_pad_repeat(0x02)!=2) failures++; // Querying again preserves the pulse.
}Cet extrait montre l’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 enseigne l’ordre lecture → mise à jour de la répétition → consultation et montre que les fonctions NES renvoient les bits sélectionnés, et non la valeur booléenne 1. Avec nes_pad_repeat_config(3, 1), maintenez B pendant 40 mises à jour, puis relâchez-le. FIRST HELD, FIRST TRIGGER et FIRST REPEAT valent 2 ; HELD TICKS vaut 40, PULSE COUNT vaut 19 et RELEASE BITS vaut 2. La première répétition survient quatre mises à jour après l’appui initial ; les suivantes sont espacées de deux mises à jour. FAILED CHECKS doit valoir 0. Une autre durée modifie le nombre d’impulsions.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\pad.c .\kitaqfc\lib\input_repeat.c .\kitaq-docs\samples\api-examples\fc\pad_repeat.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\pad_repeat.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cacheImplémentation et source
kitaqfc/lib/input_repeat.h:24
Return the requested repeat-pulse bits from the latest repeat step.
kitaqfc/lib/input_repeat.c:91
unsigned char nes_pad_repeat(unsigned char mask)
{
return (unsigned char)(nes_pad1_repeat & mask);
}nes_pad_repeat_config
Configure à l’exécution le délai initial et l’intervalle de répétition, efface nes_pad1_repeat et réinitialise les huit compteurs par bouton à delay. Ne lit pas le contrôleur et n’efface pas les masques de maintien, d’appui ou de relâchement.
Syntaxe
void nes_pad_repeat_config(unsigned char delay, unsigned char interval);Paramètres
delayCompte initial de 0 à 255. Après l’événement immédiat d’un nouvel appui, le suivant arrive
delay + 1étapes plus tard. L’unité est l’appel ànes_pad_repeat_step(), pas l’image, sauf si vous l’appelez exactement une fois par image.intervalCompte entre répétitions ultérieures, de 0 à 255. L’intervalle réel est
interval + 1étapes ; 0 produit un événement à chaque étape maintenue après le délai initial. Les huit boutons ont des compteurs indépendants.
Valeur renvoyée
Aucune (void).
Conditions et limites
Format NES brut : A=0x01, B=0x02, SELECT=0x04, START=0x08, UP=0x10, DOWN=0x20, LEFT=0x40, RIGHT=0x80. Un bit à 1 indique un appui. Utilisez ces valeurs avec nes_pad_* et les résultats bruts de __pad_*, et non les masques communs BTN_* de input.h.
Exemple d’utilisation
nes_pad_repeat_config(3,1); // Next pulse after 4 held updates, then every 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
Ce programme enseigne l’ordre lecture → mise à jour de la répétition → consultation et montre que les fonctions NES renvoient les bits sélectionnés, et non la valeur booléenne 1. Avec nes_pad_repeat_config(3, 1), maintenez B pendant 40 mises à jour, puis relâchez-le. FIRST HELD, FIRST TRIGGER et FIRST REPEAT valent 2 ; HELD TICKS vaut 40, PULSE COUNT vaut 19 et RELEASE BITS vaut 2. La première répétition survient quatre mises à jour après l’appui initial ; les suivantes sont espacées de deux mises à jour. FAILED CHECKS doit valoir 0. Une autre durée modifie le nombre d’impulsions.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\pad.c .\kitaqfc\lib\input_repeat.c .\kitaq-docs\samples\api-examples\fc\pad_repeat.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\pad_repeat.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cacheImplémentation et source
kitaqfc/lib/input_repeat.h:16
Set initial/repeat countdowns and clear repeat output. Zero countdowns are allowed and cause a repeat on the next held-button step. A fresh press emits immediately. Held repeats follow after delay+1 and then interval+1 steps. These are call counts, not milliseconds; use one fresh pad poll before each step.
kitaqfc/lib/input_repeat.c:21
void nes_pad_repeat_config(unsigned char delay, unsigned char interval)
{
unsigned char i;
nes_pad_repeat_delay = delay;
nes_pad_repeat_interval = interval;
nes_pad1_repeat = 0;
i = 0;
while (i != 8)
{
nes_pad1_repeat_counter[i] = delay;
i = i + 1;
}
}nes_pad_repeat_step
Reconstruit nes_pad1_repeat à partir des derniers masques de maintien et de nouvel appui, en avançant chaque compteur une fois. Appelez d’abord nes_pad_poll(), puis cette fonction une seule fois. Réutiliser un ancien masque d’appui réinitialise le délai et produit de nouveaux événements d’appui initial.
Syntaxe
void nes_pad_repeat_step(void);Valeur renvoyée
Aucune (void).
Conditions et limites
Format NES brut : A=0x01, B=0x02, SELECT=0x04, START=0x08, UP=0x10, DOWN=0x20, LEFT=0x40, RIGHT=0x80. Un bit à 1 indique un appui. Utilisez ces valeurs avec nes_pad_* et les résultats bruts de __pad_*, et non les masques communs BTN_* de input.h.
Initialisez les quatre octets d’état nes_pad1_* à 0 avant la première lecture. Ensuite, lisez une fois par cycle. pressed = current & ~previous et released = previous & ~current décrivent la dernière lecture. La répétition se met à jour séparément avec nes_pad_repeat_step().
Exemple d’utilisation
nes_pad_repeat_step(); // Once after each fresh poll; getters do not advance time.Cet extrait montre l’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 enseigne l’ordre lecture → mise à jour de la répétition → consultation et montre que les fonctions NES renvoient les bits sélectionnés, et non la valeur booléenne 1. Avec nes_pad_repeat_config(3, 1), maintenez B pendant 40 mises à jour, puis relâchez-le. FIRST HELD, FIRST TRIGGER et FIRST REPEAT valent 2 ; HELD TICKS vaut 40, PULSE COUNT vaut 19 et RELEASE BITS vaut 2. La première répétition survient quatre mises à jour après l’appui initial ; les suivantes sont espacées de deux mises à jour. FAILED CHECKS doit valoir 0. Une autre durée modifie le nombre d’impulsions.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\pad.c .\kitaqfc\lib\input_repeat.c .\kitaq-docs\samples\api-examples\fc\pad_repeat.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\pad_repeat.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cacheImplémentation et source
kitaqfc/lib/input_repeat.h:20
Generate per-button repeat bits from the most recently polled pad state. Poll first, then call once per tick; a countdown reaching zero emits on the following step, so an interval N leaves N decrement steps between pulses.
kitaqfc/lib/input_repeat.c:40
void nes_pad_repeat_step(void)
{
unsigned char bit_index;
unsigned char mask;
unsigned char counter;
nes_pad1_repeat = 0;
bit_index = 0;
mask = 1;
while (mask != 0)
{
if ((nes_pad1_cur & mask) == 0)
{
nes_pad1_repeat_counter[bit_index] = nes_pad_repeat_delay;
}
else
{
if ((nes_pad1_pressed & mask) != 0)
{
nes_pad1_repeat = nes_pad1_repeat | mask;
nes_pad1_repeat_counter[bit_index] = nes_pad_repeat_delay;
}
else
{
counter = nes_pad1_repeat_counter[bit_index];
if (counter == 0)
{
nes_pad1_repeat = nes_pad1_repeat | mask;
nes_pad1_repeat_counter[bit_index] = nes_pad_repeat_interval;
}
else
{
nes_pad1_repeat_counter[bit_index] = counter - 1;
}
}
}
bit_index = bit_index + 1;
// Byte overflow terminates the scan after the eighth button; each button has its own countdown.
mask = mask + mask;
}
}nes_pad_trigger
Filtre avec mask les nouveaux appuis du contrôleur 1. Sert à déclencher une action lorsqu’un bouton sélectionné passe de relâché à appuyé.
Syntaxe
unsigned char nes_pad_trigger(unsigned char mask);Paramètres
maskBoutons à conserver dans l’ordre des bits NES, combinés avec
|si nécessaire. Zéro ne sélectionne rien. Il s’agit d’un filtre, pas du numéro de port du contrôleur.
Valeur renvoyée
Les bits correspondants du masque mémorisé, à leur position d’origine. La valeur peut être différente de 1 ; 0 signifie aucune correspondance. La lecture ne consomme pas l’événement.
Conditions et limites
Format NES brut : A=0x01, B=0x02, SELECT=0x04, START=0x08, UP=0x10, DOWN=0x20, LEFT=0x40, RIGHT=0x80. Un bit à 1 indique un appui. Utilisez ces valeurs avec nes_pad_* et les résultats bruts de __pad_*, et non les masques communs BTN_* de input.h.
Initialisez les quatre octets d’état nes_pad1_* à 0 avant la première lecture. Ensuite, lisez une fois par cycle. pressed = current & ~previous et released = previous & ~current décrivent la dernière lecture. La répétition se met à jour séparément avec nes_pad_repeat_step().
Exemple d’utilisation
if (nes_pad_trigger(0x02)!=0) {
first_trigger=nes_pad_trigger(0x02); // Returns 2, not Boolean 1.
first_held=nes_pad_held(0x02); first_repeat=nes_pad_repeat(0x02);
if (first_trigger!=2 || first_held!=2 || first_repeat!=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
Ce programme enseigne l’ordre lecture → mise à jour de la répétition → consultation et montre que les fonctions NES renvoient les bits sélectionnés, et non la valeur booléenne 1. Avec nes_pad_repeat_config(3, 1), maintenez B pendant 40 mises à jour, puis relâchez-le. FIRST HELD, FIRST TRIGGER et FIRST REPEAT valent 2 ; HELD TICKS vaut 40, PULSE COUNT vaut 19 et RELEASE BITS vaut 2. La première répétition survient quatre mises à jour après l’appui initial ; les suivantes sont espacées de deux mises à jour. FAILED CHECKS doit valoir 0. Une autre durée modifie le nombre d’impulsions.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\pad.c .\kitaqfc\lib\input_repeat.c .\kitaq-docs\samples\api-examples\fc\pad_repeat.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\pad_repeat.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cacheImplémentation et source
kitaqfc/lib/input_repeat.h:22
Return the requested newly-pressed bits, not a normalized Boolean.
kitaqfc/lib/input_repeat.c:85
unsigned char nes_pad_trigger(unsigned char mask)
{
return (unsigned char)(nes_pad1_pressed & mask);
}metasprite.h — Images composées de plusieurs sprites
Disponible comme fonction C dans metasprite.c et comme macro de nes_game.h se développant en __metasprite_draw. Les deux formes lisent le même flux terminé et écrivent les mêmes entrées OAM de quatre octets. Les exemples compilent chaque forme séparément.
Les fonctions C de métasprites nécessitent nes_oam_shadow[256]. runtime.c le définit à 0x0200, réserve également 0x0300–0x03BF pour sa file VRAM et fournit __nes_nmi. Incluez chaque implémentation une seule fois et coordonnez le gestionnaire d’interruption avec le reste du programme.
nes_metasprite_draw
Disponible comme fonction C dans metasprite.c et comme macro de nes_game.h se développant en __metasprite_draw. Les deux formes lisent le même flux terminé et écrivent les mêmes entrées OAM de quatre octets. Les exemples compilent chaque forme séparément.
Déploie un flux de parties de sprite muni d’un terminateur dans des entrées consécutives du tampon miroir de la page 02. Chaque partie ajoute ses décalages X/Y d’un octet à la position de base et fournit sa tuile et ses attributs. Renvoie l’indice OAM suivant.
Syntaxe
unsigned char nes_metasprite_draw(unsigned char oam_index, unsigned char base_x, unsigned char base_y, unsigned char* metasprite);
// Macro from nes_game.h:
#define nes_metasprite_draw(i,x,y,data) __metasprite_draw((i),(x),(y),(data))Paramètres
oam_index / iIndice du sprite, de 0 à 63, et non décalage en octets. Le calcul multiplie cet indice par quatre dans un curseur de 8 bits ; les valeurs hors plage sont ramenées modulo 64 et peuvent écraser une autre entrée. L’allocation n’est pas vérifiée.
base_x / xPosition horizontale en pixels, sous forme d’octet non signé ; ce n’est pas une coordonnée de tuile.
base_y / yOctet Y de l’OAM. Pour placer le haut sous la ligne zéro, passez sa position moins un ; 239..255 sont hors des 240 lignes visibles.
metasprite / dataPointeur vers des enregistrements lisibles de quatre octets :
dx, dy, tile, attr. Un0xFFà la position dx suivante termine le flux ; aucun octet supplémentaire n’est nécessaire. Les décalages s’ajoutent modulo 256 :0xFEreprésente −2 et dy=0xFFpeut représenter −1, mais dx=0xFFest réservé au terminateur. Le pointeur doit être valide dans la mémoire actuellement accessible.
Valeur renvoyée
Indice OAM suivant : (oam_index + parties_écrites) modulo 64. Il s’agit d’un curseur, pas du nombre de parties dessinées. Un flux vide renvoie oam_index modulo 64.
Conditions et limites
Choisissez explicitement les en-têtes : nes_game.h et l’en-tête général fc.h définissent les macros. Pour les fonctions C, incluez runtime.h ou metasprite.h et liez leurs implémentations sans ces macros, ou supprimez d’abord les macros en conflit avec #undef. La macro DMA sans argument n’accepte pas l’argument page de la fonction C.
Les fonctions C de métasprites nécessitent nes_oam_shadow[256]. runtime.c le définit à 0x0200, réserve également 0x0300–0x03BF pour sa file VRAM et fournit __nes_nmi. Incluez chaque implémentation une seule fois et coordonnez le gestionnaire d’interruption avec le reste du programme.
Ces opérations modifient la RAM CPU 0x0200–0x02FF, sans mettre immédiatement à jour l’OAM matérielle. Transférez la page complète avec __oam_dma. Elles ne tiennent à jour ni les indicateurs d’allocation, ni les tableaux de coordonnées, ni le compteur de la bibliothèque de sprites. Évitez qu’une interruption modifie ou transfère une page encore en préparation.
Le nombre de parties, le découpage à l’écran et la capacité ne sont pas vérifiés. Ajoutez un terminateur et limitez-vous à 64−oam_index parties. Les coordonnées sont ramenées modulo 256 ; après l’entrée 63, l’écriture reprend à l’entrée 0. Un flux vide ne modifie rien. Ce format diffère du tableau MetaSpritePart à nombre explicite utilisé par metasprite_draw dans la bibliothèque de sprites.
Exemple d’utilisation
demo_next=nes_metasprite_draw(4,144,31,demo_parts); // C function: returns 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
C-RUNTIME combine les fonctions C. PAIR affiche deux flèches 8×8 à (144,32) et (152,32), la seconde retournée horizontalement. Une autre paire à y=64 est masquée : HIDE RANGE doit rester vide. Les dessins successifs utilisent les entrées 4–5 et 6–7 et affichent NEXT 08. La page 02 est copiée vers la page 04, puis seule l’entrée 8 passe de la tuile flèche 128 au carré 129. nes_oam_dma(4) doit afficher un carré vert à (144,96), près de PAGE 04, tandis que la page 02 conserve la tuile 128.
Les flèches ont des bords rouges, une tige verte et des détails bleus à la pointe ; la tuile carrée 129 est verte. La vérification compare 8 704 pixels colorés et les 256 octets OAM transférés par image, ainsi que les libellés. Le matériel physique n’a pas été testé.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\oam_c_helpers.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --nes-chr=.\kitaq-docs\samples\sprite_example.chr -o .\out\oam_c_helpers.nes --no-cache --no-disasmExemple d’utilisation
fc_oam_next=nes_metasprite_draw(5,136,95,fc_oam_pair); // Returns 7 after two entries.Cet extrait montre l’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éserve une ligne légendée à chaque opération. SET et MOVE montrent des flèches de 8×8 vers la droite en (144,16) et (144,32) ; TILE, un carré vert en (144,48) ; ATTR, la flèche retournée selon les deux axes en (144,64). HIDE en (144,80) et CLEAR en (144,112) doivent rester vides. META montre une paire en (136,96) et (144,96), la seconde flèche étant retournée horizontalement. NEXT 07 indique l’indice suivant après les entrées 5 et 6. Les bords sont rouges, la tige verte et les détails de la pointe bleus. La vérification compare 8 704 pixels par image et les octets OAM transférés ; le matériel physique n’a pas été testé.
Le programme ALIASES prépare les lignes avec les macros de nes_game.h et envoie la page 02 avec nes_oam_dma(). TRANSFER affiche la flèche 8×8 à (144,128). Cet exemple utilise les macros sans lier runtime.c ni metasprite.c.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\oam_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --nes-chr=.\kitaq-docs\samples\sprite_example.chr -o .\out\oam_aliases.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/metasprite.h:12
Optional declarations for the phase 10 NES metasprite helper. Metasprite data layout: [dx, dy, tile, attr] repeated, terminated by dx=0xFF Read four-byte records [dx,dy,tile,attr] until dx=0xFF, writing them to shadow OAM. Coordinates and destination offsets wrap as bytes. The caller must supply a terminator and enough unused slots; there is no capacity guard. Return the next slot index derived from the final wrapped byte offset.
kitaqfc/lib/metasprite.c:18
unsigned char nes_metasprite_draw(unsigned char oam_index, unsigned char base_x, unsigned char base_y, unsigned char* metasprite)
{
unsigned char dst;
unsigned char dx;
dst = oam_index + oam_index;
dst = dst + dst;
while (1)
{
dx = metasprite[0];
if (dx == 0xFF)
{
break;
}
// These are raw OAM Y bytes, not a corrected screen-top coordinate; no allocation bookkeeping is updated.
nes_oam_shadow[dst] = (unsigned char)(base_y + metasprite[1]);
nes_oam_shadow[(unsigned char)(dst + 1)] = metasprite[2];
nes_oam_shadow[(unsigned char)(dst + 2)] = metasprite[3];
nes_oam_shadow[(unsigned char)(dst + 3)] = (unsigned char)(base_x + dx);
dst = (unsigned char)(dst + 4);
metasprite = metasprite + 4;
}
return (unsigned char)(dst >> 2);
}nes_metasprite_hide_from
Masque une plage contiguë d’entrées du tampon OAM en écrivant 0xF8 dans chaque octet Y. Tuile, attributs et X sont conservés. Cette fonction C ne transfère pas l’OAM et ne libère aucune allocation de la bibliothèque de sprites.
Syntaxe
void nes_metasprite_hide_from(unsigned char oam_index, unsigned char sprite_count);Paramètres
oam_indexIndice du sprite, de 0 à 63, et non décalage en octets. Le calcul multiplie cet indice par quatre dans un curseur de 8 bits ; les valeurs hors plage sont ramenées modulo 64 et peuvent écraser une autre entrée. L’allocation n’est pas vérifiée.
sprite_countNombre d’entrées à masquer, de 0 à
64−oam_index. Zéro ne change rien. Un nombre supérieur fait reboucler le curseur d’octets et peut masquer des entrées au début de l’OAM ; la fonction ne vérifie pas la plage.
Valeur renvoyée
Aucune (void).
Conditions et limites
Les fonctions C de métasprites nécessitent nes_oam_shadow[256]. runtime.c le définit à 0x0200, réserve également 0x0300–0x03BF pour sa file VRAM et fournit __nes_nmi. Incluez chaque implémentation une seule fois et coordonnez le gestionnaire d’interruption avec le reste du programme.
Ces opérations modifient la RAM CPU 0x0200–0x02FF, sans mettre immédiatement à jour l’OAM matérielle. Transférez la page complète avec __oam_dma. Elles ne tiennent à jour ni les indicateurs d’allocation, ni les tableaux de coordonnées, ni le compteur de la bibliothèque de sprites. Évitez qu’une interruption modifie ou transfère une page encore en préparation.
Exemple d’utilisation
nes_metasprite_hide_from(6,2); // Hide slots 6 and 7; the pair at slots 4 and 5 remains.Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
C-RUNTIME combine les fonctions C. PAIR affiche deux flèches 8×8 à (144,32) et (152,32), la seconde retournée horizontalement. Une autre paire à y=64 est masquée : HIDE RANGE doit rester vide. Les dessins successifs utilisent les entrées 4–5 et 6–7 et affichent NEXT 08. La page 02 est copiée vers la page 04, puis seule l’entrée 8 passe de la tuile flèche 128 au carré 129. nes_oam_dma(4) doit afficher un carré vert à (144,96), près de PAGE 04, tandis que la page 02 conserve la tuile 128.
Les flèches ont des bords rouges, une tige verte et des détails bleus à la pointe ; la tuile carrée 129 est verte. La vérification compare 8 704 pixels colorés et les 256 octets OAM transférés par image, ainsi que les libellés. Le matériel physique n’a pas été testé.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\oam_c_helpers.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --nes-chr=.\kitaq-docs\samples\sprite_example.chr -o .\out\oam_c_helpers.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/metasprite.h:17
Hide consecutive shadow slots by setting Y to 0xF8. Keep the requested range within 64 slots to avoid wrapping and hiding earlier entries.
kitaqfc/lib/metasprite.c:49
void nes_metasprite_hide_from(unsigned char oam_index, unsigned char sprite_count)
{
unsigned char dst;
dst = oam_index + oam_index;
dst = dst + dst;
while (sprite_count != 0)
{
nes_oam_shadow[dst] = 0xF8;
dst = (unsigned char)(dst + 4);
sprite_count = sprite_count - 1;
}
}nametable_asset.h — Ressources et placement des tables de noms
Transfère des lignes de 32 tuiles, des rectangles à pas mémoire, des remplissages et des écrans complets de 960+64 octets ; modifie et transfère aussi le miroir d’attributs. Choisissez les transferts immédiats ou la consommation différée de la file selon la situation.
Pour les transferts directs, réglez l’incrément PPUCTRL sur un et utilisez une phase de configuration sans rendu ou un VBlank assez long pour le transfert. Ces fonctions auxiliaires ne désactivent pas le rendu et n’attendent pas.
Liez runtime.c. La file copie les données pour une NMI ultérieure ou une application sûre avec le rendu désactivé. Sérialisez la production et la consommation. Si une opération multiligne manque de place, les lignes déjà acceptées restent en file.
nes_attr_apply_now
Transfère immédiatement les 64 octets du miroir vers la table d’attributs d’une table de noms.
Syntaxe
void nes_attr_apply_now(unsigned short nt_base);Paramètres
nt_baseBase logique de table de noms $2000/$2400/$2800/$2C00 ; le miroir détermine leur indépendance physique.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Le miroir d’attributs partagé de 64 octets occupe la RAM CPU $03E0..$041F ; réservez cette zone. Un octet d’attribut couvre 4×4 tuiles ; chaque champ de deux bits choisit la palette d’un quadrant de 2×2 tuiles.
Pour les transferts directs, réglez l’incrément PPUCTRL sur un et utilisez une phase de configuration sans rendu ou un VBlank assez long pour le transfert. Ces fonctions auxiliaires ne désactivent pas le rendu et n’attendent pas.
Exemple d’utilisation
nes_attr_apply_now(0x2000);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Combinez transferts de lignes, rectangles à pas mémoire, remplissages et tables complètes. Deux barres rouges de 32×8 apparaissent au-dessus d’un carré bleu de 16×16 et de rectangles rouges de 16×24/32×24. Les transferts directs et par file dessinent à des positions distinctes.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/nametable_asset.h:20
Upload all attribute shadow bytes immediately; the caller provides safe PPU timing.
kitaqfc/lib/nametable_asset.c:90
void nes_attr_apply_now(unsigned short nt_base)
{
nes_ppu_stream_write(nes_attr_base_from_nt(nt_base), nes_attr_shadow, 64);
}nes_attr_base_from_nt
Ajoute $3C0 à la base d’une table de noms pour trouver sa table d’attributs.
Syntaxe
unsigned short nes_attr_base_from_nt(unsigned short nt_base);Paramètres
nt_baseBase logique de table de noms $2000/$2400/$2800/$2C00 ; le miroir détermine leur indépendance physique.
Valeur renvoyée
Renvoie nt_base+$3C0 sans valider l’entrée.
Exemple d’utilisation
result[1]=nes_attr_base_from_nt(0x2400);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Combinez transferts de lignes, rectangles à pas mémoire, remplissages et tables complètes. Deux barres rouges de 32×8 apparaissent au-dessus d’un carré bleu de 16×16 et de rectangles rouges de 16×24/32×24. Les transferts directs et par file dessinent à des positions distinctes.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/nametable_asset.h:11
Locate the 64-byte attribute table at offset 0x03C0 from a nametable base.
kitaqfc/lib/nametable_asset.c:30
unsigned short nes_attr_base_from_nt(unsigned short nt_base)
{
return (unsigned short)(nt_base + 0x03C0);
}nes_attr_queue_all
Copie tout le miroir d’attributs dans la file.
Syntaxe
unsigned char nes_attr_queue_all(unsigned short nt_base);Paramètres
nt_baseBase logique de table de noms $2000/$2400/$2800/$2C00 ; le miroir détermine leur indépendance physique.
Valeur renvoyée
Renvoie 1 si accepté, 0 si la file est pleine ; un enregistrement utilise 67 octets de file.
Conditions et limites
Le miroir d’attributs partagé de 64 octets occupe la RAM CPU $03E0..$041F ; réservez cette zone. Un octet d’attribut couvre 4×4 tuiles ; chaque champ de deux bits choisit la palette d’un quadrant de 2×2 tuiles.
Liez runtime.c. La file copie les données pour une NMI ultérieure ou une application sûre avec le rendu désactivé. Sérialisez la production et la consommation. Si une opération multiligne manque de place, les lignes déjà acceptées restent en file.
Exemple d’utilisation
result[5]=nes_attr_queue_all(0x2000);result[6]=nes_vram_queue_used;nes_vram_queue_nmi_flush();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Combinez transferts de lignes, rectangles à pas mémoire, remplissages et tables complètes. Deux barres rouges de 32×8 apparaissent au-dessus d’un carré bleu de 16×16 et de rectangles rouges de 16×24/32×24. Les transferts directs et par file dessinent à des positions distinctes.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/nametable_asset.h:22
Copy all shadow attribute bytes into the runtime queue and return its admission result.
kitaqfc/lib/nametable_asset.c:97
unsigned char nes_attr_queue_all(unsigned short nt_base)
{
return nes_vram_queue_try_write(nes_attr_base_from_nt(nt_base), nes_attr_shadow, 64);
}nes_attr_shadow_clear
Remplit les 64 octets du miroir avec la même valeur compactée.
Syntaxe
void nes_attr_shadow_clear(unsigned char value);Paramètres
valueOctet d’attribut compacté ; par exemple, 0x55 choisit la palette 1 dans tous les quadrants, 0xAA choisit la palette 2.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Le miroir d’attributs partagé de 64 octets occupe la RAM CPU $03E0..$041F ; réservez cette zone. Un octet d’attribut couvre 4×4 tuiles ; chaque champ de deux bits choisit la palette d’un quadrant de 2×2 tuiles.
Exemple d’utilisation
nes_attr_shadow_clear(0x55);result[2]=nes_attr_shadow[63];Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Combinez transferts de lignes, rectangles à pas mémoire, remplissages et tables complètes. Deux barres rouges de 32×8 apparaissent au-dessus d’un carré bleu de 16×16 et de rectangles rouges de 16×24/32×24. Les transferts directs et par file dessinent à des positions distinctes.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/nametable_asset.h:13
Fill all 64 shadow bytes with an already-packed attribute value.
kitaqfc/lib/nametable_asset.c:36
void nes_attr_shadow_clear(unsigned char value)
{
__memset(nes_attr_shadow, value, 64);
}nes_attr_shadow_copy
Copie une table d’attributs complète en RAM comme point de départ des modifications.
Syntaxe
void nes_attr_shadow_copy(unsigned char* src64);Paramètres
src64Table d’attributs compactée de 64 octets lisibles, et non tableau d’identifiants de palette par tuile.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Le miroir d’attributs partagé de 64 octets occupe la RAM CPU $03E0..$041F ; réservez cette zone. Un octet d’attribut couvre 4×4 tuiles ; chaque champ de deux bits choisit la palette d’un quadrant de 2×2 tuiles.
Exemple d’utilisation
for(i=0;i<64;i++)table[i]=0x55;nes_attr_shadow_copy(table);result[3]=nes_attr_shadow[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
Combinez transferts de lignes, rectangles à pas mémoire, remplissages et tables complètes. Deux barres rouges de 32×8 apparaissent au-dessus d’un carré bleu de 16×16 et de rectangles rouges de 16×24/32×24. Les transferts directs et par file dessinent à des positions distinctes.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/nametable_asset.h:15
Copy an entire packed attribute table into shadow RAM without writing the PPU.
kitaqfc/lib/nametable_asset.c:42
void nes_attr_shadow_copy(unsigned char* src64)
{
__memcpy(nes_attr_shadow, src64, 64);
}nes_attr_shadow_set_quad
Remplace la palette d’un quadrant de 2×2 tuiles en préservant les autres champs de son octet.
Syntaxe
void nes_attr_shadow_set_quad(unsigned char tile_x, unsigned char tile_y, unsigned char pal_index);Paramètres
tile_xColonne de tuile gauche, plage visible de 0 à 31.
tile_yLigne de tuile supérieure, plage visible de 0 à 29.
pal_indexLes deux bits de poids faible de l’indice de palette.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Le miroir d’attributs partagé de 64 octets occupe la RAM CPU $03E0..$041F ; réservez cette zone. Un octet d’attribut couvre 4×4 tuiles ; chaque champ de deux bits choisit la palette d’un quadrant de 2×2 tuiles.
Gardez les coordonnées inférieures à 32. Les coordonnées impaires choisissent le quadrant 2×2 qui les contient. Les lignes visibles vont de 0 à 29.
Exemple d’utilisation
nes_attr_shadow_set_quad(4,8,2);result[4]=nes_attr_shadow[17];Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Combinez transferts de lignes, rectangles à pas mémoire, remplissages et tables complètes. Deux barres rouges de 32×8 apparaissent au-dessus d’un carré bleu de 16×16 et de rectangles rouges de 16×24/32×24. Les transferts directs et par file dessinent à des positions distinctes.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/nametable_asset.h:18
Replace only the chosen quadrant's palette bits, preserving its neighbors. Palette IDs are masked to two bits; tile coordinates must fit the shadow table.
kitaqfc/lib/nametable_asset.c:72
void nes_attr_shadow_set_quad(unsigned char tile_x, unsigned char tile_y, unsigned char pal_index)
{
unsigned char idx;
unsigned char shift;
unsigned char mask;
unsigned char value;
idx = nes_attr_index(tile_x, tile_y);
shift = nes_attr_shift(tile_x, tile_y);
pal_index = (unsigned char)(pal_index & 3);
value = nes_attr_shadow[idx];
mask = (unsigned char)(3 << shift);
value = (unsigned char)(value & (unsigned char)(~mask));
value = (unsigned char)(value | (unsigned char)(pal_index << shift));
nes_attr_shadow[idx] = value;
}nes_nametable_apply_now
Transfère 960 identifiants de tuile, puis une table d’attributs de 64 octets.
Syntaxe
void nes_nametable_apply_now(unsigned short nt_base, unsigned char* nam960, unsigned char* attr64);Paramètres
nt_baseBase logique de table de noms $2000/$2400/$2800/$2C00 ; le miroir détermine leur indépendance physique.
nam960Tableau de 32×30 tuiles rangé par lignes.
attr64Soixante-quatre octets d’attributs compactés ; il ne doit pas nécessairement s’agir du miroir partagé.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Pour les transferts directs, réglez l’incrément PPUCTRL sur un et utilisez une phase de configuration sans rendu ou un VBlank assez long pour le transfert. Ces fonctions auxiliaires ne désactivent pas le rendu et n’attendent pas.
Un transfert synchrone de 1024 octets se fait normalement pendant la configuration avec le rendu désactivé. Cette fonction ne le répartit pas sur plusieurs trames.
Exemple d’utilisation
nes_nametable_apply_now(0x2000,empty,table);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Combinez transferts de lignes, rectangles à pas mémoire, remplissages et tables complètes. Deux barres rouges de 32×8 apparaissent au-dessus d’un carré bleu de 16×16 et de rectangles rouges de 16×24/32×24. Les transferts directs et par file dessinent à des positions distinctes.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/nametable_asset.h:41
Upload 960 tile bytes followed by 64 attribute bytes. This bulk operation does not disable rendering or wait for VBlank on its own.
kitaqfc/lib/nametable_asset.c:178
void nes_nametable_apply_now(unsigned short nt_base, unsigned char* nam960, unsigned char* attr64)
{
nes_ppu_stream_write(nt_base, nam960, 960);
nes_ppu_stream_write(nes_attr_base_from_nt(nt_base), attr64, 64);
}nes_nt_base_from_index
Calcule une base logique de table de noms à partir des deux bits de poids faible de l’indice.
Syntaxe
unsigned short nes_nt_base_from_index(unsigned char index);Paramètres
indexIndice ; 0..3 choisissent les tables, les valeurs supérieures rebouclent sur les deux bits de poids faible.
Valeur renvoyée
Renvoie $2000 + (index & 3)*$400.
Exemple d’utilisation
result[0]=nes_nt_base_from_index(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
Combinez transferts de lignes, rectangles à pas mémoire, remplissages et tables complètes. Deux barres rouges de 32×8 apparaissent au-dessus d’un carré bleu de 16×16 et de rectangles rouges de 16×24/32×24. Les transferts directs et par file dessinent à des positions distinctes.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/nametable_asset.h:9
Mask the index to the four logical nametables and return its PPU base. Physical storage still depends on the cartridge's mirroring configuration.
kitaqfc/lib/nametable_asset.c:22
unsigned short nes_nt_base_from_index(unsigned char index)
{
index = (unsigned char)(index & 3);
return (unsigned short)(0x2000 + ((unsigned short)index << 10));
}nes_nt_queue_fill_rect
Met en file le remplissage de chaque ligne du rectangle avec un identifiant de tuile unique.
Syntaxe
unsigned char nes_nt_queue_fill_rect(unsigned short nt_base, unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height, unsigned char value);Paramètres
nt_baseBase logique de table de noms $2000/$2400/$2800/$2C00 ; le miroir détermine leur indépendance physique.
tile_xColonne de tuile gauche, plage visible de 0 à 31.
tile_yLigne de tuile supérieure, plage visible de 0 à 29.
widthLargeur en tuiles.
heightHauteur en tuiles.
valueIdentifiant de tuile de remplissage, de 0 à 255.
Valeur renvoyée
Renvoie 1 après toutes les lignes ou pour une hauteur nulle, 0 si la mise en file échoue.
Conditions et limites
Liez runtime.c. La file copie les données pour une NMI ultérieure ou une application sûre avec le rendu désactivé. Sérialisez la production et la consommation. Si une opération multiligne manque de place, les lignes déjà acceptées restent en file.
Gardez coordonnées et étendues dans la table de noms visible ; normalement, pitch≥width. Aucun découpage n’est effectué. Les lignes mises en file doivent avoir au plus 127 octets ; un rectangle ordinaire de table de noms a au plus 32 tuiles de large.
Exemple d’utilisation
result[10]=nes_nt_queue_fill_rect(0x2000,16,8,4,3,1);result[11]=nes_vram_queue_used;nes_vram_queue_nmi_flush();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Combinez transferts de lignes, rectangles à pas mémoire, remplissages et tables complètes. Deux barres rouges de 32×8 apparaissent au-dessus d’un carré bleu de 16×16 et de rectangles rouges de 16×24/32×24. Les transferts directs et par file dessinent à des positions distinctes.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/nametable_asset.h:38
Queue one fill record per row, stopping on failure while retaining previously queued rows. The runtime fill-length and rectangle bounds requirements apply.
kitaqfc/lib/nametable_asset.c:157
unsigned char nes_nt_queue_fill_rect(unsigned short nt_base, unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height, unsigned char value)
{
unsigned char row;
unsigned short ppu_addr;
row = 0;
while (row != height)
{
ppu_addr = (unsigned short)(nt_base + ((unsigned short)(tile_y + row) << 5) + tile_x);
if (nes_vram_queue_try_fill(ppu_addr, value, width) == 0)
{
return 0;
}
row = (unsigned char)(row + 1);
}
return 1;
}nes_nt_queue_rect
Copie la source de chaque ligne du rectangle dans la file.
Syntaxe
unsigned char nes_nt_queue_rect(unsigned short nt_base, unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height, unsigned char pitch, unsigned char* src);Paramètres
nt_baseBase logique de table de noms $2000/$2400/$2800/$2C00 ; le miroir détermine leur indépendance physique.
tile_xColonne de tuile gauche, plage visible de 0 à 31.
tile_yLigne de tuile supérieure, plage visible de 0 à 29.
widthLargeur en tuiles.
heightHauteur en tuiles.
pitchPas en octets entre les débuts de lignes de la source ; permet de sauter le remplissage de fin de ligne.
srcSource lisible couvrant au moins (height−1)*pitch+width octets.
Valeur renvoyée
Renvoie 1 après toutes les lignes ou pour une hauteur nulle, 0 si la mise en file échoue.
Conditions et limites
Liez runtime.c. La file copie les données pour une NMI ultérieure ou une application sûre avec le rendu désactivé. Sérialisez la production et la consommation. Si une opération multiligne manque de place, les lignes déjà acceptées restent en file.
Gardez coordonnées et étendues dans la table de noms visible ; normalement, pitch≥width. Aucun découpage n’est effectué. Les lignes mises en file doivent avoir au plus 127 octets ; un rectangle ordinaire de table de noms a au plus 32 tuiles de large.
Exemple d’utilisation
result[8]=nes_nt_queue_rect(0x2000,10,8,2,3,4,patch);result[9]=nes_vram_queue_used;nes_vram_queue_nmi_flush();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Combinez transferts de lignes, rectangles à pas mémoire, remplissages et tables complètes. Deux barres rouges de 32×8 apparaissent au-dessus d’un carré bleu de 16×16 et de rectangles rouges de 16×24/32×24. Les transferts directs et par file dessinent à des positions distinctes.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/nametable_asset.h:35
Copy rows into the runtime queue until complete or full. Failure leaves earlier rows queued; it does not roll back a partially admitted rectangle. Widths must respect the queue literal-record limit. Pitch is source bytes per row. Each copied literal record costs width+3 queue bytes; check total admission needs when partial updates are unacceptable.
kitaqfc/lib/nametable_asset.c:137
unsigned char nes_nt_queue_rect(unsigned short nt_base, unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height, unsigned char pitch, unsigned char* src)
{
unsigned char row;
unsigned short ppu_addr;
row = 0;
while (row != height)
{
ppu_addr = (unsigned short)(nt_base + ((unsigned short)(tile_y + row) << 5) + tile_x);
if (nes_vram_queue_try_write(ppu_addr, src, width) == 0)
{
return 0;
}
src = src + pitch;
row = (unsigned char)(row + 1);
}
return 1;
}nes_nt_queue_row
Copie une ligne complète de 32 tuiles dans la file.
Syntaxe
unsigned char nes_nt_queue_row(unsigned short nt_base, unsigned char row, unsigned char* src32);Paramètres
nt_baseBase logique de table de noms $2000/$2400/$2800/$2C00 ; le miroir détermine leur indépendance physique.
rowLigne de 0 à 29 ; les limites ne sont pas vérifiées.
src32Trente-deux identifiants de tuile lisibles.
Valeur renvoyée
Renvoie 1 si accepté, 0 si la file est pleine ; utilise 35 octets de file.
Conditions et limites
Liez runtime.c. La file copie les données pour une NMI ultérieure ou une application sûre avec le rendu désactivé. Sérialisez la production et la consommation. Si une opération multiligne manque de place, les lignes déjà acceptées restent en file.
Exemple d’utilisation
result[7]=nes_nt_queue_row(0x2000,4,row);nes_vram_queue_nmi_flush();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Combinez transferts de lignes, rectangles à pas mémoire, remplissages et tables complètes. Deux barres rouges de 32×8 apparaissent au-dessus d’un carré bleu de 16×16 et de rectangles rouges de 16×24/32×24. Les transferts directs et par file dessinent à des positions distinctes.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/nametable_asset.h:26
Copy one complete nametable row into the runtime queue.
kitaqfc/lib/nametable_asset.c:111
unsigned char nes_nt_queue_row(unsigned short nt_base, unsigned char row, unsigned char* src32)
{
unsigned short ppu_addr;
ppu_addr = (unsigned short)(nt_base + ((unsigned short)row << 5));
return nes_vram_queue_try_write(ppu_addr, src32, 32);
}nes_nt_stream_rect
Pour chaque ligne du rectangle, lit selon le pas de la source et transfère directement au PPU.
Syntaxe
void nes_nt_stream_rect(unsigned short nt_base, unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height, unsigned char pitch, unsigned char* src);Paramètres
nt_baseBase logique de table de noms $2000/$2400/$2800/$2C00 ; le miroir détermine leur indépendance physique.
tile_xColonne de tuile gauche, plage visible de 0 à 31.
tile_yLigne de tuile supérieure, plage visible de 0 à 29.
widthLargeur en tuiles.
heightHauteur en tuiles.
pitchPas en octets entre les débuts de lignes de la source ; permet de sauter le remplissage de fin de ligne.
srcSource lisible couvrant au moins (height−1)*pitch+width octets.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Pour les transferts directs, réglez l’incrément PPUCTRL sur un et utilisez une phase de configuration sans rendu ou un VBlank assez long pour le transfert. Ces fonctions auxiliaires ne désactivent pas le rendu et n’attendent pas.
Gardez coordonnées et étendues dans la table de noms visible ; normalement, pitch≥width. Aucun découpage n’est effectué. Les lignes mises en file doivent avoir au plus 127 octets ; un rectangle ordinaire de table de noms a au plus 32 tuiles de large.
Exemple d’utilisation
// A pitch of four skips two source bytes at the end of each row.
nes_nt_stream_rect(0x2000,4,8,2,2,4,patch);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Combinez transferts de lignes, rectangles à pas mémoire, remplissages et tables complètes. Deux barres rouges de 32×8 apparaissent au-dessus d’un carré bleu de 16×16 et de rectangles rouges de 16×24/32×24. Les transferts directs et par file dessinent à des positions distinctes.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/nametable_asset.h:29
Write each rectangle row immediately, advancing source by pitch rather than width. Caller-provided coordinates, storage and timing are not clipped or checked.
kitaqfc/lib/nametable_asset.c:120
void nes_nt_stream_rect(unsigned short nt_base, unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height, unsigned char pitch, unsigned char* src)
{
unsigned char row;
unsigned short ppu_addr;
row = 0;
while (row != height)
{
ppu_addr = (unsigned short)(nt_base + ((unsigned short)(tile_y + row) << 5) + tile_x);
nes_ppu_stream_write(ppu_addr, src, width);
src = src + pitch;
row = (unsigned char)(row + 1);
}
}nes_nt_stream_row
Copie directement dans le PPU une ligne complète de 32 tuiles.
Syntaxe
void nes_nt_stream_row(unsigned short nt_base, unsigned char row, unsigned char* src32);Paramètres
nt_baseBase logique de table de noms $2000/$2400/$2800/$2C00 ; le miroir détermine leur indépendance physique.
rowLigne de 0 à 29 ; les limites ne sont pas vérifiées.
src32Trente-deux identifiants de tuile lisibles.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Pour les transferts directs, réglez l’incrément PPUCTRL sur un et utilisez une phase de configuration sans rendu ou un VBlank assez long pour le transfert. Ces fonctions auxiliaires ne désactivent pas le rendu et n’attendent pas.
Exemple d’utilisation
nes_nt_stream_row(0x2000,2,row);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Combinez transferts de lignes, rectangles à pas mémoire, remplissages et tables complètes. Deux barres rouges de 32×8 apparaissent au-dessus d’un carré bleu de 16×16 et de rectangles rouges de 16×24/32×24. Les transferts directs et par file dessinent à des positions distinctes.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch3_nametable.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch3_nametable.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/nametable_asset.h:24
Write one complete 32-tile row directly. The caller validates the row and PPU timing.
kitaqfc/lib/nametable_asset.c:103
void nes_nt_stream_row(unsigned short nt_base, unsigned char row, unsigned char* src32)
{
unsigned short ppu_addr;
ppu_addr = (unsigned short)(nt_base + ((unsigned short)row << 5));
nes_ppu_stream_write(ppu_addr, src32, 32);
}nes_game.h — Macros d'opérations pour les jeux
nes_game.h fournit des noms de macros lisibles pour les files VRAM, l’OAM et les métasprites, les manettes, les interruptions du mapper, le défilement scindé et les opérations FDS. Chaque macro se développe en un intrinsèque : les diagnostics et les métadonnées KUROSAKI conservent donc l’opération matérielle sous-jacente. Les macros de file utilisent la file intrinsèque ; la macro DMA de l’OAM n’a pas d’argument.
Choisissez explicitement les en-têtes : nes_game.h et l’en-tête général fc.h définissent les macros. Pour les fonctions C, incluez runtime.h ou metasprite.h et liez leurs implémentations sans ces macros, ou supprimez d’abord les macros en conflit avec #undef. La macro DMA sans argument n’accepte pas l’argument page de la fonction C.
nes_fds_farcall
Macro utilitaire d’appel interbanque FDS dans nes_game.h. Se développe en __fds_overlay_farcall((bank), (func)).
Syntaxe
#define nes_fds_farcall(bank, func) __fds_overlay_farcall((bank), (func))Paramètres
bankExpression représentant la banque. Elle est évaluée une fois avant l’appel, mais la banque réellement chargée est déterminée par l’emplacement de func après l’édition de liens. Cela n’appelle pas une adresse dans une banque arbitraire choisie à l’exécution. Passez une valeur correspondante, comme
__bankof(func).funcNom d’une fonction déclarée sans paramètre. L’exemple passe
u8 overlay_answer(void). Les adresses numériques, les pointeurs de fonction à l’exécution et les fonctions demandant des arguments sont refusés. Utilisez un appel ordinairetarget(a, b)si des arguments sont nécessaires.
Valeur renvoyée
Résultat sur huit bits de la fonction cible. Si le chargement échoue mais que la banque précédente peut être restaurée, la cible n’est pas appelée et l’octet d’erreur de chargement est renvoyé à la place. Définissez une convention de résultat qui distingue une erreur d’un résultat normal.
Conditions et limites
Utilisez cette API avec --mapper=fds --fds-layout=fds32. La banque 0 contient le code commun à $A000–$DFFF. La banque 1 occupe $6000–$9FFF au démarrage ; les banques 2 et suivantes sont des overlays chargés dans cette même fenêtre de 16 Kio. Placez le code ou les données d’un overlay avec une directive telle que #pragma fixed_bank 2.
La banque 1 est restaurée depuis un fichier PRG de démarrage distinct de 16 384 octets à $6000. Sans manifeste, les fichiers par défaut ont l’ID 0 pour la banque 1, l’ID 1 pour le code commun et l’ID 2 pour CHR. Un manifeste personnalisé doit scinder le PRG de démarrage en fichiers de 16 384 octets à $6000 et $A000. Pour les banques à partir de 2, l’identifiant est --fds-overlay-start-id (32 par défaut) + numéro de banque − 2.
Lors d’un appel vers une autre banque, la banque précédente est mémorisée puis restaurée avant le retour. Les appels imbriqués suivent la même règle. Une restauration est également tentée après un transfert partiellement échoué. Si la restauration échoue elle-même, l’exécution s’arrête dans le code commun au lieu de revenir à du code écrasé. Les appels vers la banque commune ou la même banque évitent les transferts inutiles.
Les appels BIOS sont synchrones ; cette API ne fait pas avancer la boucle de jeu une fois par image pendant un chargement. Utilisez-la depuis le code de contrôle ordinaire de la banque commune, et non depuis un gestionnaire d’interruption. La continuité de l’affichage et de l’audio ainsi que la coexistence avec le véritable BIOS doivent être vérifiées séparément.
Ces captures utilisent un programme de test original de la convention d’appel LoadFiles pour vérifier le code CPU compilé, les transferts mémoire et chaque pixel affiché. Elles ne vérifient ni le véritable BIOS, ni la durée des transferts disque, ni le CRC, ni le démarrage sur matériel réel. Le modèle de contrôleur FDS de KUROSAKI est partiel ; une exécution ordinaire sans ce programme de test ne prouve pas les mêmes résultats de transfert.
La première commande de compilation ci-dessous construit l’exemple téléchargeable. Le vérificateur Python compile les cinq leçons avec et sans optimisation, puis les vérifie dans KUROSAKI. Il crée et supprime un programme de test temporaire à partir de scripts/fds_abi_fixture.py ; ces vérifications ne nécessitent aucun BIOS externe. Ce programme de test n’est pas un BIOS pour les jeux ordinaires.
Exemple d’utilisation
#pragma fixed_bank 0
#include "fc_fds_scene.h"
u8 choose_overlay(void){fds_result[2]++;return 2;}
#pragma fixed_bank 2
u8 overlay_answer(void){fds_result[1]++;fds_result[3]=__fds_current_bank();return 42;}
#pragma fixed_bank 0
void main(void) {
__irq_disable();fds_result[1]=0;fds_result[2]=0;
fds_result[0]=nes_fds_farcall(choose_overlay(),overlay_answer);
fds_result[4]=__fds_current_bank();fds_result[15]=165;
fds_call_screen();while(1){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
Avec le programme de test original de l’ABI LoadFiles, RETURN VALUE vaut 042 ; CALLBACK COUNT et BANK EXPR COUNT valent chacun 001 ; BANK IN CALLBACK vaut 002 et BANK AFTER RETURN vaut 001. La fonction et l’expression de banque ont été exécutées une fois chacune, et la banque 1 a été restaurée après l’appel à la banque 2. Ce n’est pas une capture d’un véritable test de transfert disque.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\fds_call_alias.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fds_call_alias.fds --mapper=fds --fds-layout=fds32 --fds-no-license-bypass --fds-overlay-trim --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm
python .\kitaq-docs\tools\check_fds_load_examples.pyImplémentation et source
kitaqfc/lib/nes_game.h:41
nes_fds_load_bank
Forme macro de __fds_load_bank() dans nes_game.h, pour charger explicitement une banque logique via l’en-tête utilitaire du jeu.
Syntaxe
#define nes_fds_load_bank(bank) __fds_load_bank((bank))Paramètres
bankBanque logique à charger, de 1 à 254. La banque 0 est du code commun, pas une fenêtre chargeable ; 255 est réservé à une résidence inconnue. À partir de la banque 2, l’identifiant de fichier calculé doit aussi tenir dans 0..254.
Valeur renvoyée
Zéro en cas de succès. Renvoie 255 pour les banques 0 ou 255, un dépassement de l’identifiant de fichier ou une banque 1 sans fichier de restauration. Un transfert BIOS échoué renvoie son octet d’erreur. Une erreur d’argument avant le transfert conserve la banque mémorisée ; un échec de transfert BIOS la marque 255 (inconnue).
Conditions et limites
Utilisez cette API avec --mapper=fds --fds-layout=fds32. La banque 0 contient le code commun à $A000–$DFFF. La banque 1 occupe $6000–$9FFF au démarrage ; les banques 2 et suivantes sont des overlays chargés dans cette même fenêtre de 16 Kio. Placez le code ou les données d’un overlay avec une directive telle que #pragma fixed_bank 2.
Se développe en __fds_load_bank((bank)) sans évaluer bank plusieurs fois. Les limites d’arguments, la vérification de résidence et le comportement en cas d’erreur sont ceux de l’intrinsèque.
La banque 1 est restaurée depuis un fichier PRG de démarrage distinct de 16 384 octets à $6000. Sans manifeste, les fichiers par défaut ont l’ID 0 pour la banque 1, l’ID 1 pour le code commun et l’ID 2 pour CHR. Un manifeste personnalisé doit scinder le PRG de démarrage en fichiers de 16 384 octets à $6000 et $A000. Pour les banques à partir de 2, l’identifiant est --fds-overlay-start-id (32 par défaut) + numéro de banque − 2.
Avec la vérification de résidence par défaut, une banque déjà enregistrée renvoie zéro sans lecture disque. --fds-no-overlay-guard désactive ce raccourci dans __fds_load_bank(). Un chargement réussi mémorise la banque demandée. Cette information ne valide pas le contenu de la mémoire.
Charger une autre banque directement depuis du code dans la fenêtre $6000–$9FFF peut écraser la fonction en cours ou son adresse de retour. Cet exemple place l’appelant et le code d’affichage dans #pragma fixed_bank 0. Pour appeler une fonction d’une autre banque puis revenir, utilisez __fds_overlay_farcall() ou un appel de fonction typé ordinaire.
Les appels BIOS sont synchrones ; cette API ne fait pas avancer la boucle de jeu une fois par image pendant un chargement. Utilisez-la depuis le code de contrôle ordinaire de la banque commune, et non depuis un gestionnaire d’interruption. La continuité de l’affichage et de l’audio ainsi que la coexistence avec le véritable BIOS doivent être vérifiées séparément.
Ces captures utilisent un programme de test original de la convention d’appel LoadFiles pour vérifier le code CPU compilé, les transferts mémoire et chaque pixel affiché. Elles ne vérifient ni le véritable BIOS, ni la durée des transferts disque, ni le CRC, ni le démarrage sur matériel réel. Le modèle de contrôleur FDS de KUROSAKI est partiel ; une exécution ordinaire sans ce programme de test ne prouve pas les mêmes résultats de transfert.
La première commande de compilation ci-dessous construit l’exemple téléchargeable. Le vérificateur Python compile les cinq leçons avec et sans optimisation, puis les vérifie dans KUROSAKI. Il crée et supprime un programme de test temporaire à partir de scripts/fds_abi_fixture.py ; ces vérifications ne nécessitent aucun BIOS externe. Ce programme de test n’est pas un BIOS pour les jeux ordinaires.
Exemple d’utilisation
#pragma fixed_bank 0
#include "fc_fds_scene.h"
#pragma fixed_bank 2
__prg_rom u8 bank_payload[4]={11,22,33,44};
#pragma fixed_bank 0
void main(void) {
__irq_disable();
fds_result[0]=__fds_load_bank(2);
fds_result[1]=__fds_current_bank();
fds_result[2]=__fds_require_bank(2);
fds_result[3]=bank_payload[0];fds_result[4]=bank_payload[3];
fds_result[5]=nes_fds_load_bank(1);
fds_result[6]=__fds_current_bank();
fds_result[7]=__fds_require_bank(1);
fds_result[8]=__fds_load_bank(0);
fds_result[9]=__fds_load_bank(255);
fds_result[15]=165;
m_init();m_text(2,2,"FDS DATA WINDOW");m_wait();
m_text(2,5,"LOAD BANK 2 STATUS");fds_number(25,5,fds_result[0]);m_wait();
m_text(2,7,"FIRST / LAST BYTE");fds_number(21,7,fds_result[3]);fds_number(25,7,fds_result[4]);m_wait();
m_text(2,9,"REQUIRE SAME BANK");fds_number(25,9,fds_result[2]);m_wait();
m_text(2,11,"RESTORE BANK 1");fds_number(25,11,fds_result[5]);m_wait();
m_text(2,13,"RESIDENT BANK");fds_number(25,13,fds_result[6]);m_wait();
m_text(2,16,"INVALID BANKS 0 / 255");m_wait();
fds_number(2,18,fds_result[8]);fds_number(8,18,fds_result[9]);m_wait();
while(1){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
Avec le programme de test original de l’ABI LoadFiles, LOAD BANK 2 STATUS, REQUIRE SAME BANK et RESTORE BANK 1 valent tous 000. FIRST / LAST BYTE affiche 011 et 044, issus des quatre octets transférés ; RESIDENT BANK vaut 001 après restauration. Les banques invalides 0 et 255 renvoient chacune 255. Demander la même banque ne provoque aucun chargement supplémentaire : les requêtes de fichiers vérifiées sont 32, puis 0.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\fds_bank_load.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fds_bank_load.fds --mapper=fds --fds-layout=fds32 --fds-no-license-bypass --fds-overlay-trim --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasm
python .\kitaq-docs\tools\check_fds_load_examples.pyImplémentation et source
kitaqfc/lib/nes_game.h:40
nes_fds_wave_load
Macro transmettant son tableau à __fds_wave_load pour charger une onde de 64 octets.
Syntaxe
#define nes_fds_wave_load(wave64) __fds_wave_load((wave64))Paramètres
wave64Soixante-quatre octets d’onde FDS, chacun représentant une amplitude sur six bits de 0 à 63. NULL n’est pas vérifié.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Construisez une image .fds avec --mapper=fds. Cette leçon utilise le son sans entrées/sorties disque. L’enregistrement passe par le démarrage direct en RAM et le modèle audio de KUROSAKI. Le micrologiciel de test vide n’implémente aucune routine BIOS et n’est pas distribué. Le démarrage disque normal et le matériel réel nécessitent un environnement d’amorçage adapté.
Exemple d’utilisation
// Mapper 20 sound lesson: original 64-step triangle and two sustained pitches.
#include "fc_sound_example.h"
#include "fds_sound.h"
#include "nes_game.h"
__location(0x4087) u8 mod_control;
__location(0x4085) u8 mod_counter;
u8 triangle[64]; u8 modulation[32];
void main(void) {
u8 i;
sound_begin("FDS WAVE AND VOLUME");
for(i=0;i<32;i++) { triangle[i]=(u8)(i*2); triangle[63-i]=(u8)(i*2); modulation[i]=0; }
__fds_sound_enable();
// Halt/reset modulation before writing the 32 values (each writes two slots).
mod_control=0x80; mod_counter=0;
__fds_mod_load(modulation);
__fds_wave_load(triangle);
sound_result[0]=*((u8*)0x4040); sound_result[1]=*((u8*)0x405F);
__fds_freq_set(1031);
__fds_volume_set(24);
sound_wait(60);
__fds_volume_set(0); sound_wait(30);
// This macro forwards the same 64-byte load. Use raw envelope registers.
nes_fds_wave_load(triangle);
__fds_env_set(0x98,0x80,0);
__fds_freq_set(1545);
sound_wait(60);
__fds_volume_set(0); sound_wait(30);
sound_end();
}Résultat attendu
Un triangle original de 64 pas joue à environ 440 Hz, s’interrompt, joue à environ 660 Hz puis s’arrête. La seconde note utilise nes_fds_wave_load et des réglages bruts d’enveloppe. Cela vérifie le modèle audio et le démarrage direct, pas l’amorçage disque par BIOS.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_fds.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-fds.fds --mapper=fds --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/nes_game.h:39
#define nes_fds_wave_load(wave64) __fds_wave_load((wave64))nes_mapper_irq_ack
Macro d’acquittement du gestionnaire dans nes_game.h. Se développe en __mapper_irq_ack(), effaçant et désactivant la demande en même temps.
Syntaxe
#define nes_mapper_irq_ack() __mapper_irq_ack()Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Les déclarations des intrinsèques sont dans intrinsics.h. Incluez nes_game.h pour les macros nes_mapper_irq_*. Choisissez la carte à la compilation avec --mapper.
MMC3 uniquement. Fournissez un gestionnaire __nes_irq, des transitions PPU A12 admissibles, l’activation IRQ du mapper et __irq_enable() côté CPU. L’exemple active le rendu avec les motifs de fond à $0000 et les sprites à $1000. Cette leçon ne vérifie pas la synchronisation sur une ligne exacte du matériel réel.
L’acquittement et la désactivation MMC3 écrivent tous deux dans $E000. Cela efface la demande actuelle et désactive les suivantes. Rappelez __mapper_irq_enable() au moment voulu pour armer une autre interruption. Aucune de ces opérations ne modifie le masque d’interruptions CPU ni l’activation NMI.
Le compilateur émet RTI pour un gestionnaire d’interruption personnalisé, mais celui-ci doit préserver les registres A/X/Y et les zones temporaires partagées qu’il modifie. L’exemple sauvegarde A/X/Y et n’utilise qu’un incrément d’octet et un acquittement sans argument. Si vous ajoutez des appels C, examinez aussi leur stockage partagé.
Exemple d’utilisation
void __nes_irq(void) {
__asm {
PHA
TXA
PHA
TYA
PHA
}
irq_count++;
if (irq_phase == 1) { nes_mapper_irq_ack(); }
else { __mapper_irq_ack(); }
__asm {
PLA
TAY
PLA
TAX
PLA
}
}Cet extrait montre l’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 MMC3 affiche les marqueurs CHR 19/20, 21/22 et 23/24. Les lectures CIRAM donnent A B A B en mirroring vertical et A A B B en horizontal. Les comptes IRQ sont 01→02→03→03 : chacune des trois premières activations explicites autorise une interruption ; le compteur reste fixe après désactivation. Chaque étape attend six images.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\mapper_controls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\mapper_controls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\mapper_banks.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/nes_game.h:36
nes_mapper_irq_disable
Désactive l’IRQ MMC3 et efface sa demande en attente via nes_game.h. Se développe en __mapper_irq_disable().
Syntaxe
#define nes_mapper_irq_disable() __mapper_irq_disable()Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Les déclarations des intrinsèques sont dans intrinsics.h. Incluez nes_game.h pour les macros nes_mapper_irq_*. Choisissez la carte à la compilation avec --mapper.
MMC3 uniquement. Fournissez un gestionnaire __nes_irq, des transitions PPU A12 admissibles, l’activation IRQ du mapper et __irq_enable() côté CPU. L’exemple active le rendu avec les motifs de fond à $0000 et les sprites à $1000. Cette leçon ne vérifie pas la synchronisation sur une ligne exacte du matériel réel.
L’acquittement et la désactivation MMC3 écrivent tous deux dans $E000. Cela efface la demande actuelle et désactive les suivantes. Rappelez __mapper_irq_enable() au moment voulu pour armer une autre interruption. Aucune de ces opérations ne modifie le masque d’interruptions CPU ni l’activation NMI.
Le compilateur émet RTI pour un gestionnaire d’interruption personnalisé, mais celui-ci doit préserver les registres A/X/Y et les zones temporaires partagées qu’il modifie. L’exemple sauvegarde A/X/Y et n’utilise qu’un incrément d’octet et un acquittement sans argument. Si vous ajoutez des appels C, examinez aussi leur stockage partagé.
Exemple d’utilisation
nes_mapper_irq_disable();
for (i=0;i<6;i++) { m_wait(); }
mapper_result[18]=irq_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 MMC3 affiche les marqueurs CHR 19/20, 21/22 et 23/24. Les lectures CIRAM donnent A B A B en mirroring vertical et A A B B en horizontal. Les comptes IRQ sont 01→02→03→03 : chacune des trois premières activations explicites autorise une interruption ; le compteur reste fixe après désactivation. Chaque étape attend six images.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\mapper_controls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\mapper_controls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\mapper_banks.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/nes_game.h:35
nes_mapper_irq_enable
Active l’IRQ MMC3 via nes_game.h. Se développe en __mapper_irq_enable() sans modifier le masque d’interruptions CPU.
Syntaxe
#define nes_mapper_irq_enable() __mapper_irq_enable()Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Les déclarations des intrinsèques sont dans intrinsics.h. Incluez nes_game.h pour les macros nes_mapper_irq_*. Choisissez la carte à la compilation avec --mapper.
MMC3 uniquement. Fournissez un gestionnaire __nes_irq, des transitions PPU A12 admissibles, l’activation IRQ du mapper et __irq_enable() côté CPU. L’exemple active le rendu avec les motifs de fond à $0000 et les sprites à $1000. Cette leçon ne vérifie pas la synchronisation sur une ligne exacte du matériel réel.
L’acquittement et la désactivation MMC3 écrivent tous deux dans $E000. Cela efface la demande actuelle et désactive les suivantes. Rappelez __mapper_irq_enable() au moment voulu pour armer une autre interruption. Aucune de ces opérations ne modifie le masque d’interruptions CPU ni l’activation NMI.
Le compilateur émet RTI pour un gestionnaire d’interruption personnalisé, mais celui-ci doit préserver les registres A/X/Y et les zones temporaires partagées qu’il modifie. L’exemple sauvegarde A/X/Y et n’utilise qu’un incrément d’octet et un acquittement sans argument. Si vous ajoutez des appels C, examinez aussi leur stockage partagé.
Exemple d’utilisation
nes_mapper_irq_set(15); nes_mapper_irq_enable();
for (i=0;i<6;i++) { m_wait(); }
mapper_result[16]=irq_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 MMC3 affiche les marqueurs CHR 19/20, 21/22 et 23/24. Les lectures CIRAM donnent A B A B en mirroring vertical et A A B B en horizontal. Les comptes IRQ sont 01→02→03→03 : chacune des trois premières activations explicites autorise une interruption ; le compteur reste fixe après désactivation. Chaque étape attend six images.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\mapper_controls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\mapper_controls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\mapper_banks.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/nes_game.h:34
nes_mapper_irq_set
Macro de réglage du verrou MMC3 dans nes_game.h. Transmet son argument une fois à __mapper_irq_set et demande un rechargement.
Syntaxe
#define nes_mapper_irq_set(scanline) __mapper_irq_set((scanline))Paramètres
scanlineValeur de verrouillage du compteur sur huit bits, de 0 à 255, et non une coordonnée Y absolue. Le moment du rechargement et les transitions PPU A12 admissibles déterminent le déclenchement. Zéro est valide et ne signifie pas « désactiver les interruptions ».
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Les déclarations des intrinsèques sont dans intrinsics.h. Incluez nes_game.h pour les macros nes_mapper_irq_*. Choisissez la carte à la compilation avec --mapper.
MMC3 uniquement. Fournissez un gestionnaire __nes_irq, des transitions PPU A12 admissibles, l’activation IRQ du mapper et __irq_enable() côté CPU. L’exemple active le rendu avec les motifs de fond à $0000 et les sprites à $1000. Cette leçon ne vérifie pas la synchronisation sur une ligne exacte du matériel réel.
L’acquittement et la désactivation MMC3 écrivent tous deux dans $E000. Cela efface la demande actuelle et désactive les suivantes. Rappelez __mapper_irq_enable() au moment voulu pour armer une autre interruption. Aucune de ces opérations ne modifie le masque d’interruptions CPU ni l’activation NMI.
Le compilateur émet RTI pour un gestionnaire d’interruption personnalisé, mais celui-ci doit préserver les registres A/X/Y et les zones temporaires partagées qu’il modifie. L’exemple sauvegarde A/X/Y et n’utilise qu’un incrément d’octet et un acquittement sans argument. Si vous ajoutez des appels C, examinez aussi leur stockage partagé.
Exemple d’utilisation
nes_mapper_irq_set(15); nes_mapper_irq_enable();
for (i=0;i<6;i++) { m_wait(); }
mapper_result[16]=irq_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 MMC3 affiche les marqueurs CHR 19/20, 21/22 et 23/24. Les lectures CIRAM donnent A B A B en mirroring vertical et A A B B en horizontal. Les comptes IRQ sont 01→02→03→03 : chacune des trois premières activations explicites autorise une interruption ; le compteur reste fixe après désactivation. Chaque étape attend six images.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\mapper_controls.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\mapper_controls.nes --mapper=mmc3 --nes-chr=.\kitaq-docs\samples\mapper_banks.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/nes_game.h:33
nes_oam_clear
Macro de nes_game.h : elle se développe en l’intrinsèque indiqué dans la syntaxe. Il suffit d’inclure cet en-tête ; aucun fichier d’implémentation C n’est nécessaire pour cette opération.
Masque les 64 sprites du tampon miroir de la page 02 en réglant chaque octet Y sur 0xF0. Les numéros de tuiles, les attributs et les coordonnées X sont conservés.
Syntaxe
#define nes_oam_clear() __oam_clear()Valeur renvoyée
Aucune (void).
Conditions et limites
Ces opérations modifient la RAM CPU 0x0200–0x02FF, sans mettre immédiatement à jour l’OAM matérielle. Transférez la page complète avec __oam_dma. Elles ne tiennent à jour ni les indicateurs d’allocation, ni les tableaux de coordonnées, ni le compteur de la bibliothèque de sprites. Évitez qu’une interruption modifie ou transfère une page encore en préparation.
Exemple d’utilisation
nes_sprite_set(63,144,111,128,0); // Seed the CLEAR row with a visible entry.
nes_oam_clear(); // Set every Y byte to 240; tile, attributes and X are retained.Cet extrait montre l’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éserve une ligne légendée à chaque opération. SET et MOVE montrent des flèches de 8×8 vers la droite en (144,16) et (144,32) ; TILE, un carré vert en (144,48) ; ATTR, la flèche retournée selon les deux axes en (144,64). HIDE en (144,80) et CLEAR en (144,112) doivent rester vides. META montre une paire en (136,96) et (144,96), la seconde flèche étant retournée horizontalement. NEXT 07 indique l’indice suivant après les entrées 5 et 6. Les bords sont rouges, la tige verte et les détails de la pointe bleus. La vérification compare 8 704 pixels par image et les octets OAM transférés ; le matériel physique n’a pas été testé.
Le programme ALIASES prépare les lignes avec les macros de nes_game.h et envoie la page 02 avec nes_oam_dma(). TRANSFER affiche la flèche 8×8 à (144,128). Cet exemple utilise les macros sans lier runtime.c ni metasprite.c.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\oam_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --nes-chr=.\kitaq-docs\samples\sprite_example.chr -o .\out\oam_aliases.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/nes_game.h:21
#define nes_oam_clear() __oam_clear()nes_oam_dma
Ce nom possède deux formes. La macro sans argument nes_oam_dma() transfère la page 02 via __oam_dma(). La fonction C nes_oam_dma(page) transfère la page CPU de 256 octets indiquée. Toutes deux remettent OAMADDR à zéro et transfèrent la page entière sans modifier la source.
Syntaxe
#define nes_oam_dma() __oam_dma()
// C function declared in runtime.h:
void nes_oam_dma(unsigned char page);Paramètres
page (C)Octet de poids fort de l’adresse CPU source : passez
4pour0x0400–0x04FF, et non0x0400. Fournissez une page complète de 256 octets lisibles et gardez le banc requis accessible. Évitez les pages contenant des registres d’E/S, dont la lecture peut avoir des effets de bord. La source n’est pas validée.
Valeur renvoyée
Aucune (void).
Conditions et limites
Choisissez explicitement les en-têtes : nes_game.h et l’en-tête général fc.h définissent les macros. Pour les fonctions C, incluez runtime.h ou metasprite.h et liez leurs implémentations sans ces macros, ou supprimez d’abord les macros en conflit avec #undef. La macro DMA sans argument n’accepte pas l’argument page de la fonction C.
Les fonctions C de métasprites nécessitent nes_oam_shadow[256]. runtime.c le définit à 0x0200, réserve également 0x0300–0x03BF pour sa file VRAM et fournit __nes_nmi. Incluez chaque implémentation une seule fois et coordonnez le gestionnaire d’interruption avec le reste du programme.
Appelez le DMA pendant VBlank ou avec le rendu désactivé. Aucune des deux formes n’attend VBlank. Préparez d’abord toute la page source, puis transférez-la ; empêchez une interruption de la modifier pendant sa préparation.
Exemple d’utilisation
m_wait();nes_oam_dma(); // Expand to the page-02 compiler intrinsic.Cet extrait montre l’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éserve une ligne légendée à chaque opération. SET et MOVE montrent des flèches de 8×8 vers la droite en (144,16) et (144,32) ; TILE, un carré vert en (144,48) ; ATTR, la flèche retournée selon les deux axes en (144,64). HIDE en (144,80) et CLEAR en (144,112) doivent rester vides. META montre une paire en (136,96) et (144,96), la seconde flèche étant retournée horizontalement. NEXT 07 indique l’indice suivant après les entrées 5 et 6. Les bords sont rouges, la tige verte et les détails de la pointe bleus. La vérification compare 8 704 pixels par image et les octets OAM transférés ; le matériel physique n’a pas été testé.
Le programme ALIASES prépare les lignes avec les macros de nes_game.h et envoie la page 02 avec nes_oam_dma(). TRANSFER affiche la flèche 8×8 à (144,128). Cet exemple utilise les macros sans lier runtime.c ni metasprite.c.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\oam_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --nes-chr=.\kitaq-docs\samples\sprite_example.chr -o .\out\oam_aliases.nes --no-cache --no-disasmExemple d’utilisation
m_wait();nes_oam_dma(4); // C function: source address high byte, 0x0400 -> 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
C-RUNTIME combine les fonctions C. PAIR affiche deux flèches 8×8 à (144,32) et (152,32), la seconde retournée horizontalement. Une autre paire à y=64 est masquée : HIDE RANGE doit rester vide. Les dessins successifs utilisent les entrées 4–5 et 6–7 et affichent NEXT 08. La page 02 est copiée vers la page 04, puis seule l’entrée 8 passe de la tuile flèche 128 au carré 129. nes_oam_dma(4) doit afficher un carré vert à (144,96), près de PAGE 04, tandis que la page 02 conserve la tuile 128.
Les flèches ont des bords rouges, une tige verte et des détails bleus à la pointe ; la tuile carrée 129 est verte. La vérification compare 8 704 pixels colorés et les 256 octets OAM transférés par image, ainsi que les libellés. Le matériel physique n’a pas été testé.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\oam_c_helpers.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --nes-chr=.\kitaq-docs\samples\sprite_example.chr -o .\out\oam_c_helpers.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/nes_game.h:23
kitaqfc/lib/runtime.c:245
void nes_oam_dma(unsigned char page)
{
OAMADDR = 0;
OAMDMA = page;
}nes_pad1
Macro de forme fonction qui se développe exactement en __pad_read1_safe(). Lit le contrôleur 1 et renvoie son masque NES brut ; ce n’est pas un alias de l’état mémorisé input_current().
Syntaxe
#define nes_pad1() __pad_read1_safe()Valeur renvoyée
Masque de maintien de 8 bits dans l’ordre NES. Chaque bit à 1 identifie un bouton appuyé ; 0 signifie aucun. Ce n’est pas un booléen normalisé.
Conditions et limites
Format NES brut : A=0x01, B=0x02, SELECT=0x04, START=0x08, UP=0x10, DOWN=0x20, LEFT=0x40, RIGHT=0x80. Un bit à 1 indique un appui. Utilisez ces valeurs avec nes_pad_* et les résultats bruts de __pad_*, et non les masques communs BTN_* de input.h.
Cet appel lit un nouvel état matériel. Il ne met pas à jour les états mémorisés input_* ou nes_pad1_* et ne produit ni événements d’appui ou de relâchement, ni répétitions. Mémorisez le résultat et comparez-le à votre masque précédent pour détecter les transitions.
La lecture sûre répète des paires de lectures complètes jusqu’à obtenir deux masques identiques. Chaque lecture active le strobe de $4016 et redémarre la lecture série des deux contrôleurs. Le nombre d’essais n’est pas limité. Ce contrôle ne prouve pas la compatibilité avec toutes les combinaisons DMC/périphériques.
Exemple d’utilisation
alias1=nes_pad1(); // Macro for __pad_read1_safe(), using NES raw bits.Cet extrait montre l’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 compare les deux ports, les lectures simples et avec vérification de concordance, les filtres et les macros abrégées. Maintenez A + droite sur la manette 1 et B + gauche sur la manette 2. RAW P1, SAFE P1 et ALIAS P1 valent 129 ; les trois valeurs P2 sont 66. BUTTONS P1 vaut 1 et DIRS P1 vaut 128 : le filtre des directions conserve la position des bits de poids fort. FAILED CHECKS doit valoir 0. Les valeurs restent affichées.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\input_raw.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_raw.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cacheImplémentation et source
kitaqfc/lib/nes_game.h:30
nes_pad2
Macro de forme fonction qui se développe exactement en __pad_read2_safe(). Lit le contrôleur 2 et renvoie son masque NES brut ; ce n’est pas un alias de l’état mémorisé input_current().
Syntaxe
#define nes_pad2() __pad_read2_safe()Valeur renvoyée
Masque de maintien de 8 bits dans l’ordre NES. Chaque bit à 1 identifie un bouton appuyé ; 0 signifie aucun. Ce n’est pas un booléen normalisé.
Conditions et limites
Format NES brut : A=0x01, B=0x02, SELECT=0x04, START=0x08, UP=0x10, DOWN=0x20, LEFT=0x40, RIGHT=0x80. Un bit à 1 indique un appui. Utilisez ces valeurs avec nes_pad_* et les résultats bruts de __pad_*, et non les masques communs BTN_* de input.h.
Cet appel lit un nouvel état matériel. Il ne met pas à jour les états mémorisés input_* ou nes_pad1_* et ne produit ni événements d’appui ou de relâchement, ni répétitions. Mémorisez le résultat et comparez-le à votre masque précédent pour détecter les transitions.
La lecture sûre répète des paires de lectures complètes jusqu’à obtenir deux masques identiques. Chaque lecture active le strobe de $4016 et redémarre la lecture série des deux contrôleurs. Le nombre d’essais n’est pas limité. Ce contrôle ne prouve pas la compatibilité avec toutes les combinaisons DMC/périphériques.
Exemple d’utilisation
alias2=nes_pad2(); // Macro for __pad_read2_safe(), using NES raw bits.Cet extrait montre l’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 compare les deux ports, les lectures simples et avec vérification de concordance, les filtres et les macros abrégées. Maintenez A + droite sur la manette 1 et B + gauche sur la manette 2. RAW P1, SAFE P1 et ALIAS P1 valent 129 ; les trois valeurs P2 sont 66. BUTTONS P1 vaut 1 et DIRS P1 vaut 128 : le filtre des directions conserve la position des bits de poids fort. FAILED CHECKS doit valoir 0. Les valeurs restent affichées.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\input_raw.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\input_raw.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cacheImplémentation et source
kitaqfc/lib/nes_game.h:31
nes_split_scroll_sprite0
Macro de séparation d’écran de nes_game.h. Transmet X et Y une fois chacun à __split_scroll_sprite0, avec la même attente et les mêmes écritures de défilement.
Syntaxe
#define nes_split_scroll_sprite0(x,y) __split_scroll_sprite0((x),(y))Paramètres
xDéfilement horizontal de 0 à 255, pas la position X d’un objet. L’exemple utilise 32 pour décaler de 32 pixels vers la gauche la partie inférieure du même fond.
yRéglage temporaire de défilement vertical de 0 à 255 ; la plage visible habituelle est 0..239. La fonction écrit $2005 et ne change donc pas immédiatement la position verticale active pendant le rendu. L’exemple de séparation horizontale passe zéro.
Valeur renvoyée
Aucune valeur de retour.
Conditions et limites
Faites chevaucher un pixel opaque du sprite OAM 0 et un pixel opaque du fond, les deux couches activées. La priorité derrière le fond permet toujours un hit. Les huit pixels de gauche nécessitent les autorisations de couche correspondantes ; un chevauchement en X=255 ne déclenche pas de hit.
Interroge le bit 6 de PPUSTATUS ($2002) jusqu’à son effacement, puis jusqu’à son activation. Si un hit a déjà eu lieu à l’appel, attend un nouveau hit à l’image suivante. Lire le drapeau ne l’acquitte pas ; le PPU l’efface pendant le pré-rendu.
Aucun délai d’expiration ni retour d’échec. Sprite 0 caché, fond transparent, rendu désactivé ou toute absence de chevauchement bloque l’appel. Assurez un hit avant d’appeler. L’activation IRQ CPU n’est pas nécessaire et la fonction n’active pas NMI. L’exemple active NMI pour son attente d’image distincte.
Lire $2002 affecte aussi le verrou partagé des écritures d’adresse/défilement et le drapeau VBlank. N’insérez pas cet appel entre les deux écritures d’une opération $2005/$2006. Utilisez-le depuis le code principal, pas un gestionnaire NMI/IRQ.
Après le hit, lit $2002 puis écrit X et Y dans $2005. X fin change immédiatement ; X grossier au prochain rechargement horizontal. Y s’applique normalement au prochain rechargement de pré-rendu, sauf remplacement préalable par une autre écriture. Ce n’est pas un repositionnement raster X/Y arbitraire immédiat.
L’interrogation et l’exécution des instructions retardent les écritures. KUROSAKI rend par ligne ; ces captures ne prouvent donc pas une frontière matérielle exacte au point près. L’exemple place le changement dans la bande blanche Y=96..103, loin des barres bleues et rouges.
L’en-tête partagé fc_sprite0_scene.h prépare des barres originales bleues/rouges et une bande blanche horizontale. Le sprite 0 est en (16,96), caché derrière le fond ; son Y OAM brut vaut 95 car Y affiché=Y OAM+1. Chaque image rétablit le défilement supérieur à zéro en VBlank avant d’attendre le hit.
NESdev : référence PPU pour les programmeurs
Exemple d’utilisation
void main(void) {
s0_prepare();
while (1) {
s0_frame();
nes_split_scroll_sprite0(32,0);
s0_completed++;
}
}Cet extrait montre l’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-dessus de la bande blanche, bleu en X=64..95 et rouge en X=160..191. En dessous, dès Y=104, ils passent à X=32..63 et X=128..159 : seule la zone inférieure se décale de 32 pixels vers la gauche. La bande est en Y=96..103 et les barres finissent à Y=207. La validation vérifie une terminaison par image et la position/couleur de chaque pixel.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite0_split_alias.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite0_split_alias.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\sprite0_scene.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/nes_game.h:37
nes_sprite_hide
Macro de nes_game.h : elle se développe en l’intrinsèque indiqué dans la syntaxe. Il suffit d’inclure cet en-tête ; aucun fichier d’implémentation C n’est nécessaire pour cette opération.
Masque un sprite du tampon miroir en réglant Y sur 0xF0. X, la tuile et les attributs restent disponibles pour sa réutilisation. La fonction ne libère aucune allocation et ne modifie pas le compteur de sprites actifs de la bibliothèque.
Syntaxe
#define nes_sprite_hide(i) __sprite_hide((i))Paramètres
iIndice du sprite, de 0 à 63, et non décalage en octets. Le calcul multiplie cet indice par quatre dans un curseur de 8 bits ; les valeurs hors plage sont ramenées modulo 64 et peuvent écraser une autre entrée. L’allocation n’est pas vérifiée.
Valeur renvoyée
Aucune (void).
Conditions et limites
Ces opérations modifient la RAM CPU 0x0200–0x02FF, sans mettre immédiatement à jour l’OAM matérielle. Transférez la page complète avec __oam_dma. Elles ne tiennent à jour ni les indicateurs d’allocation, ni les tableaux de coordonnées, ni le compteur de la bibliothèque de sprites. Évitez qu’une interruption modifie ou transfère une page encore en préparation.
Exemple d’utilisation
nes_sprite_hide(4); // The HIDE row remains empty after DMA.Cet extrait montre l’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éserve une ligne légendée à chaque opération. SET et MOVE montrent des flèches de 8×8 vers la droite en (144,16) et (144,32) ; TILE, un carré vert en (144,48) ; ATTR, la flèche retournée selon les deux axes en (144,64). HIDE en (144,80) et CLEAR en (144,112) doivent rester vides. META montre une paire en (136,96) et (144,96), la seconde flèche étant retournée horizontalement. NEXT 07 indique l’indice suivant après les entrées 5 et 6. Les bords sont rouges, la tige verte et les détails de la pointe bleus. La vérification compare 8 704 pixels par image et les octets OAM transférés ; le matériel physique n’a pas été testé.
Le programme ALIASES prépare les lignes avec les macros de nes_game.h et envoie la page 02 avec nes_oam_dma(). TRANSFER affiche la flèche 8×8 à (144,128). Cet exemple utilise les macros sans lier runtime.c ni metasprite.c.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\oam_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --nes-chr=.\kitaq-docs\samples\sprite_example.chr -o .\out\oam_aliases.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/nes_game.h:26
#define nes_sprite_hide(i) __sprite_hide((i))nes_sprite_move
Macro de nes_game.h : elle se développe en l’intrinsèque indiqué dans la syntaxe. Il suffit d’inclure cet en-tête ; aucun fichier d’implémentation C n’est nécessaire pour cette opération.
Modifie uniquement les octets X et Y d’un sprite du tampon miroir. La tuile et les attributs sont conservés : le même dessin se déplace sans changer de palette ni de retournement.
Syntaxe
#define nes_sprite_move(i,x,y) __sprite_move((i),(x),(y))Paramètres
iIndice du sprite, de 0 à 63, et non décalage en octets. Le calcul multiplie cet indice par quatre dans un curseur de 8 bits ; les valeurs hors plage sont ramenées modulo 64 et peuvent écraser une autre entrée. L’allocation n’est pas vérifiée.
xPosition horizontale en pixels, sous forme d’octet non signé ; ce n’est pas une coordonnée de tuile.
yOctet Y de l’OAM. Pour placer le haut sous la ligne zéro, passez sa position moins un ; 239..255 sont hors des 240 lignes visibles.
Valeur renvoyée
Aucune (void).
Conditions et limites
Ces opérations modifient la RAM CPU 0x0200–0x02FF, sans mettre immédiatement à jour l’OAM matérielle. Transférez la page complète avec __oam_dma. Elles ne tiennent à jour ni les indicateurs d’allocation, ni les tableaux de coordonnées, ni le compteur de la bibliothèque de sprites. Évitez qu’une interruption modifie ou transfère une page encore en préparation.
Exemple d’utilisation
nes_sprite_move(1,144,31); // Move to (144,32), retaining tile 128 and attributes 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 réserve une ligne légendée à chaque opération. SET et MOVE montrent des flèches de 8×8 vers la droite en (144,16) et (144,32) ; TILE, un carré vert en (144,48) ; ATTR, la flèche retournée selon les deux axes en (144,64). HIDE en (144,80) et CLEAR en (144,112) doivent rester vides. META montre une paire en (136,96) et (144,96), la seconde flèche étant retournée horizontalement. NEXT 07 indique l’indice suivant après les entrées 5 et 6. Les bords sont rouges, la tige verte et les détails de la pointe bleus. La vérification compare 8 704 pixels par image et les octets OAM transférés ; le matériel physique n’a pas été testé.
Le programme ALIASES prépare les lignes avec les macros de nes_game.h et envoie la page 02 avec nes_oam_dma(). TRANSFER affiche la flèche 8×8 à (144,128). Cet exemple utilise les macros sans lier runtime.c ni metasprite.c.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\oam_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --nes-chr=.\kitaq-docs\samples\sprite_example.chr -o .\out\oam_aliases.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/nes_game.h:25
#define nes_sprite_move(i,x,y) __sprite_move((i),(x),(y))nes_sprite_set
Macro de nes_game.h : elle se développe en l’intrinsèque indiqué dans la syntaxe. Il suffit d’inclure cet en-tête ; aucun fichier d’implémentation C n’est nécessaire pour cette opération.
Écrit les quatre champs d’un sprite dans le tampon miroir de la page 02. Les arguments sont l’indice, X, Y, la tuile et les attributs ; l’ordre en mémoire est Y, tuile, attributs, X.
Syntaxe
#define nes_sprite_set(i,x,y,t,a) __sprite_set((i),(x),(y),(t),(a))Paramètres
iIndice du sprite, de 0 à 63, et non décalage en octets. Le calcul multiplie cet indice par quatre dans un curseur de 8 bits ; les valeurs hors plage sont ramenées modulo 64 et peuvent écraser une autre entrée. L’allocation n’est pas vérifiée.
xPosition horizontale en pixels, sous forme d’octet non signé ; ce n’est pas une coordonnée de tuile.
yOctet Y de l’OAM. Pour placer le haut sous la ligne zéro, passez sa position moins un ; 239..255 sont hors des 240 lignes visibles.
tNumé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é.
aOctet d’attributs complet : les bits 0–1 choisissent la palette 0–3 ; le bit 5 place les pixels opaques du sprite derrière ceux du fond ; les bits 6 et 7 retournent le dessin horizontalement et verticalement. Laissez les bits 2–4 à zéro. Combinez les indicateurs par OU bit à bit ; l’octet remplace tous les attributs précédents.
Valeur renvoyée
Aucune (void).
Conditions et limites
Ces opérations modifient la RAM CPU 0x0200–0x02FF, sans mettre immédiatement à jour l’OAM matérielle. Transférez la page complète avec __oam_dma. Elles ne tiennent à jour ni les indicateurs d’allocation, ni les tableaux de coordonnées, ni le compteur de la bibliothèque de sprites. Évitez qu’une interruption modifie ou transfère une page encore en préparation.
Exemple d’utilisation
nes_sprite_set(0,144,15,128,0); // An 8x8 arrow at visible position (144,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
L’exemple réserve une ligne légendée à chaque opération. SET et MOVE montrent des flèches de 8×8 vers la droite en (144,16) et (144,32) ; TILE, un carré vert en (144,48) ; ATTR, la flèche retournée selon les deux axes en (144,64). HIDE en (144,80) et CLEAR en (144,112) doivent rester vides. META montre une paire en (136,96) et (144,96), la seconde flèche étant retournée horizontalement. NEXT 07 indique l’indice suivant après les entrées 5 et 6. Les bords sont rouges, la tige verte et les détails de la pointe bleus. La vérification compare 8 704 pixels par image et les octets OAM transférés ; le matériel physique n’a pas été testé.
Le programme ALIASES prépare les lignes avec les macros de nes_game.h et envoie la page 02 avec nes_oam_dma(). TRANSFER affiche la flèche 8×8 à (144,128). Cet exemple utilise les macros sans lier runtime.c ni metasprite.c.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\oam_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --nes-chr=.\kitaq-docs\samples\sprite_example.chr -o .\out\oam_aliases.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/nes_game.h:24
#define nes_sprite_set(i,x,y,t,a) __sprite_set((i),(x),(y),(t),(a))nes_vram_clear_queue
Macro de nes_game.h : elle se développe en l’intrinsèque indiqué dans la syntaxe. Il suffit d’inclure cet en-tête ; aucun fichier d’implémentation C n’est nécessaire pour cette opération.
Abandonne tous les enregistrements en attente et remet longueur et drapeau prêt à zéro. N’écrit pas en VRAM et n’efface pas le débordement. Appelez séparément __vramq_clear_overflow pour effacer cet indicateur.
Syntaxe
#define nes_vram_clear_queue() __vramq_clear()Valeur renvoyée
Aucune (void).
Conditions et limites
FC compte les octets d’ordres encodés dans un tampon intrinsèque fixe de 128 octets. Une écriture de tuile coûte 4 octets, un remplissage 5 et une copie par pointeur 6, métadonnées comprises. NMI peut consommer une file prête ; inspectez-la et construisez-la avant validation, en coordonnant production et consommation.
Ces macros utilisent la file de commandes intrinsèque du compilateur, également employée par lib/vram.c. Elles ne sélectionnent pas le tampon C nes_vram_queue_*. Consultez les octets encodés en attente avec __vramq_len() et les dépassements de capacité avec __vramq_overflow() ; acquittez le drapeau d’échec avec __vramq_clear_overflow().
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
nes_vram_clear_queue();
if (__vramq_len()!=0 || __vramq_overflow()!=1) failures++;
// Clearing queued work deliberately leaves the overflow latch set.Cet extrait montre l’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 utilise les macros de nes_game.h pour ajouter un octet, copier, remplir, valider et vider la file. Il emploie aussi les intrinsèques de consultation et d’exécution __vramq_* pour vérifier leurs effets. Le titre est VRAM QUEUE MACROS. Les gros transferts s’exécutent avec le rendu désactivé ; les valider ne garantit pas qu’ils tiennent dans VBlank.
Le programme présente capacité, pointeurs conservés, remises à zéro indépendantes et exécution directe ou par NMI. On attend CAPACITY 128, ENCODED BYTES 030, AFTER EXEC 000, OVERFLOW SEEN 001 et FAILED CHECKS 000. Six enregistrements occupent 30 octets et effectuent 512 écritures d’un octet. OVERFLOW SEEN mémorise le rejet volontaire précédent ; il ne décrit pas un indicateur final encore actif.
La copie bleue commence au pixel (0,16), le remplissage vert en (0,88). Chacun couvre sept lignes complètes de 256 pixels, puis 248 pixels de la huitième : 255 tuiles au total. La dernière case de 8 × 8 reste noire. La copie répète des motifs pleins, à moitié gauche et triangulaires ; le premier est triangulaire car la source change après l’ajout. Le remplissage reste plein malgré le changement de variable chez l’appelant. Forme et couleur sont vérifiées.
À y=160, on attend un carré rouge plein à x=16, une demi-tuile gauche rouge à x=224 et un carré rouge plein à x=240. Le premier subsiste après les enregistrements de longueur nulle ; le milieu prouve le traitement par NMI ; le dernier, un put. La case annulée en (248,160) reste noire. Les longs transferts s’effectuent avec rendu et NMI désactivés ; seule la petite écriture finale utilise NMI. Il s’agit d’un test sur émulateur NROM, pas sur matériel réel.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\vram_queue_macros.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_macros.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/nes_game.h:19
#define nes_vram_clear_queue() __vramq_clear()nes_vram_commit
Macro de nes_game.h : elle se développe en l’intrinsèque indiqué dans la syntaxe. Il suffit d’inclure cet en-tête ; aucun fichier d’implémentation C n’est nécessaire pour cette opération.
Active le drapeau prêt afin que l’exécuteur puisse consommer la file. Ne copie pas les données, n’écrit pas dans la PPU et n’attend pas NMI. Après validation, gardez la file et les sources conservées stables jusqu’à la fin. Si NMI est active, le gestionnaire par défaut peut traiter la file de façon asynchrone.
Syntaxe
#define nes_vram_commit() __vramq_commit()Valeur renvoyée
Aucune (void).
Conditions et limites
FC compte les octets d’ordres encodés dans un tampon intrinsèque fixe de 128 octets. Une écriture de tuile coûte 4 octets, un remplissage 5 et une copie par pointeur 6, métadonnées comprises. NMI peut consommer une file prête ; inspectez-la et construisez-la avant validation, en coordonnant production et consommation.
Ces macros utilisent la file de commandes intrinsèque du compilateur, également employée par lib/vram.c. Elles ne sélectionnent pas le tampon C nes_vram_queue_*. Consultez les octets encodés en attente avec __vramq_len() et les dépassements de capacité avec __vramq_overflow() ; acquittez le drapeau d’échec avec __vramq_clear_overflow().
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
nes_vram_commit(); // NMI is disabled here: this only marks the queue ready.
if (__vramq_len()!=30) 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 utilise les macros de nes_game.h pour ajouter un octet, copier, remplir, valider et vider la file. Il emploie aussi les intrinsèques de consultation et d’exécution __vramq_* pour vérifier leurs effets. Le titre est VRAM QUEUE MACROS. Les gros transferts s’exécutent avec le rendu désactivé ; les valider ne garantit pas qu’ils tiennent dans VBlank.
Le programme présente capacité, pointeurs conservés, remises à zéro indépendantes et exécution directe ou par NMI. On attend CAPACITY 128, ENCODED BYTES 030, AFTER EXEC 000, OVERFLOW SEEN 001 et FAILED CHECKS 000. Six enregistrements occupent 30 octets et effectuent 512 écritures d’un octet. OVERFLOW SEEN mémorise le rejet volontaire précédent ; il ne décrit pas un indicateur final encore actif.
La copie bleue commence au pixel (0,16), le remplissage vert en (0,88). Chacun couvre sept lignes complètes de 256 pixels, puis 248 pixels de la huitième : 255 tuiles au total. La dernière case de 8 × 8 reste noire. La copie répète des motifs pleins, à moitié gauche et triangulaires ; le premier est triangulaire car la source change après l’ajout. Le remplissage reste plein malgré le changement de variable chez l’appelant. Forme et couleur sont vérifiées.
À y=160, on attend un carré rouge plein à x=16, une demi-tuile gauche rouge à x=224 et un carré rouge plein à x=240. Le premier subsiste après les enregistrements de longueur nulle ; le milieu prouve le traitement par NMI ; le dernier, un put. La case annulée en (248,160) reste noire. Les longs transferts s’effectuent avec rendu et NMI désactivés ; seule la petite écriture finale utilise NMI. Il s’agit d’un test sur émulateur NROM, pas sur matériel réel.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\vram_queue_macros.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_macros.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/nes_game.h:18
#define nes_vram_commit() __vramq_commit()nes_vram_copy
Macro de nes_game.h : elle se développe en l’intrinsèque indiqué dans la syntaxe. Il suffit d’inclure cet en-tête ; aucun fichier d’implémentation C n’est nécessaire pour cette opération.
Ajoute un enregistrement de six octets pour copier len octets de src vers ppu_addr à l’exécution. Conserve le pointeur, pas les données. Même une copie de 255 octets n’occupe que six octets de file. Lit la source par adresses croissantes ; choisissez l’incrément PPU 1 pour une destination contiguë.
Syntaxe
#define nes_vram_copy(addr, src, len) __vramq_copy((addr), (src), (len))Paramètres
addrAdresse PPU en octets (
0x0000–0x3FFF), et non pointeur CPU. La destination doit être inscriptible : modifier les motifs exige de la CHR RAM, pas de la CHR ROM. Le mappage et le mirroring PPU s’appliquent. Pour les copies et remplissages contigus, choisissez l’incrément 1 dans PPUCTRL. Exécutez à un instant sûr, puis rétablissez le défilement voulu ; l’exécuteur écrit PPUADDR et PPUDATA sans restaurer le défilement.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, de 0 à 255. Un seul enregistrement traite tout le compte, sans découpage en morceaux de 127 octets. Zéro occupe encore un enregistrement de copie ou de remplissage. À l’exécution, l’adresse PPU est réglée mais aucun octet n’est écrit dans PPUDATA. 256 est hors plage.
Valeur renvoyée
Aucune (void).
Conditions et limites
L’ajout ne renvoie pas de valeur de réussite. Si l’enregistrement entier ne tient pas, active __vramq_overflow() sans modifier les enregistrements ni la longueur. Une place exactement suffisante est acceptée. Un ancien indicateur n’empêche pas un ajout qui tient ; traitez-le ou effacez-le avant d’évaluer un nouveau lot. Plusieurs ajouts ne forment pas une transaction.
FC compte les octets d’ordres encodés dans un tampon intrinsèque fixe de 128 octets. Une écriture de tuile coûte 4 octets, un remplissage 5 et une copie par pointeur 6, métadonnées comprises. NMI peut consommer une file prête ; inspectez-la et construisez-la avant validation, en coordonnant production et consommation.
Ces macros utilisent la file de commandes intrinsèque du compilateur, également employée par lib/vram.c. Elles ne sélectionnent pas le tampon C nes_vram_queue_*. Consultez les octets encodés en attente avec __vramq_len() et les dépassements de capacité avec __vramq_overflow() ; acquittez le drapeau d’échec avec __vramq_clear_overflow().
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
nes_vram_copy(0x2040,source_bytes,255);
source_bytes[0]=3; // The executor must see this change through its retained pointer.Cet extrait montre l’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 utilise les macros de nes_game.h pour ajouter un octet, copier, remplir, valider et vider la file. Il emploie aussi les intrinsèques de consultation et d’exécution __vramq_* pour vérifier leurs effets. Le titre est VRAM QUEUE MACROS. Les gros transferts s’exécutent avec le rendu désactivé ; les valider ne garantit pas qu’ils tiennent dans VBlank.
Le programme présente capacité, pointeurs conservés, remises à zéro indépendantes et exécution directe ou par NMI. On attend CAPACITY 128, ENCODED BYTES 030, AFTER EXEC 000, OVERFLOW SEEN 001 et FAILED CHECKS 000. Six enregistrements occupent 30 octets et effectuent 512 écritures d’un octet. OVERFLOW SEEN mémorise le rejet volontaire précédent ; il ne décrit pas un indicateur final encore actif.
La copie bleue commence au pixel (0,16), le remplissage vert en (0,88). Chacun couvre sept lignes complètes de 256 pixels, puis 248 pixels de la huitième : 255 tuiles au total. La dernière case de 8 × 8 reste noire. La copie répète des motifs pleins, à moitié gauche et triangulaires ; le premier est triangulaire car la source change après l’ajout. Le remplissage reste plein malgré le changement de variable chez l’appelant. Forme et couleur sont vérifiées.
À y=160, on attend un carré rouge plein à x=16, une demi-tuile gauche rouge à x=224 et un carré rouge plein à x=240. Le premier subsiste après les enregistrements de longueur nulle ; le milieu prouve le traitement par NMI ; le dernier, un put. La case annulée en (248,160) reste noire. Les longs transferts s’effectuent avec rendu et NMI désactivés ; seule la petite écriture finale utilise NMI. Il s’agit d’un test sur émulateur NROM, pas sur matériel réel.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\vram_queue_macros.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_macros.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/nes_game.h:16
#define nes_vram_copy(addr, src, len) __vramq_copy((addr), (src), (len))nes_vram_fill
Macro de nes_game.h : elle se développe en l’intrinsèque indiqué dans la syntaxe. Il suffit d’inclure cet en-tête ; aucun fichier d’implémentation C n’est nécessaire pour cette opération.
Ajoute un enregistrement de cinq octets répétant l’octet value pendant len écritures PPU. La valeur est stockée : modifier ensuite la variable de l’appelant ne change pas le remplissage en attente. Répète un octet, pas un motif graphique de plusieurs octets.
Syntaxe
#define nes_vram_fill(addr, value, len) __vramq_fill((addr), (value), (len))Paramètres
addrAdresse PPU en octets (
0x0000–0x3FFF), et non pointeur CPU. La destination doit être inscriptible : modifier les motifs exige de la CHR RAM, pas de la CHR ROM. Le mappage et le mirroring PPU s’appliquent. Pour les copies et remplissages contigus, choisissez l’incrément 1 dans PPUCTRL. Exécutez à un instant sûr, puis rétablissez le défilement voulu ; l’exécuteur écrit PPUADDR et PPUDATA sans restaurer le défilement.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, de 0 à 255. Un seul enregistrement traite tout le compte, sans découpage en morceaux de 127 octets. Zéro occupe encore un enregistrement de copie ou de remplissage. À l’exécution, l’adresse PPU est réglée mais aucun octet n’est écrit dans PPUDATA. 256 est hors plage.
Valeur renvoyée
Aucune (void).
Conditions et limites
L’ajout ne renvoie pas de valeur de réussite. Si l’enregistrement entier ne tient pas, active __vramq_overflow() sans modifier les enregistrements ni la longueur. Une place exactement suffisante est acceptée. Un ancien indicateur n’empêche pas un ajout qui tient ; traitez-le ou effacez-le avant d’évaluer un nouveau lot. Plusieurs ajouts ne forment pas une transaction.
FC compte les octets d’ordres encodés dans un tampon intrinsèque fixe de 128 octets. Une écriture de tuile coûte 4 octets, un remplissage 5 et une copie par pointeur 6, métadonnées comprises. NMI peut consommer une file prête ; inspectez-la et construisez-la avant validation, en coordonnant production et consommation.
Ces macros utilisent la file de commandes intrinsèque du compilateur, également employée par lib/vram.c. Elles ne sélectionnent pas le tampon C nes_vram_queue_*. Consultez les octets encodés en attente avec __vramq_len() et les dépassements de capacité avec __vramq_overflow() ; acquittez le drapeau d’échec avec __vramq_clear_overflow().
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
nes_vram_fill(0x2160,fill_value,255); // Seven complete rows and 31 tiles in the eighth.
fill_value=3; // The queued value stays 1, so the green block remains solid.Cet extrait montre l’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 utilise les macros de nes_game.h pour ajouter un octet, copier, remplir, valider et vider la file. Il emploie aussi les intrinsèques de consultation et d’exécution __vramq_* pour vérifier leurs effets. Le titre est VRAM QUEUE MACROS. Les gros transferts s’exécutent avec le rendu désactivé ; les valider ne garantit pas qu’ils tiennent dans VBlank.
Le programme présente capacité, pointeurs conservés, remises à zéro indépendantes et exécution directe ou par NMI. On attend CAPACITY 128, ENCODED BYTES 030, AFTER EXEC 000, OVERFLOW SEEN 001 et FAILED CHECKS 000. Six enregistrements occupent 30 octets et effectuent 512 écritures d’un octet. OVERFLOW SEEN mémorise le rejet volontaire précédent ; il ne décrit pas un indicateur final encore actif.
La copie bleue commence au pixel (0,16), le remplissage vert en (0,88). Chacun couvre sept lignes complètes de 256 pixels, puis 248 pixels de la huitième : 255 tuiles au total. La dernière case de 8 × 8 reste noire. La copie répète des motifs pleins, à moitié gauche et triangulaires ; le premier est triangulaire car la source change après l’ajout. Le remplissage reste plein malgré le changement de variable chez l’appelant. Forme et couleur sont vérifiées.
À y=160, on attend un carré rouge plein à x=16, une demi-tuile gauche rouge à x=224 et un carré rouge plein à x=240. Le premier subsiste après les enregistrements de longueur nulle ; le milieu prouve le traitement par NMI ; le dernier, un put. La case annulée en (248,160) reste noire. Les longs transferts s’effectuent avec rendu et NMI désactivés ; seule la petite écriture finale utilise NMI. Il s’agit d’un test sur émulateur NROM, pas sur matériel réel.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\vram_queue_macros.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_macros.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/nes_game.h:17
#define nes_vram_fill(addr, value, len) __vramq_fill((addr), (value), (len))nes_vram_put
Macro de nes_game.h : elle se développe en l’intrinsèque indiqué dans la syntaxe. Il suffit d’inclure cet en-tête ; aucun fichier d’implémentation C n’est nécessaire pour cette opération.
Ajoute une adresse PPU et une valeur d’un octet dans un enregistrement de quatre octets. La valeur est copiée dans la file maintenant et écrite à l’exécution. Permet notamment de modifier une tuile de table de noms, ou un autre octet PPU inscriptible.
Syntaxe
#define nes_vram_put(addr, value) __vramq_put((addr), (value))Paramètres
addrAdresse PPU en octets (
0x0000–0x3FFF), et non pointeur CPU. La destination doit être inscriptible : modifier les motifs exige de la CHR RAM, pas de la CHR ROM. Le mappage et le mirroring PPU s’appliquent. Pour les copies et remplissages contigus, choisissez l’incrément 1 dans PPUCTRL. Exécutez à un instant sûr, puis rétablissez le défilement voulu ; l’exécuteur écrit PPUADDR et PPUDATA sans restaurer le défilement.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.
Valeur renvoyée
Aucune (void).
Conditions et limites
L’ajout ne renvoie pas de valeur de réussite. Si l’enregistrement entier ne tient pas, active __vramq_overflow() sans modifier les enregistrements ni la longueur. Une place exactement suffisante est acceptée. Un ancien indicateur n’empêche pas un ajout qui tient ; traitez-le ou effacez-le avant d’évaluer un nouveau lot. Plusieurs ajouts ne forment pas une transaction.
FC compte les octets d’ordres encodés dans un tampon intrinsèque fixe de 128 octets. Une écriture de tuile coûte 4 octets, un remplissage 5 et une copie par pointeur 6, métadonnées comprises. NMI peut consommer une file prête ; inspectez-la et construisez-la avant validation, en coordonnant production et consommation.
Ces macros utilisent la file de commandes intrinsèque du compilateur, également employée par lib/vram.c. Elles ne sélectionnent pas le tampon C nes_vram_queue_*. Consultez les octets encodés en attente avec __vramq_len() et les dépassements de capacité avec __vramq_overflow() ; acquittez le drapeau d’échec avec __vramq_clear_overflow().
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
nes_vram_put(0x2282,1); // Red 8x8 sentinel at pixel (16,160).Cet extrait montre l’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 utilise les macros de nes_game.h pour ajouter un octet, copier, remplir, valider et vider la file. Il emploie aussi les intrinsèques de consultation et d’exécution __vramq_* pour vérifier leurs effets. Le titre est VRAM QUEUE MACROS. Les gros transferts s’exécutent avec le rendu désactivé ; les valider ne garantit pas qu’ils tiennent dans VBlank.
Le programme présente capacité, pointeurs conservés, remises à zéro indépendantes et exécution directe ou par NMI. On attend CAPACITY 128, ENCODED BYTES 030, AFTER EXEC 000, OVERFLOW SEEN 001 et FAILED CHECKS 000. Six enregistrements occupent 30 octets et effectuent 512 écritures d’un octet. OVERFLOW SEEN mémorise le rejet volontaire précédent ; il ne décrit pas un indicateur final encore actif.
La copie bleue commence au pixel (0,16), le remplissage vert en (0,88). Chacun couvre sept lignes complètes de 256 pixels, puis 248 pixels de la huitième : 255 tuiles au total. La dernière case de 8 × 8 reste noire. La copie répète des motifs pleins, à moitié gauche et triangulaires ; le premier est triangulaire car la source change après l’ajout. Le remplissage reste plein malgré le changement de variable chez l’appelant. Forme et couleur sont vérifiées.
À y=160, on attend un carré rouge plein à x=16, une demi-tuile gauche rouge à x=224 et un carré rouge plein à x=240. Le premier subsiste après les enregistrements de longueur nulle ; le milieu prouve le traitement par NMI ; le dernier, un put. La case annulée en (248,160) reste noire. Les longs transferts s’effectuent avec rendu et NMI désactivés ; seule la petite écriture finale utilise NMI. Il s’agit d’un test sur émulateur NROM, pas sur matériel réel.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\vram_queue_macros.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_macros.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/nes_game.h:15
#define nes_vram_put(addr, value) __vramq_put((addr), (value))oam_fair.h — Rotation des sprites avec priorités
Ajoute les entrées actives d’un ensemble logiciel de 64 éléments au tampon OAM. Avant chaque parcours, avance le point de départ de 13 modulo 64. Les appels successifs font tourner la priorité OAM pour répartir le clignotement ; ils n’augmentent pas la limite matérielle de sprites.
Définissez les tableaux X, Y, active et shadow ainsi que le curseur used ; incluez oam_fair_impl.h une seule fois dans une banque PRG fixe. Appelez depuis la boucle principale en mode sprites 8×8. Les coordonnées rebouclent modulo 256, sans découpage. La routine ne transfère pas l’OAM : utilisez le DMA depuis la page du tampon shadow. Le matériel reste limité à 64 sprites OAM et huit par ligne de balayage.
OAM_FairDraw
Ajoute les entrées actives d’un ensemble logiciel de 64 éléments au tampon OAM. Avant chaque parcours, avance le point de départ de 13 modulo 64. Les appels successifs font tourner la priorité OAM pour répartir le clignotement ; ils n’augmentent pas la limite matérielle de sprites.
Syntaxe
void OAM_FairDraw(void);Valeur renvoyée
Aucune valeur de retour C. oam_fair_drawn contient le nombre ajouté, oam_fair_used le curseur d’octets mis à jour et oam_fair_phase l’indice de départ du parcours. La phase avance même si aucune entrée n’est dessinée ; oam_fair_drawn vaut alors zéro.
Conditions et limites
La fonction n’a pas d’arguments ; configurez les variables partagées. oam_fair_x[64] et oam_fair_y[64] contiennent les centres des sprites 8×8 en pixels : X brut dans l’OAM vaut centre X−4, Y brut vaut centre Y−5. Les entrées non nulles de oam_fair_active[64] sont sélectionnées. Toutes utilisent la tuile et les attributs communs de oam_fair_tile et oam_fair_attr.
Réglez oam_fair_used sur le prochain décalage libre en octets dans oam_fair_shadow[256], aligné sur quatre octets. oam_fair_limit borne le nombre d’entrées ajoutées par cet appel. Le parcours examine au plus 64 éléments et cesse d’écrire au décalage 252, laissant l’entrée 63 inutilisée. Les entrées précédentes sont conservées ; masquez séparément les entrées finales inutilisées.
Définissez les tableaux X, Y, active et shadow ainsi que le curseur used ; incluez oam_fair_impl.h une seule fois dans une banque PRG fixe. Appelez depuis la boucle principale en mode sprites 8×8. Les coordonnées rebouclent modulo 256, sans découpage. La routine ne transfère pas l’OAM : utilisez le DMA depuis la page du tampon shadow. Le matériel reste limité à 64 sprites OAM et huit par ligne de balayage.
Exemple d’utilisation
oam_fair_used=4; // Byte cursor: reserve the already prepared slot 0.
OAM_FairDraw(); // Phase becomes 13; append pool entries 13, 14 and 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
FAIR-POOL conserve un carré vert 8×8 à (144,32) dans l’entrée 0 et ajoute trois flèches centrées à (148,68), (164,68) et (180,68). Leurs coins supérieurs gauches doivent être à (144,64), (160,64) et (176,64). Avec phase=0 et used=4, il affiche PHASE 13, DRAWN 03 et BYTES 16. L’image fixe vérifie le placement et la conservation ; un test d’état séparé de 64 appels vérifie que chaque élément devient le point de départ exactement une fois.
Les flèches ont des bords rouges, une tige verte et des détails bleus à la pointe ; la tuile carrée 129 est verte. La vérification compare 8 704 pixels colorés et les 256 octets OAM transférés par image, ainsi que les libellés. Le matériel physique n’a pas été testé.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\oam_fair.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --nes-chr=.\kitaq-docs\samples\sprite_example.chr -o .\out\oam_fair.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/oam_fair.h:24
Append active pool entries using the configured common tile/attributes. The emitter stops at byte cursor 252, leaving slot 63 unused to avoid cursor wrap. Hide unused trailing OAM entries separately before DMA.
kitaqfc/lib/oam_fair_impl.h:12
void OAM_FairDraw(void) {
__asm {
LDA oam_fair_phase
CLC
ADC #13
AND #63
STA oam_fair_phase
TAX
LDY oam_fair_used
LDA #0
STA oam_fair_drawn
STA oam_fair_scanned
// Visit each pool entry at most once, preserving already-written OAM entries
// and sharing the configured tile/attribute values across emitted sprites.
kq_fair_loop:
LDA oam_fair_active,X
BEQ kq_fair_next
LDA oam_fair_drawn
CMP oam_fair_limit
BCS kq_fair_done
// Reserve the final four-byte slot so advancing this byte cursor cannot wrap to zero.
CPY #252
BCS kq_fair_done
// Convert the 8x8 center to raw OAM coordinates; Y also needs the hardware minus-one bias.
LDA oam_fair_y,X
SEC
SBC #5
STA oam_fair_shadow,Y
LDA oam_fair_tile
STA oam_fair_shadow+1,Y
LDA oam_fair_attr
STA oam_fair_shadow+2,Y
LDA oam_fair_x,X
SEC
SBC #4
STA oam_fair_shadow+3,Y
INY
INY
INY
INY
INC oam_fair_drawn
// Advance cyclically and stop after returning to this frame's starting entry.
kq_fair_next:
TXA
CLC
ADC #1
AND #63
TAX
CPX oam_fair_phase
BNE kq_fair_loop
// Publish the updated byte cursor for later OAM writers and the VBlank DMA path.
kq_fair_done:
STY oam_fair_used
}
}pad.h — Entrées des manettes NES
pad.h et pad.c mémorisent le contrôleur 1 dans l’ordre NES. La lecture calcule les masques précédent, maintenu, d’appui et de relâchement, sans programmer de répétition. Liez aussi input_repeat.c pour une répétition configurable par bouton. Pour le contrôleur 2, utilisez une fonction intrinsèque du port 2 et conservez l’état précédent dans le jeu.
Format NES brut : A=0x01, B=0x02, SELECT=0x04, START=0x08, UP=0x10, DOWN=0x20, LEFT=0x40, RIGHT=0x80. Un bit à 1 indique un appui. Utilisez ces valeurs avec nes_pad_* et les résultats bruts de __pad_*, et non les masques communs BTN_* de input.h.
Initialisez les quatre octets d’état nes_pad1_* à 0 avant la première lecture. Ensuite, lisez une fois par cycle. pressed = current & ~previous et released = previous & ~current décrivent la dernière lecture. La répétition se met à jour séparément avec nes_pad_repeat_step().
nes_pad_poll
Active le strobe de $4016, lit les huit bits série D0 du contrôleur 1 et met à jour nes_pad1_prev, nes_pad1_cur, nes_pad1_pressed et nes_pad1_released. Il n’y a qu’une lecture, sans les essais de concordance des fonctions sûres. La lecture finale de $4017 ne mémorise pas l’état du contrôleur 2.
Syntaxe
void nes_pad_poll(void);Valeur renvoyée
Aucune (void).
Conditions et limites
Format NES brut : A=0x01, B=0x02, SELECT=0x04, START=0x08, UP=0x10, DOWN=0x20, LEFT=0x40, RIGHT=0x80. Un bit à 1 indique un appui. Utilisez ces valeurs avec nes_pad_* et les résultats bruts de __pad_*, et non les masques communs BTN_* de input.h.
Initialisez les quatre octets d’état nes_pad1_* à 0 avant la première lecture. Ensuite, lisez une fois par cycle. pressed = current & ~previous et released = previous & ~current décrivent la dernière lecture. La répétition se met à jour séparément avec nes_pad_repeat_step().
Exemple d’utilisation
nes_pad_poll(); // Read controller 1 and update its held/pressed/released snapshots.Cet extrait montre l’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 enseigne l’ordre lecture → mise à jour de la répétition → consultation et montre que les fonctions NES renvoient les bits sélectionnés, et non la valeur booléenne 1. Avec nes_pad_repeat_config(3, 1), maintenez B pendant 40 mises à jour, puis relâchez-le. FIRST HELD, FIRST TRIGGER et FIRST REPEAT valent 2 ; HELD TICKS vaut 40, PULSE COUNT vaut 19 et RELEASE BITS vaut 2. La première répétition survient quatre mises à jour après l’appui initial ; les suivantes sont espacées de deux mises à jour. FAILED CHECKS doit valoir 0. Une autre durée modifie le nombre d’impulsions.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\pad.c .\kitaqfc\lib\input_repeat.c .\kitaq-docs\samples\api-examples\fc\pad_repeat.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\pad_repeat.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chr --no-disasm --no-cacheImplémentation et source
kitaqfc/lib/pad.h:16
Latch controller input with a 1-to-0 strobe and shift eight controller-1 bits into held/pressed/released masks. This direct path does not perform repeated reads for DMC interference; the final JOY2 read does not populate player-2 state.
kitaqfc/lib/pad.c:21
void nes_pad_poll(void)
{
unsigned char state;
unsigned char mask;
unsigned char sample;
nes_pad1_prev = nes_pad1_cur;
JOY1 = 1;
JOY1 = 0;
state = 0;
mask = 1;
while (mask != 0)
{
sample = JOY1;
if ((sample & 1) != 0)
{
state = state | mask;
}
mask = mask + mask;
}
nes_pad1_cur = state;
nes_pad1_pressed = (unsigned char)(state & (unsigned char)(state ^ nes_pad1_prev));
nes_pad1_released = (unsigned char)(nes_pad1_prev & (unsigned char)(state ^ nes_pad1_prev));
sample = JOY2;
sample = sample;
}palette.h — Palettes NES
Gère les couleurs du fond et des sprites avec un miroir CPU de 32 octets et des transferts immédiats ou par file. Les adresses de palette PPU comportent des alias.
nes_palette_apply_now
Copie 32 couleurs dans le miroir, puis les transfère directement au PPU.
Syntaxe
void nes_palette_apply_now(unsigned char* src32);Paramètres
src32Palette lisible de 32 octets : 16 couleurs de fond suivies de 16 couleurs de sprites ; utilisez des codes couleur de 0 à 63.
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 copie miroir réserve les adresses CPU 0x03C0–0x03DF. Les adresses PPU 0x3F10/14/18/1C sont des alias de 0x3F00/04/08/0C : les 32 octets bruts du miroir ne correspondent donc pas nécessairement à 32 valeurs PPU indépendantes relues. Utilisez un incrément PPU de un pendant un créneau VBlank sûr ou avec le rendu désactivé. Cette fonction auxiliaire n’attend pas, ne masque pas les interruptions et ne restaure pas le défilement.
Exemple d’utilisation
nes_palette_apply_now(colors);Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Affichez des rectangles de fond de 32×32 rouges, bleus et verts en (16,32), (80,32) et (144,32), ainsi que des carrés de sprites de 8×8 en (16,96), (80,96) et (144,96), dans le même ordre de couleurs. Les palettes séparées du fond et des sprites illustrent les transferts directs et par file.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch2_palette.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_palette.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/palette.h:11
Replace shadow palette data and upload all 32 bytes immediately. The caller provides a safe PPU access period; this helper does not wait for VBlank.
kitaqfc/lib/palette.c:28
void nes_palette_apply_now(unsigned char* src32)
{
nes_palette_copy(src32);
nes_ppu_stream_write(0x3F00, nes_palette_shadow, 32);
}nes_palette_apply_shadow_now
Transfère directement au PPU les 32 couleurs courantes du miroir.
Syntaxe
void nes_palette_apply_shadow_now(void);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 copie miroir réserve les adresses CPU 0x03C0–0x03DF. Les adresses PPU 0x3F10/14/18/1C sont des alias de 0x3F00/04/08/0C : les 32 octets bruts du miroir ne correspondent donc pas nécessairement à 32 valeurs PPU indépendantes relues. Utilisez un incrément PPU de un pendant un créneau VBlank sûr ou avec le rendu désactivé. Cette fonction auxiliaire n’attend pas, ne masque pas les interruptions et ne restaure pas le défilement.
Exemple d’utilisation
nes_palette_apply_shadow_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
Affichez des rectangles de fond de 32×32 rouges, bleus et verts en (16,32), (80,32) et (144,32), ainsi que des carrés de sprites de 8×8 en (16,96), (80,96) et (144,96), dans le même ordre de couleurs. Les palettes séparées du fond et des sprites illustrent les transferts directs et par file.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch2_palette.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_palette.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/palette.h:13
Upload the current palette shadow directly, with timing controlled by the caller.
kitaqfc/lib/palette.c:35
void nes_palette_apply_shadow_now(void)
{
nes_ppu_stream_write(0x3F00, nes_palette_shadow, 32);
}nes_palette_copy
Copie 32 octets de palette dans la copie miroir côté CPU sans les transférer au PPU.
Syntaxe
void nes_palette_copy(unsigned char* src32);Paramètres
src32Palette lisible de 32 octets : 16 couleurs de fond suivies de 16 couleurs de sprites ; utilisez des codes couleur de 0 à 63.
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 copie miroir réserve les adresses CPU 0x03C0–0x03DF. Les adresses PPU 0x3F10/14/18/1C sont des alias de 0x3F00/04/08/0C : les 32 octets bruts du miroir ne correspondent donc pas nécessairement à 32 valeurs PPU indépendantes relues.
Exemple d’utilisation
nes_palette_copy(colors);result[0]=nes_palette_shadow[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
Affichez des rectangles de fond de 32×32 rouges, bleus et verts en (16,32), (80,32) et (144,32), ainsi que des carrés de sprites de 8×8 en (16,96), (80,96) et (144,96), dans le même ordre de couleurs. Les palettes séparées du fond et des sprites illustrent les transferts directs et par file.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch2_palette.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_palette.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/palette.h:8
Copy exactly 32 palette bytes to the fixed shadow buffer without writing the PPU.
kitaqfc/lib/palette.c:19
void nes_palette_copy(unsigned char* src32)
{
__memcpy(nes_palette_shadow, src32, 32);
}nes_palette_queue_all
Remplace les 32 couleurs du miroir et les copie dans la file VRAM du runtime.
Syntaxe
unsigned char nes_palette_queue_all(unsigned char* src32);Paramètres
src32Palette lisible de 32 octets : 16 couleurs de fond suivies de 16 couleurs de sprites ; utilisez des codes couleur de 0 à 63.
Valeur renvoyée
1 si la mise en file réussit, 0 si la capacité est insuffisante. Les nouvelles valeurs du miroir restent en place même en cas d’échec. La réussite ne signifie pas que le PPU a déjà été mis à jour.
Conditions et limites
La copie miroir réserve les adresses CPU 0x03C0–0x03DF. Les adresses PPU 0x3F10/14/18/1C sont des alias de 0x3F00/04/08/0C : les 32 octets bruts du miroir ne correspondent donc pas nécessairement à 32 valeurs PPU indépendantes relues. La file copie les valeurs ; la source peut donc être modifiée après une mise en file réussie. Évitez les accès concurrents non coordonnés entre la production dans la file et sa consommation par la NMI.
Exemple d’utilisation
nes_vram_queue_clear();result[1]=nes_palette_queue_all(colors);result[2]=nes_vram_queue_used;nes_vram_queue_nmi_flush();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Affichez des rectangles de fond de 32×32 rouges, bleus et verts en (16,32), (80,32) et (144,32), ainsi que des carrés de sprites de 8×8 en (16,96), (80,96) et (144,96), dans le même ordre de couleurs. Les palettes séparées du fond et des sprites illustrent les transferts directs et par file.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch2_palette.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_palette.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/palette.h:18
Update the shadow and copy all colors into the runtime queue. A queue failure leaves the new shadow contents in place. Return one if the runtime queue accepted the copied payload, zero if it was full. Admission does not mean the NMI consumer has already updated the PPU.
kitaqfc/lib/palette.c:42
unsigned char nes_palette_queue_all(unsigned char* src32)
{
nes_palette_copy(src32);
return nes_vram_queue_try_write(0x3F00, nes_palette_shadow, 32);
}nes_palette_queue_bg4
Met à jour les quatre couleurs d’une palette de fond dans le miroir et les copie dans la file VRAM.
Syntaxe
unsigned char nes_palette_queue_bg4(unsigned char pal_index, unsigned char* src4);Paramètres
pal_indexIndice de palette de 0 à 3 ; la fonction ne le valide pas.
src4Quatre octets de la palette choisie ; utilisez des codes couleur de 0 à 63.
Valeur renvoyée
1 si la mise en file réussit, 0 si la capacité est insuffisante. Les nouvelles valeurs du miroir restent en place même en cas d’échec. La réussite ne signifie pas que le PPU a déjà été mis à jour.
Conditions et limites
La copie miroir réserve les adresses CPU 0x03C0–0x03DF. Les adresses PPU 0x3F10/14/18/1C sont des alias de 0x3F00/04/08/0C : les 32 octets bruts du miroir ne correspondent donc pas nécessairement à 32 valeurs PPU indépendantes relues. La file copie les valeurs ; la source peut donc être modifiée après une mise en file réussie. Évitez les accès concurrents non coordonnés entre la production dans la file et sa consommation par la NMI.
Exemple d’utilisation
result[3]=nes_palette_queue_bg4(3,four);nes_vram_queue_nmi_flush();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Affichez des rectangles de fond de 32×32 rouges, bleus et verts en (16,32), (80,32) et (144,32), ainsi que des carrés de sprites de 8×8 en (16,96), (80,96) et (144,96), dans le même ordre de couleurs. Les palettes séparées du fond et des sprites illustrent les transferts directs et par file.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch2_palette.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_palette.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/palette.h:21
Update and queue four background palette bytes. pal_index must be 0..3; there is no range check before writing the shadow.
kitaqfc/lib/palette.c:50
unsigned char nes_palette_queue_bg4(unsigned char pal_index, unsigned char* src4)
{
unsigned char dst;
dst = pal_index + pal_index;
dst = dst + dst;
__memcpy(nes_palette_shadow + dst, src4, 4);
return nes_vram_queue_try_write((unsigned short)(0x3F00 + dst), nes_palette_shadow + dst, 4);
}nes_palette_queue_sprite4
Met à jour les quatre couleurs d’une palette de sprites dans le miroir et les copie dans la file VRAM.
Syntaxe
unsigned char nes_palette_queue_sprite4(unsigned char pal_index, unsigned char* src4);Paramètres
pal_indexIndice de palette de 0 à 3 ; la fonction ne le valide pas.
src4Quatre octets de la palette choisie ; utilisez des codes couleur de 0 à 63.
Valeur renvoyée
1 si la mise en file réussit, 0 si la capacité est insuffisante. Les nouvelles valeurs du miroir restent en place même en cas d’échec. La réussite ne signifie pas que le PPU a déjà été mis à jour.
Conditions et limites
La copie miroir réserve les adresses CPU 0x03C0–0x03DF. Les adresses PPU 0x3F10/14/18/1C sont des alias de 0x3F00/04/08/0C : les 32 octets bruts du miroir ne correspondent donc pas nécessairement à 32 valeurs PPU indépendantes relues. La file copie les valeurs ; la source peut donc être modifiée après une mise en file réussie. Évitez les accès concurrents non coordonnés entre la production dans la file et sa consommation par la NMI.
Exemple d’utilisation
result[4]=nes_palette_queue_sprite4(2,four);nes_vram_queue_nmi_flush();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Affichez des rectangles de fond de 32×32 rouges, bleus et verts en (16,32), (80,32) et (144,32), ainsi que des carrés de sprites de 8×8 en (16,96), (80,96) et (144,96), dans le même ordre de couleurs. Les palettes séparées du fond et des sprites illustrent les transferts directs et par file.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch2_palette.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_palette.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/palette.h:24
Update and queue four sprite palette bytes at the 0x3F10 region. The caller supplies pal_index 0..3; NES palette mirroring still applies.
kitaqfc/lib/palette.c:61
unsigned char nes_palette_queue_sprite4(unsigned char pal_index, unsigned char* src4)
{
unsigned char dst;
dst = pal_index + pal_index;
dst = dst + dst;
__memcpy(nes_palette_shadow + (unsigned char)(0x10 + dst), src4, 4);
return nes_vram_queue_try_write((unsigned short)(0x3F10 + dst), nes_palette_shadow + (unsigned char)(0x10 + dst), 4);
}Déplacement personnalisé avec les types Q5.3
En plus des fonctions world/body, physics2d.h définit des types et constantes pour des déplacements fractionnaires personnalisés. Cet exemple implémente game_step avec la convention Q5.3, selon une approche distincte de l’intégration world/body.
KQ2DPosition stocke la position en pixels entiers (0..255), KQ2DFraction le reste (0..7), KQ2DSpeed l’amplitude du déplacement par tick en huitièmes de pixel (0..255), et KQ2DDirection la direction. Les quatre types sont des u8. La direction est stockée séparément de la vitesse et non encodée par un signe.
Utilisez KQ2D_SUBPIXEL_BITS=3, ONE=8 et MASK=7 pour combiner position*8+fraction dans un intermédiaire sur 16 bits. La direction NONE=0 signifie aucun mouvement, NEGATIVE=1 une soustraction et POSITIVE=2 une addition. Le jeu doit gérer les limites afin que la soustraction reste positive ou nulle et que la position entière finale reste dans 0..255.
KQ2D_DRAG_BRAKE=1, STUN=2, COAST=3 et THRUST=4 identifient des comportements de freinage, d’étourdissement, de roue libre et de poussée définis par le jeu. Une simple affectation n’applique ni accélération ni résistance. Définissez chaque effet et sa durée dans votre routine de mise à jour.
Exemple : accumuler des déplacements d’un demi-pixel
Le carré rouge supérieur de 16×16 pixels démarre à X=24 ; celui du bas montre X=32 après 16 ticks. Une vitesse de 4 signifie 4/8=0.5 pixel par tick, soit huit pixels en 16 ticks. Les positions Y différentes séparent les deux états pour les comparer. Une vérification numérique suivante recule pendant huit ticks et obtient X=28, avec une fraction de 0.
void game_step() {
u16 total;
total=(u16)position*KQ2D_SUBPIXEL_ONE+fraction;
if(direction==KQ2D_DIR_POSITIVE) total=total+speed;
else if(direction==KQ2D_DIR_NEGATIVE) total=total-speed;
position=(KQ2DPosition)(total>>KQ2D_SUBPIXEL_BITS);
fraction=(KQ2DFraction)(total&KQ2D_SUBPIXEL_MASK);
}
// Initial state: position=24; fraction=0; speed=4;
// direction=KQ2D_DIR_POSITIVE; call game_step() 16 times.
Compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_subpixel.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\physics_subpixel.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmphysics2d
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.
Ne vous contentez pas d’inclure les en-têtes : compilez aussi les fichiers d’implémentation. En 2D, utilisez fixed.c et physics2d.c ; en 3D, ajoutez physics3d.c. Les exemples utilisent MMC3, la CHR RAM et un espace de dessin en PRG RAM à $6800–$6FFF. Ce tampon de dessin n’est pas une exigence de la bibliothèque physique elle-même.
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.
Ne vous contentez pas d’inclure les en-têtes : compilez aussi les fichiers d’implémentation. En 2D, utilisez fixed.c et physics2d.c ; en 3D, ajoutez physics3d.c. Les exemples utilisent MMC3, la CHR RAM et un espace de dessin en PRG RAM à $6800–$6FFF. Ce tampon de dessin n’est pas une exigence de la bibliothèque physique elle-même.
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, un tick plus tard. Un carré rouge de 16×16, centré en (24,24) et de vitesse (4,16), atteint (28,36), avec une vitesse Y nulle sur le sol bleu. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48). Les vérifications RAM couvrent aussi l’initialisation, les fonctions de réglage, l’intégration, les requêtes rectangle/point et la mise à l’échelle signée.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body2d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body2d.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/physics2d.h:36
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.
kitaqfc/lib/physics2d.c:351
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;
}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.
Ne vous contentez pas d’inclure les en-têtes : compilez aussi les fichiers d’implémentation. En 2D, utilisez fixed.c et physics2d.c ; en 3D, ajoutez physics3d.c. Les exemples utilisent MMC3, la CHR RAM et un espace de dessin en PRG RAM à $6800–$6FFF. Ce tampon de dessin n’est pas une exigence de la bibliothèque physique elle-même.
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, un tick plus tard. Un carré rouge de 16×16, centré en (24,24) et de vitesse (4,16), atteint (28,36), avec une vitesse Y nulle sur le sol bleu. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48). Les vérifications RAM couvrent aussi l’initialisation, les fonctions de réglage, l’intégration, les requêtes rectangle/point et la mise à l’échelle signée.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body2d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body2d.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/physics2d.h:41
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 uses non-reentrant helper scratch. This is discrete integration; fast bodies can pass through thin obstacles.
kitaqfc/lib/physics2d.c:581
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[(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_value();
kq2d_asm_limit = world->max_speed;
kq2d__clamp_value();
b->vx = kq2d_asm_value;
kq2d_asm_value = b->vy;
kq2d_asm_operand = world->gravity_y;
kq2d__add_value();
kq2d_asm_limit = world->max_speed;
kq2d__clamp_value();
b->vy = kq2d_asm_value;
kq2d_asm_value = b->x;
kq2d_asm_operand = b->vx;
kq2d__add_value();
b->x = kq2d_asm_value;
kq2d_asm_value = b->y;
kq2d_asm_operand = b->vy;
kq2d__add_value();
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[(u8)i];
if (a->active == 0) continue;
u8 j;
for (j = (u8)(i + 1); j < count; j++)
{
KQBody2D* b = &bodies[(u8)j];
if (b->active == 0) continue;
kq2d__resolve_pair(a, b);
}
}
}
}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é.
Ne vous contentez pas d’inclure les en-têtes : compilez aussi les fichiers d’implémentation. En 2D, utilisez fixed.c et physics2d.c ; en 3D, ajoutez physics3d.c. Les exemples utilisent MMC3, la CHR RAM et un espace de dessin en PRG RAM à $6800–$6FFF. Ce tampon de dessin n’est pas une exigence de la bibliothèque physique elle-même.
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, un tick plus tard. Un carré rouge de 16×16, centré en (24,24) et de vitesse (4,16), atteint (28,36), avec une vitesse Y nulle sur le sol bleu. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48). Les vérifications RAM couvrent aussi l’initialisation, les fonctions de réglage, l’intégration, les requêtes rectangle/point et la mise à l’échelle signée.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body2d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body2d.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/physics2d.h:45
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.
kitaqfc/lib/physics2d.c:451
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_value();
kq2d_asm_limit = world->max_speed;
kq2d__clamp_value();
body->vx = kq2d_asm_value;
kq2d_asm_value = body->vy;
kq2d_asm_operand = world->gravity_y;
kq2d__add_value();
kq2d_asm_limit = world->max_speed;
kq2d__clamp_value();
body->vy = kq2d_asm_value;
kq2d_asm_value = body->x;
kq2d_asm_operand = body->vx;
kq2d__add_value();
body->x = kq2d_asm_value;
kq2d_asm_value = body->y;
kq2d_asm_operand = body->vy;
kq2d__add_value();
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.
Ne vous contentez pas d’inclure les en-têtes : compilez aussi les fichiers d’implémentation. En 2D, utilisez fixed.c et physics2d.c ; en 3D, ajoutez physics3d.c. Les exemples utilisent MMC3, la CHR RAM et un espace de dessin en PRG RAM à $6800–$6FFF. Ce tampon de dessin n’est pas une exigence de la bibliothèque physique elle-même.
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, un tick plus tard. Un carré rouge de 16×16, centré en (24,24) et de vitesse (4,16), atteint (28,36), avec une vitesse Y nulle sur le sol bleu. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48). Les vérifications RAM couvrent aussi l’initialisation, les fonctions de réglage, l’intégration, les requêtes rectangle/point et la mise à l’échelle signée.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body2d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body2d.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/physics2d.h:49
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.
kitaqfc/lib/physics2d.c:366
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_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.
Ne vous contentez pas d’inclure les en-têtes : compilez aussi les fichiers d’implémentation. En 2D, utilisez fixed.c et physics2d.c ; en 3D, ajoutez physics3d.c. Les exemples utilisent MMC3, la CHR RAM et un espace de dessin en PRG RAM à $6800–$6FFF. Ce tampon de dessin n’est pas une exigence de la bibliothèque physique elle-même.
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, un tick plus tard. Un carré rouge de 16×16, centré en (24,24) et de vitesse (4,16), atteint (28,36), avec une vitesse Y nulle sur le sol bleu. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48). Les vérifications RAM couvrent aussi l’initialisation, les fonctions de réglage, l’intégration, les requêtes rectangle/point et la mise à l’échelle signée.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body2d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body2d.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/physics2d.h:52
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.
kitaqfc/lib/physics2d.c:384
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_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.
Ne vous contentez pas d’inclure les en-têtes : compilez aussi les fichiers d’implémentation. En 2D, utilisez fixed.c et physics2d.c ; en 3D, ajoutez physics3d.c. Les exemples utilisent MMC3, la CHR RAM et un espace de dessin en PRG RAM à $6800–$6FFF. Ce tampon de dessin n’est pas une exigence de la bibliothèque physique elle-même.
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, un tick plus tard. Un carré rouge de 16×16, centré en (24,24) et de vitesse (4,16), atteint (28,36), avec une vitesse Y nulle sur le sol bleu. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48). Les vérifications RAM couvrent aussi l’initialisation, les fonctions de réglage, l’intégration, les requêtes rectangle/point et la mise à l’échelle signée.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body2d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body2d.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/physics2d.h:54
Replace the center without altering velocity, extents or activity. Null is ignored.
kitaqfc/lib/physics2d.c:399
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.
Ne vous contentez pas d’inclure les en-têtes : compilez aussi les fichiers d’implémentation. En 2D, utilisez fixed.c et physics2d.c ; en 3D, ajoutez physics3d.c. Les exemples utilisent MMC3, la CHR RAM et un espace de dessin en PRG RAM à $6800–$6FFF. Ce tampon de dessin n’est pas une exigence de la bibliothèque physique elle-même.
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, un tick plus tard. Un carré rouge de 16×16, centré en (24,24) et de vitesse (4,16), atteint (28,36), avec une vitesse Y nulle sur le sol bleu. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48). Les vérifications RAM couvrent aussi l’initialisation, les fonctions de réglage, l’intégration, les requêtes rectangle/point et la mise à l’échelle signée.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body2d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body2d.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/physics2d.h:56
Replace velocity without clamping or checking activity/mass. Null is ignored.
kitaqfc/lib/physics2d.c:407
void kq2d_body_set_velocity(KQBody2D* body, s16 vx, s16 vy)
{
if (body == 0) return;
body->vx = vx;
body->vy = vy;
}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.
Ne vous contentez pas d’inclure les en-têtes : compilez aussi les fichiers d’implémentation. En 2D, utilisez fixed.c et physics2d.c ; en 3D, ajoutez physics3d.c. Les exemples utilisent MMC3, la CHR RAM et un espace de dessin en PRG RAM à $6800–$6FFF. Ce tampon de dessin n’est pas une exigence de la bibliothèque physique elle-même.
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, un tick plus tard. Un carré rouge de 16×16, centré en (24,24) et de vitesse (4,16), atteint (28,36), avec une vitesse Y nulle sur le sol bleu. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48). Les vérifications RAM couvrent aussi l’initialisation, les fonctions de réglage, l’intégration, les requêtes rectangle/point et la mise à l’échelle signée.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body2d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body2d.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/physics2d.h:60
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.
kitaqfc/lib/physics2d.c:417
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_value();
kq2d_asm_limit = max_speed;
kq2d__clamp_value();
body->vx = kq2d_asm_value;
kq2d_asm_value = body->vy;
kq2d_asm_operand = gravity_y;
kq2d__add_value();
kq2d_asm_limit = max_speed;
kq2d__clamp_value();
body->vy = kq2d_asm_value;
}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é.
Ne vous contentez pas d’inclure les en-têtes : compilez aussi les fichiers d’implémentation. En 2D, utilisez fixed.c et physics2d.c ; en 3D, ajoutez physics3d.c. Les exemples utilisent MMC3, la CHR RAM et un espace de dessin en PRG RAM à $6800–$6FFF. Ce tampon de dessin n’est pas une exigence de la bibliothèque physique elle-même.
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, un tick plus tard. Un carré rouge de 16×16, centré en (24,24) et de vitesse (4,16), atteint (28,36), avec une vitesse Y nulle sur le sol bleu. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48). Les vérifications RAM couvrent aussi l’initialisation, les fonctions de réglage, l’intégration, les requêtes rectangle/point et la mise à l’échelle signée.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body2d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body2d.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/physics2d.h:64
Scale both velocities by a signed eight-bit coefficient divided by 256. Despite the unsigned parameter, values 128..255 become negative coefficients; this is not a full-range unsigned Q8 damping helper. Null is ignored.
kitaqfc/lib/physics2d.c:441
void kq2d_body_apply_friction(KQBody2D* body, u8 friction_q8)
{
if (body == 0) return;
body->vx = kq2d_scale_q8(body->vx, (s16)(s8)friction_q8);
body->vy = kq2d_scale_q8(body->vy, (s16)(s8)friction_q8);
}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.
Ne vous contentez pas d’inclure les en-têtes : compilez aussi les fichiers d’implémentation. En 2D, utilisez fixed.c et physics2d.c ; en 3D, ajoutez physics3d.c. Les exemples utilisent MMC3, la CHR RAM et un espace de dessin en PRG RAM à $6800–$6FFF. Ce tampon de dessin n’est pas une exigence de la bibliothèque physique elle-même.
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, un tick plus tard. Un carré rouge de 16×16, centré en (24,24) et de vitesse (4,16), atteint (28,36), avec une vitesse Y nulle sur le sol bleu. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48). Les vérifications RAM couvrent aussi l’initialisation, les fonctions de réglage, l’intégration, les requêtes rectangle/point et la mise à l’échelle signée.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body2d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body2d.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/physics2d.h:67
Delegate strict rectangle overlap to the fixed-point utility; edge-only contact is false. Coordinate-plus-size sums must remain representable as s16.
kitaqfc/lib/physics2d.c:485
u8 kq2d_rect_intersect(KQRect a, KQRect b)
{
return kq_rect_intersect(a, b);
}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.
Ne vous contentez pas d’inclure les en-têtes : compilez aussi les fichiers d’implémentation. En 2D, utilisez fixed.c et physics2d.c ; en 3D, ajoutez physics3d.c. Les exemples utilisent MMC3, la CHR RAM et un espace de dessin en PRG RAM à $6800–$6FFF. Ce tampon de dessin n’est pas une exigence de la bibliothèque physique elle-même.
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, un tick plus tard. Un carré rouge de 16×16, centré en (24,24) et de vitesse (4,16), atteint (28,36), avec une vitesse Y nulle sur le sol bleu. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48). Les vérifications RAM couvrent aussi l’initialisation, les fonctions de réglage, l’intégration, les requêtes rectangle/point et la mise à l’échelle signée.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body2d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body2d.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/physics2d.h:70
Delegate the half-open point test: include left/top and exclude right/bottom. Coordinate-plus-size sums must remain representable as s16.
kitaqfc/lib/physics2d.c:492
u8 kq2d_point_in_rect(s16 x, s16 y, KQRect r)
{
return kq_point_in_rect(x, y, r);
}kq2d_scale_q8
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.
Ne vous contentez pas d’inclure les en-têtes : compilez aussi les fichiers d’implémentation. En 2D, utilisez fixed.c et physics2d.c ; en 3D, ajoutez physics3d.c. Les exemples utilisent MMC3, la CHR RAM et un espace de dessin en PRG RAM à $6800–$6FFF. Ce tampon de dessin n’est pas une exigence de la bibliothèque physique elle-même.
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. Sa ligne de vitesse verte passe de (8,16) à gauche à (2,−8) à droite, montrant le rebond et le frottement tangentiel contre la surface bleue. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48) ; le centre local du corps est (24,40). La vitesse incidente est 16 et l’exemple de temps de franchissement renvoie 192/256. Un appel distinct de limitation de vitesse réduit (300,400) à (147,196).

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_surface.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_surface.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/physics2d.h:86
Truncates toward zero, including negative values; coefficient is -256..256.
kitaqfc/lib/physics2d.c:8
s16 kq2d_scale_q8(s16 value,s16 coefficient) {
u16 magnitude;u16 product;u8 factor;u8 negative;
__asm {
LDA value
ORA value+1
BEQ kqfc_scale_zero
LDA coefficient
BNE kqfc_scale_fraction
LDA coefficient+1
BEQ kqfc_scale_zero
BMI kqfc_scale_negate_value
LDA value
LDX value+1
RTS
kqfc_scale_negate_value:
SEC
LDA #0
SBC value
STA product
LDA #0
SBC value+1
TAX
LDA product
RTS
kqfc_scale_zero:
LDA #0
LDX #0
RTS
kqfc_scale_fraction:
LDA value+1
EOR coefficient+1
AND #128
STA negative
LDA value
STA magnitude
LDA value+1
STA magnitude+1
BPL kqfc_scale_value_positive
SEC
LDA #0
SBC magnitude
STA magnitude
LDA #0
SBC magnitude+1
STA magnitude+1
kqfc_scale_value_positive:
LDA coefficient
STA factor
LDA coefficient+1
BPL kqfc_scale_factor_positive
SEC
LDA #0
SBC factor
STA factor
kqfc_scale_factor_positive:
LDA #0
STA product
STA product+1
// Process coefficient bit 0; carry is the product's seventeenth bit.
LSR factor
BCC kqfc_scale_shift_0
CLC
LDA product
ADC magnitude
STA product
LDA product+1
ADC magnitude+1
STA product+1
kqfc_scale_shift_0:
ROR product+1
ROR product
// Process coefficient bit 1; carry is the product's seventeenth bit.
LSR factor
BCC kqfc_scale_shift_1
CLC
LDA product
ADC magnitude
STA product
LDA product+1
ADC magnitude+1
STA product+1
kqfc_scale_shift_1:
ROR product+1
ROR product
// Process coefficient bit 2; carry is the product's seventeenth bit.
LSR factor
BCC kqfc_scale_shift_2
CLC
LDA product
ADC magnitude
STA product
LDA product+1
ADC magnitude+1
STA product+1
kqfc_scale_shift_2:
ROR product+1
ROR product
// Process coefficient bit 3; carry is the product's seventeenth bit.
LSR factor
BCC kqfc_scale_shift_3
CLC
LDA product
ADC magnitude
STA product
LDA product+1
ADC magnitude+1
STA product+1
kqfc_scale_shift_3:
ROR product+1
ROR product
// Process coefficient bit 4; carry is the product's seventeenth bit.
LSR factor
BCC kqfc_scale_shift_4
CLC
LDA product
ADC magnitude
STA product
LDA product+1
ADC magnitude+1
STA product+1
kqfc_scale_shift_4:
ROR product+1
ROR product
// Process coefficient bit 5; carry is the product's seventeenth bit.
LSR factor
BCC kqfc_scale_shift_5
CLC
LDA product
ADC magnitude
STA product
LDA product+1
ADC magnitude+1
STA product+1
kqfc_scale_shift_5:
ROR product+1
ROR product
// Process coefficient bit 6; carry is the product's seventeenth bit.
LSR factor
BCC kqfc_scale_shift_6
CLC
LDA product
ADC magnitude
STA product
LDA product+1
ADC magnitude+1
STA product+1
kqfc_scale_shift_6:
ROR product+1
ROR product
// Process coefficient bit 7; carry is the product's seventeenth bit.
LSR factor
BCC kqfc_scale_shift_7
CLC
LDA product
ADC magnitude
STA product
LDA product+1
ADC magnitude+1
STA product+1
kqfc_scale_shift_7:
ROR product+1
ROR product
LDA negative
BEQ kqfc_scale_positive
SEC
LDA #0
SBC product
STA product
LDA #0
SBC product+1
TAX
LDA product
RTS
kqfc_scale_positive:
LDA product
LDX product+1
RTS
}
}kq2d_body_limit_speed
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.
Ne vous contentez pas d’inclure les en-têtes : compilez aussi les fichiers d’implémentation. En 2D, utilisez fixed.c et physics2d.c ; en 3D, ajoutez physics3d.c. Les exemples utilisent MMC3, la CHR RAM et un espace de dessin en PRG RAM à $6800–$6FFF. Ce tampon de dessin n’est pas une exigence de la bibliothèque physique elle-même.
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. Sa ligne de vitesse verte passe de (8,16) à gauche à (2,−8) à droite, montrant le rebond et le frottement tangentiel contre la surface bleue. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48) ; le centre local du corps est (24,40). La vitesse incidente est 16 et l’exemple de temps de franchissement renvoie 192/256. Un appel distinct de limitation de vitesse réduit (300,400) à (147,196).

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_surface.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_surface.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/physics2d.h:90
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.
kitaqfc/lib/physics2d.c:214
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[(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
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.
Ne vous contentez pas d’inclure les en-têtes : compilez aussi les fichiers d’implémentation. En 2D, utilisez fixed.c et physics2d.c ; en 3D, ajoutez physics3d.c. Les exemples utilisent MMC3, la CHR RAM et un espace de dessin en PRG RAM à $6800–$6FFF. Ce tampon de dessin n’est pas une exigence de la bibliothèque physique elle-même.
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. Sa ligne de vitesse verte passe de (8,16) à gauche à (2,−8) à droite, montrant le rebond et le frottement tangentiel contre la surface bleue. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48) ; le centre local du corps est (24,40). La vitesse incidente est 16 et l’exemple de temps de franchissement renvoie 192/256. Un appel distinct de limitation de vitesse réduit (300,400) à (147,196).

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_surface.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_surface.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/physics2d.h:93
Kinematic surface response; returns incoming normal speed, or zero if separating. Caller resolves penetration separately. Relative components must fit +/-8191.
kitaqfc/lib/physics2d.c:268
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_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.
Ne vous contentez pas d’inclure les en-têtes : compilez aussi les fichiers d’implémentation. En 2D, utilisez fixed.c et physics2d.c ; en 3D, ajoutez physics3d.c. Les exemples utilisent MMC3, la CHR RAM et un espace de dessin en PRG RAM à $6800–$6FFF. Ce tampon de dessin n’est pas une exigence de la bibliothèque physique elle-même.
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. Sa ligne de vitesse verte passe de (8,16) à gauche à (2,−8) à droite, montrant le rebond et le frottement tangentiel contre la surface bleue. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48) ; le centre local du corps est (24,40). La vitesse incidente est 16 et l’exemple de temps de franchissement renvoie 192/256. Un appel distinct de limitation de vitesse réduit (300,400) à (147,196).

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_surface.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_surface.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/physics2d.h:96
Linear crossing time in Q8 (0..256); positive separation is outside. Returns 0 for initial overlap, 256 for no crossing. Gaps must fit +/-8191.
kitaqfc/lib/physics2d.c:245
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));
}physics3d
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.
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.
Ne vous contentez pas d’inclure les en-têtes : compilez aussi les fichiers d’implémentation. En 2D, utilisez fixed.c et physics2d.c ; en 3D, ajoutez physics3d.c. Les exemples utilisent MMC3, la CHR RAM et un espace de dessin en PRG RAM à $6800–$6FFF. Ce tampon de dessin n’est pas une exigence de la bibliothèque physique elle-même.
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.
Ne vous contentez pas d’inclure les en-têtes : compilez aussi les fichiers d’implémentation. En 2D, utilisez fixed.c et physics2d.c ; en 3D, ajoutez physics3d.c. Les exemples utilisent MMC3, la CHR RAM et un espace de dessin en PRG RAM à $6800–$6FFF. Ce tampon de dessin n’est pas une exigence de la bibliothèque physique elle-même.
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 rectangles rouges montrent (36,24,24) après un tick et les régions bleues représentent l’obstacle statique. La vitesse X passe de 16 à −14, tandis que la vitesse Z reste à 8. L’impact vaut 16, mais les indicateurs restent nuls même avec break_speed=1. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48).

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body3d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body3d.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/physics3d.h:47
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.
kitaqfc/lib/physics3d.c:125
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;
}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.
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.
Ne vous contentez pas d’inclure les en-têtes : compilez aussi les fichiers d’implémentation. En 2D, utilisez fixed.c et physics2d.c ; en 3D, ajoutez physics3d.c. Les exemples utilisent MMC3, la CHR RAM et un espace de dessin en PRG RAM à $6800–$6FFF. Ce tampon de dessin n’est pas une exigence de la bibliothèque physique elle-même.
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 rectangles rouges montrent (36,24,24) après un tick et les régions bleues représentent l’obstacle statique. La vitesse X passe de 16 à −14, tandis que la vitesse Z reste à 8. L’impact vaut 16, mais les indicateurs restent nuls même avec break_speed=1. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48).

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body3d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body3d.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/physics3d.h:51
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.
kitaqfc/lib/physics3d.c:161
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
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é.
Ne vous contentez pas d’inclure les en-têtes : compilez aussi les fichiers d’implémentation. En 2D, utilisez fixed.c et physics2d.c ; en 3D, ajoutez physics3d.c. Les exemples utilisent MMC3, la CHR RAM et un espace de dessin en PRG RAM à $6800–$6FFF. Ce tampon de dessin n’est pas une exigence de la bibliothèque physique elle-même.
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 rectangles rouges montrent (36,24,24) après un tick et les régions bleues représentent l’obstacle statique. La vitesse X passe de 16 à −14, tandis que la vitesse Z reste à 8. L’impact vaut 16, mais les indicateurs restent nuls même avec break_speed=1. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48).

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body3d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body3d.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/physics3d.h:56
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.
kitaqfc/lib/physics3d.c:142
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_step
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.
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.
Ne vous contentez pas d’inclure les en-têtes : compilez aussi les fichiers d’implémentation. En 2D, utilisez fixed.c et physics2d.c ; en 3D, ajoutez physics3d.c. Les exemples utilisent MMC3, la CHR RAM et un espace de dessin en PRG RAM à $6800–$6FFF. Ce tampon de dessin n’est pas une exigence de la bibliothèque physique elle-même.
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 rectangles rouges montrent (36,24,24) après un tick et les régions bleues représentent l’obstacle statique. La vitesse X passe de 16 à −14, tandis que la vitesse Z reste à 8. L’impact vaut 16, mais les indicateurs restent nuls même avec break_speed=1. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48).

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body3d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body3d.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/physics3d.h:62
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 uses non-reentrant helper scratch and can miss fast crossings.
kitaqfc/lib/physics3d.c:323
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[(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_value();
kq3d_asm_operand = b->ax;
kq3d__add_value();
kq3d_asm_limit = world->max_speed;
kq3d__clamp_value();
b->vx = kq3d_asm_value;
kq3d_asm_value = b->vy;
kq3d_asm_operand = world->gravity_y;
kq3d__add_value();
kq3d_asm_operand = b->ay;
kq3d__add_value();
kq3d_asm_limit = world->max_speed;
kq3d__clamp_value();
b->vy = kq3d_asm_value;
kq3d_asm_value = b->vz;
kq3d_asm_operand = world->gravity_z;
kq3d__add_value();
kq3d_asm_operand = b->az;
kq3d__add_value();
kq3d_asm_limit = world->max_speed;
kq3d__clamp_value();
b->vz = kq3d_asm_value;
kq3d_asm_value = b->x;
kq3d_asm_operand = b->vx;
kq3d__add_value();
b->x = kq3d_asm_value;
kq3d_asm_value = b->y;
kq3d_asm_operand = b->vy;
kq3d__add_value();
b->y = kq3d_asm_value;
kq3d_asm_value = b->z;
kq3d_asm_operand = b->vz;
kq3d__add_value();
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[(u8)i];
if (a->active == 0) continue;
u8 j;
for (j = (u8)(i + 1); j < count; j++)
{
KQBody3D* b = &bodies[(u8)j];
if (b->active == 0) continue;
kq3d__resolve_pair(a, b);
}
}
}
}kq3d_integrate_body
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.
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.
Ne vous contentez pas d’inclure les en-têtes : compilez aussi les fichiers d’implémentation. En 2D, utilisez fixed.c et physics2d.c ; en 3D, ajoutez physics3d.c. Les exemples utilisent MMC3, la CHR RAM et un espace de dessin en PRG RAM à $6800–$6FFF. Ce tampon de dessin n’est pas une exigence de la bibliothèque physique elle-même.
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 rectangles rouges montrent (36,24,24) après un tick et les régions bleues représentent l’obstacle statique. La vitesse X passe de 16 à −14, tandis que la vitesse Z reste à 8. L’impact vaut 16, mais les indicateurs restent nuls même avec break_speed=1. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48).

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body3d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body3d.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/physics3d.h:67
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.
kitaqfc/lib/physics3d.c:267
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_value();
kq3d_asm_operand = body->ax;
kq3d__add_value();
kq3d_asm_limit = world->max_speed;
kq3d__clamp_value();
body->vx = kq3d_asm_value;
kq3d_asm_value = body->vy;
kq3d_asm_operand = world->gravity_y;
kq3d__add_value();
kq3d_asm_operand = body->ay;
kq3d__add_value();
kq3d_asm_limit = world->max_speed;
kq3d__clamp_value();
body->vy = kq3d_asm_value;
kq3d_asm_value = body->vz;
kq3d_asm_operand = world->gravity_z;
kq3d__add_value();
kq3d_asm_operand = body->az;
kq3d__add_value();
kq3d_asm_limit = world->max_speed;
kq3d__clamp_value();
body->vz = kq3d_asm_value;
kq3d_asm_value = body->x;
kq3d_asm_operand = body->vx;
kq3d__add_value();
body->x = kq3d_asm_value;
kq3d_asm_value = body->y;
kq3d_asm_operand = body->vy;
kq3d__add_value();
body->y = kq3d_asm_value;
kq3d_asm_value = body->z;
kq3d_asm_operand = body->vz;
kq3d__add_value();
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.
Ne vous contentez pas d’inclure les en-têtes : compilez aussi les fichiers d’implémentation. En 2D, utilisez fixed.c et physics2d.c ; en 3D, ajoutez physics3d.c. Les exemples utilisent MMC3, la CHR RAM et un espace de dessin en PRG RAM à $6800–$6FFF. Ce tampon de dessin n’est pas une exigence de la bibliothèque physique elle-même.
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 rectangles rouges montrent (36,24,24) après un tick et les régions bleues représentent l’obstacle statique. La vitesse X passe de 16 à −14, tandis que la vitesse Z reste à 8. L’impact vaut 16, mais les indicateurs restent nuls même avec break_speed=1. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48).

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body3d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body3d.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/physics3d.h:71
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.
kitaqfc/lib/physics3d.c:188
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_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
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.
Ne vous contentez pas d’inclure les en-têtes : compilez aussi les fichiers d’implémentation. En 2D, utilisez fixed.c et physics2d.c ; en 3D, ajoutez physics3d.c. Les exemples utilisent MMC3, la CHR RAM et un espace de dessin en PRG RAM à $6800–$6FFF. Ce tampon de dessin n’est pas une exigence de la bibliothèque physique elle-même.
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 rectangles rouges montrent (36,24,24) après un tick et les régions bleues représentent l’obstacle statique. La vitesse X passe de 16 à −14, tandis que la vitesse Z reste à 8. L’impact vaut 16, mais les indicateurs restent nuls même avec break_speed=1. Les origines des panneaux sont aux coordonnées écran (8,48) et (88,48).

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\physics_body3d.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --mapper=mmc3 --nes-chr-ram -o .\out\physics_body3d.nes --no-cache --no-disasmImplémentation et source
kitaqfc/lib/physics3d.h:75
Sum three signed products, dividing each by 256 (toward zero) before addition. Coefficients are signed bytes scaled by 1/256; the 16-bit sum is not saturated.
kitaqfc/lib/physics3d.c:407
s16 kq3d_dot_q8_8(s16 x, s16 y, s16 z, s8 ax, s8 ay, s8 az)
{
return (s16)(kq2d_scale_q8(x,(s16)ax) + kq2d_scale_q8(y,(s16)ay) + kq2d_scale_q8(z,(s16)az));
}ppu.h — Déclarations d'affichage PPU
Incluez ou compilez ppu.c une seule fois, sans runtime.c. Avant ses fonctions à deux octets d’adresse, appelez __ppu_read_status() pour réinitialiser le verrou partagé. ppu.h ne déclare pas ces fonctions : ses quatre déclarations relatives à l’écran, à la palette et à la table de noms n’ont pas d’implémentation dans cette distribution. Les fonctions présentées ici proviennent de ppu.c ; inclure uniquement ppu.h ne suffit pas.
nes_ppu_clear_nt
Cette distribution n’implémente pas nes_ppu_clear_nt(nt_base, tile, attr). L’exemple efface la table de noms 0 en deux opérations : __nametable_rect_nt(0,0,0,32,30,0) écrit ses 960 cellules de tuiles, puis __vram_fill(0x23C0,0,64) efface ses 64 octets d’attributs compactés. Le rendu est désactivé et l’incrément vaut 1. Les tables logiques peuvent partager leur mémoire selon le mirroring de la cartouche.
Syntaxe
void nes_ppu_clear_nt(unsigned short nt_base, unsigned char tile, unsigned char attr);Paramètres
nt_base / tile / attrLe prototype déclare
nt_basesur 16 bits non signés ettile/attrsur huit bits non signés. Aucun corps n’implémente la sélection d’adresse, le remplissage ou la validation. La solution de remplacement choisit explicitement la table logique 0 et fournit séparément les valeurs de tuile et d’attribut compacté.
Valeur renvoyée
Type de retour déclaré : void. Aucune implémentation n’est liée ; il n’existe donc pas de comportement de retour exécutable pour ce nom.
Conditions et limites
L’exemple présente des solutions implémentées, pas un appel réussi à la déclaration. La vérification comprend l’échec attendu pour symbole non résolu de chaque nom absent et des contrôles distincts des solutions dans l’émulateur. Pour appeler le nom déclaré, fournissez une implémentation compatible ; inclure un autre en-tête ne crée pas le corps.
Exemple d’utilisation
nes_ppu_clear_nt(0x2000,0,0); // All 960 tiles and 64 packed attribute bytes.
// Nametable reads are buffered: discard one read, then inspect all 1024 bytes.
__ppu_addr(0x2000);discarded_read=sample_ppudata;
for(i=0;i<1024;i++)if(sample_ppudata!=0)failures=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 solution prépare l’écran sans rendu, installe les palettes, efface tuiles et attributs, puis dessine ce test. Un motif bleu de tuiles pleines, demi-barres gauches et triangles commence en (0,16) ; un bloc vert plein commence en (0,96). Chaque région mesure 256×64 pixels, sauf sa dernière case de 8×8 en (248,72) ou (248,152), qui reste noire car le transfert contient 255 octets de tuiles. À y=208, les formes rouges sont un carré de 8×8 en x=16, une barre gauche de 4×8 en x=224 et un triangle de huit lignes en x=240. FAILED CHECKS indique 0. Des tests d’état distincts confirment les deux registres de contrôle, le transfert des 32 octets de palette et l’effacement des 1 024 octets de la table de noms. Les quatre appels déclarés doivent échouer à l’édition de liens.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\ppu_implemented.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\ppu_implemented.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/ppu.h:14
Fill 960 tiles and 64 packed attributes; preserve PPUCTRL. Accept exactly $2000/$2400/$2800/$2C00; invalid bases are ignored.
kitaqfc/lib/ppu.c:60
void nes_ppu_clear_nt(unsigned short nt_base, unsigned char tile, unsigned char attr)
{
unsigned char table;
unsigned char saved_ctrl;
if (nt_base != 0x2000 && nt_base != 0x2400 && nt_base != 0x2800 && nt_base != 0x2C00) return;
table = (unsigned char)((nt_base - 0x2000) >> 10);
saved_ctrl=__ppu_ctrl_get();
__ppu_ctrl_set((u8)(saved_ctrl & 0xFB));
__nametable_rect_nt(table,0,0,32,30,tile);
__vram_fill((u16)(nt_base+0x3C0),attr,64);
__ppu_ctrl_set(saved_ctrl);
}nes_ppu_fill
Définit l’adresse avec hi et lo, puis écrit value dans PPUDATA count fois. Cette fonction de ppu.c remplit immédiatement avec un nombre sur huit bits ; l’appelant réinitialise d’abord le verrou. Elle ne limite pas l’écriture aux lignes ou aux rectangles.
Syntaxe
void nes_ppu_fill(unsigned char hi, unsigned char lo, unsigned char value, unsigned char count);Paramètres
hi / lohietlosont les octets de poids fort et faible d’une adresse PPU : par exemple,0x23, 0x42désigne0x2342. Ce ne sont pas des coordonnées de tuiles. Les règles habituelles de masquage et de miroir des adresses PPU s’appliquent.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.
countNombre d’octets de
0..255(huit bits non signés). Zéro définit l’adresse sans écrire de données. Le verrou partagé n’est pas réinitialisé, même pour zéro ; préparez-le avant l’appel.
Valeur renvoyée
Aucune (void).
Conditions et limites
Incluez ou compilez ppu.c une seule fois, sans runtime.c. Avant ses fonctions à deux octets d’adresse, appelez __ppu_read_status() pour réinitialiser le verrou partagé. ppu.h ne déclare pas ces fonctions : ses quatre déclarations relatives à l’écran, à la palette et à la table de noms n’ont pas d’implémentation dans cette distribution. Les fonctions présentées ici proviennent de ppu.c ; inclure uniquement ppu.h ne suffit pas.
L’accès direct à la PPU exige de désactiver le rendu ou de terminer toute l’opération dans un intervalle VBlank sûr. Ces fonctions n’attendent pas, ne mettent rien en file, ne bloquent pas NMI et ne rétablissent pas le défilement. Empêchez une interruption de modifier le verrou ou l’adresse partagés pendant l’appel. Le bit 2 de PPUCTRL choisit un pas de destination de 1 ou 32 par octet. La PPU gère les miroirs et le bouclage des adresses ; la CHR-ROM n’est pas inscriptible. Rétablissez le défilement voulu avant le rendu.
Exemple d’utilisation
__ppu_read_status();nes_ppu_fill(0x21,0x80,1,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’exemple séparé à deux octets d’adresse montre la préparation explicite du verrou et les nombres sur huit bits. Les régions bleue et verte utilisent chacune 255 octets : les dernières cases de 8×8, en (248,72) et (248,152), restent noires. Les repères rouges ont les mêmes positions et formes que dans l’exemple du runtime. FAILED CHECKS indique 0 ; ce programme ne teste pas les fonctions d’attente du runtime.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\ppu_address_pair.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\ppu_address_pair.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/ppu.c:27
Set the address and issue count identical PPUDATA writes without waiting for VBlank.
kitaqfc/lib/ppu.c:27
void nes_ppu_fill(unsigned char hi, unsigned char lo, unsigned char value, unsigned char count)
{
unsigned char i;
nes_ppu_seek_bytes(hi, lo);
for (i = 0; i != count; ++i)
kq_ppu_data_register = value;
}nes_ppu_load_palette
nes_ppu_load_palette(pal32) n’a qu’une déclaration, sans transfert de palette implémenté. L’exemple utilise __palette_bg_load pour 16 octets de fond et __palette_sp_load pour 16 octets de sprites, rendu désactivé et incrément d’adresse à 1. Les alias matériels de palette restent actifs : une écriture de palette de sprites peut aussi modifier une entrée du fond.
Syntaxe
void nes_ppu_load_palette(unsigned char* pal32);Paramètres
pal32pal32est déclaré comme pointeur vers des octets non signés. Ce nom ne fournit pas de transfert implémenté de 32 octets. Pour la solution fonctionnelle, fournissez 16 octets lisibles à chaque intrinsèque de palette et maintenez la banque source accessible jusqu’au retour.
Valeur renvoyée
Type de retour déclaré : void. Aucune implémentation n’est liée ; il n’existe donc pas de comportement de retour exécutable pour ce nom.
Conditions et limites
L’exemple présente des solutions implémentées, pas un appel réussi à la déclaration. La vérification comprend l’échec attendu pour symbole non résolu de chaque nom absent et des contrôles distincts des solutions dans l’émulateur. Pour appeler le nom déclaré, fournissez une implémentation compatible ; inclure un autre en-tête ne crée pas le corps.
Exemple d’utilisation
nes_ppu_load_palette(stream_palette); // Sixteen BG bytes followed by sixteen sprite bytes.
// Palette reads are immediate; both halves use the same original sample palette.
__ppu_addr(0x3F00);
for(i=0;i<32;i++)if(sample_ppudata!=stream_palette[(u8)(i&15)])failures=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 solution prépare l’écran sans rendu, installe les palettes, efface tuiles et attributs, puis dessine ce test. Un motif bleu de tuiles pleines, demi-barres gauches et triangles commence en (0,16) ; un bloc vert plein commence en (0,96). Chaque région mesure 256×64 pixels, sauf sa dernière case de 8×8 en (248,72) ou (248,152), qui reste noire car le transfert contient 255 octets de tuiles. À y=208, les formes rouges sont un carré de 8×8 en x=16, une barre gauche de 4×8 en x=224 et un triangle de huit lignes en x=240. FAILED CHECKS indique 0. Des tests d’état distincts confirment les deux registres de contrôle, le transfert des 32 octets de palette et l’effacement des 1 024 octets de la table de noms. Les quatre appels déclarés doivent échouer à l’édition de liens.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\ppu_implemented.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\ppu_implemented.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/ppu.h:11
Copy 32 bytes into $3F00..$3F1F with increment one; preserve PPUCTRL. Null is ignored. Hardware palette mirrors apply; source bank must stay mapped.
kitaqfc/lib/ppu.c:48
void nes_ppu_load_palette(unsigned char* pal32)
{
u8 saved_ctrl;
if (pal32 == 0) return;
saved_ctrl=__ppu_ctrl_get();
__ppu_ctrl_set((u8)(saved_ctrl & 0xFB));
__palette_bg_load(pal32);
__palette_sp_load(pal32 + 16);
__ppu_ctrl_set(saved_ctrl);
}nes_ppu_screen_off
nes_ppu_screen_off est déclarée dans ppu.h, mais son corps n’est pas fourni : un appel direct échoue à l’édition de liens. L’exemple exécutable arrête le rendu avec __ppu_off(), qui écrit zéro dans PPUMASK et sa copie logicielle. NMI n’est pas désactivée ; l’exemple écrit séparément zéro dans PPUCTRL pour préparer l’écran en bloc.
Syntaxe
void nes_ppu_screen_off(void);Valeur renvoyée
Type de retour déclaré : void. Aucune implémentation n’est liée ; il n’existe donc pas de comportement de retour exécutable pour ce nom.
Conditions et limites
L’exemple présente des solutions implémentées, pas un appel réussi à la déclaration. La vérification comprend l’échec attendu pour symbole non résolu de chaque nom absent et des contrôles distincts des solutions dans l’émulateur. Pour appeler le nom déclaré, fournissez une implémentation compatible ; inclure un autre en-tête ne crée pas le corps.
Exemple d’utilisation
nes_ppu_screen_off();__ppu_ctrl_set(0); // Disable NMI during this bulk preparation.Cet extrait montre l’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 solution prépare l’écran sans rendu, installe les palettes, efface tuiles et attributs, puis dessine ce test. Un motif bleu de tuiles pleines, demi-barres gauches et triangles commence en (0,16) ; un bloc vert plein commence en (0,96). Chaque région mesure 256×64 pixels, sauf sa dernière case de 8×8 en (248,72) ou (248,152), qui reste noire car le transfert contient 255 octets de tuiles. À y=208, les formes rouges sont un carré de 8×8 en x=16, une barre gauche de 4×8 en x=224 et un triangle de huit lignes en x=240. FAILED CHECKS indique 0. Des tests d’état distincts confirment les deux registres de contrôle, le transfert des 32 octets de palette et l’effacement des 1 024 octets de la table de noms. Les quatre appels déclarés doivent échouer à l’édition de liens.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\ppu_implemented.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\ppu_implemented.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/ppu.h:6
Link ppu.c. Bulk palette/nametable transfers require rendering to be disabled. Disable background and sprite rendering, preserving other PPUMASK bits.
kitaqfc/lib/ppu.c:36
void nes_ppu_screen_off(void) { __ppu_mask_set((u8)(__ppu_mask_get() & 0xE7)); }nes_ppu_screen_on
nes_ppu_screen_on(ctrl, mask) est une déclaration sans implémentation ; elle ne peut pas activer l’écran. L’exemple fonctionnel rétablit le défilement, puis appelle __ppu_ctrl_set(0x80) et __ppu_mask_set(0x0A). NMI et le fond sont activés, y compris les huit pixels du bord gauche, sans sprites. Choisissez les valeurs de registre adaptées au jeu.
Syntaxe
void nes_ppu_screen_on(unsigned char ctrl, unsigned char mask);Paramètres
ctrl / maskLa déclaration donne à
ctrletmaskdes types non signés sur huit bits. Aucun corps ne définit leur comportement à l’exécution. La solution fonctionnelle écrit PPUCTRL et PPUMASK par deux appels intrinsèques distincts.
Valeur renvoyée
Type de retour déclaré : void. Aucune implémentation n’est liée ; il n’existe donc pas de comportement de retour exécutable pour ce nom.
Conditions et limites
L’exemple présente des solutions implémentées, pas un appel réussi à la déclaration. La vérification comprend l’échec attendu pour symbole non résolu de chaque nom absent et des contrôles distincts des solutions dans l’émulateur. Pour appeler le nom déclaré, fournissez une implémentation compatible ; inclure un autre en-tête ne crée pas le corps.
Exemple d’utilisation
nes_ppu_screen_on(0x80,0x0A);
// NMI and background rendering are now enabled, with left-edge background visible.Cet extrait montre l’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 solution prépare l’écran sans rendu, installe les palettes, efface tuiles et attributs, puis dessine ce test. Un motif bleu de tuiles pleines, demi-barres gauches et triangles commence en (0,16) ; un bloc vert plein commence en (0,96). Chaque région mesure 256×64 pixels, sauf sa dernière case de 8×8 en (248,72) ou (248,152), qui reste noire car le transfert contient 255 octets de tuiles. À y=208, les formes rouges sont un carré de 8×8 en x=16, une barre gauche de 4×8 en x=224 et un triangle de huit lignes en x=240. FAILED CHECKS indique 0. Des tests d’état distincts confirment les deux registres de contrôle, le transfert des 32 octets de palette et l’effacement des 1 024 octets de la table de noms. Les quatre appels déclarés doivent échouer à l’édition de liens.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\ppu_implemented.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\ppu_implemented.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/ppu.h:8
Set scroll to (0,0), then apply the requested PPUCTRL and PPUMASK values.
kitaqfc/lib/ppu.c:39
void nes_ppu_screen_on(unsigned char ctrl, unsigned char mask)
{
__ppu_read_status();
__scroll_set(0,0);
__ppu_ctrl_set(ctrl);
__ppu_mask_set(mask);
}nes_ppu_seek_bytes
Lit PPUSTATUS pour réinitialiser le verrou d’adresse partagé du PPU, puis définit l’adresse avec deux octets distincts, hi et lo. Cette forme est utile si le jeu stocke déjà l’adresse sur deux octets séparés.
Syntaxe
void nes_ppu_seek_bytes(unsigned char hi, unsigned char lo);Paramètres
hi / lohietlosont les octets de poids fort et faible d’une adresse PPU : par exemple,0x23, 0x42désigne0x2342. Ce ne sont pas des coordonnées de tuiles. Les règles habituelles de masquage et de miroir des adresses PPU s’appliquent.
Valeur renvoyée
Aucune (void).
Conditions et limites
Incluez ou compilez ppu.c une seule fois, sans runtime.c. Avant ses fonctions à deux octets d’adresse, appelez __ppu_read_status() pour réinitialiser le verrou partagé. ppu.h ne déclare pas ces fonctions : ses quatre déclarations relatives à l’écran, à la palette et à la table de noms n’ont pas d’implémentation dans cette distribution. Les fonctions présentées ici proviennent de ppu.c ; inclure uniquement ppu.h ne suffit pas.
L’accès direct à la PPU exige de désactiver le rendu ou de terminer toute l’opération dans un intervalle VBlank sûr. Ces fonctions n’attendent pas, ne mettent rien en file, ne bloquent pas NMI et ne rétablissent pas le défilement. Empêchez une interruption de modifier le verrou ou l’adresse partagés pendant l’appel. Le bit 2 de PPUCTRL choisit un pas de destination de 1 ou 32 par octet. La PPU gère les miroirs et le bouclage des adresses ; la CHR-ROM n’est pas inscriptible. Rétablissez le défilement voulu avant le rendu.
Exemple d’utilisation
nes_ppu_seek_bytes(0x23,0x42);
PPUDATA=1; // Red 8x8 marker at pixel (16,208).Cet extrait montre l’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 séparé à deux octets d’adresse montre la préparation explicite du verrou et les nombres sur huit bits. Les régions bleue et verte utilisent chacune 255 octets : les dernières cases de 8×8, en (248,72) et (248,152), restent noires. Les repères rouges ont les mêmes positions et formes que dans l’exemple du runtime. FAILED CHECKS indique 0 ; ce programme ne teste pas les fonctions d’attente du runtime.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\ppu_address_pair.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\ppu_address_pair.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/ppu.c:8
Reset the shared scroll/address latch before writing the address byte pair.
kitaqfc/lib/ppu.c:8
void nes_ppu_seek_bytes(unsigned char hi, unsigned char lo)
{
__ppu_read_status();
kq_ppu_addr_register = hi;
kq_ppu_addr_register = lo;
}nes_ppu_write_bytes
Écrit directement dans PPUDATA count octets consécutifs de la source après avoir défini l’adresse avec hi et lo. Cette fonction de ppu.c accepte un nombre sur huit bits ; l’appelant doit réinitialiser le verrou d’adresse. Le transfert se termine avant le retour, sans file d’attente.
Syntaxe
void nes_ppu_write_bytes(unsigned char hi, unsigned char lo, const unsigned char* src, unsigned char count);Paramètres
hi / lohietlosont les octets de poids fort et faible d’une adresse PPU : par exemple,0x23, 0x42désigne0x2342. Ce ne sont pas des coordonnées de tuiles. Les règles habituelles de masquage et de miroir des adresses PPU s’appliquent.srcPointeur CPU vers au moins le nombre demandé d’octets lisibles. Maintenez la source accessible et stable jusqu’au retour de ce transfert synchrone. Aucun changement de banque, stockage du pointeur dans une file ou contrôle de longueur n’est effectué ; un nombre nul ne déréférence pas le pointeur.
countNombre d’octets de
0..255(huit bits non signés). Zéro définit l’adresse sans écrire de données. Le verrou partagé n’est pas réinitialisé, même pour zéro ; préparez-le avant l’appel.
Valeur renvoyée
Aucune (void).
Conditions et limites
Incluez ou compilez ppu.c une seule fois, sans runtime.c. Avant ses fonctions à deux octets d’adresse, appelez __ppu_read_status() pour réinitialiser le verrou partagé. ppu.h ne déclare pas ces fonctions : ses quatre déclarations relatives à l’écran, à la palette et à la table de noms n’ont pas d’implémentation dans cette distribution. Les fonctions présentées ici proviennent de ppu.c ; inclure uniquement ppu.h ne suffit pas.
L’accès direct à la PPU exige de désactiver le rendu ou de terminer toute l’opération dans un intervalle VBlank sûr. Ces fonctions n’attendent pas, ne mettent rien en file, ne bloquent pas NMI et ne rétablissent pas le défilement. Empêchez une interruption de modifier le verrou ou l’adresse partagés pendant l’appel. Le bit 2 de PPUCTRL choisit un pas de destination de 1 ou 32 par octet. La PPU gère les miroirs et le bouclage des adresses ; la CHR-ROM n’est pas inscriptible. Rétablissez le défilement voulu avant le rendu.
Exemple d’utilisation
__ppu_read_status();nes_ppu_write_bytes(0x20,0x40,source_bytes,255);
source_bytes[0]=3; // The completed transfer retains tile 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 séparé à deux octets d’adresse montre la préparation explicite du verrou et les nombres sur huit bits. Les régions bleue et verte utilisent chacune 255 octets : les dernières cases de 8×8, en (248,72) et (248,152), restent noires. Les repères rouges ont les mêmes positions et formes que dans l’exemple du runtime. FAILED CHECKS indique 0 ; ce programme ne teste pas les fonctions d’attente du runtime.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\ppu_address_pair.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\ppu_address_pair.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/ppu.c:18
Set the address and write count bytes directly through PPUDATA. The current PPUCTRL increment mode determines how the destination advances. count is 0..255; zero still changes PPU address/latch state. No bank switch or payload copy is performed.
kitaqfc/lib/ppu.c:18
void nes_ppu_write_bytes(unsigned char hi, unsigned char lo, const unsigned char* src, unsigned char count)
{
unsigned char i;
nes_ppu_seek_bytes(hi, lo);
for (i = 0; i != count; ++i)
kq_ppu_data_register = src[i];
}runtime.h — Fonctions C pour NMI, OAM et transferts PPU
Utilisez les déclarations de runtime.h et incluez ou compilez runtime.c exactement une fois. Outre cette file, il fournit __nes_nmi, le compteur de trames, les fonctions PPU directes et le tampon OAM de la page 02. Coordonnez son gestionnaire NMI avec votre programme ; une déclaration seule ne lie pas l’implémentation.
Il s’agit d’une file distincte de 192 octets de runtime.c, aux adresses CPU 0x0300–0x03BF. Un enregistrement de données coûte 3+len octets ; un remplissage en coûte quatre. nes_vram_queue_used mesure les octets encodés, pas les écritures PPU en attente ni la VRAM libre. La file intrinsèque __vramq_* a un autre format ; ces fonctions ne l’effacent, ne la consultent et ne l’exécutent pas.
Séparez la préparation et l’exécution des lots ; aucun verrou ni double tampon n’est fourni. Pour une préparation déterministe, désactivez NMI pendant les ajouts, puis exécutez avec le rendu coupé, ou réactivez NMI pour un lot tenant dans VBlank. runtime.c vide automatiquement une file non vide depuis __nes_nmi, sans validation préalable. Le vidage ne limite pas le temps, ne fractionne pas le travail et ne restaure pas le défilement. La place dans la file ne garantit pas de tenir dans VBlank.
nes_ppu_seek
Définit l’adresse PPU des prochains accès à PPUDATA. Dans runtime.c, nes_ppu_seek(ppu_addr) lit PPUSTATUS pour réinitialiser le verrou d’écriture partagé, puis écrit les octets de poids fort et faible. L’autre implémentation, nes_ppu_seek(hi, lo) dans ppu.c, ne réinitialise pas ce verrou. Ces fonctions portent le même nom, mais diffèrent par leurs paramètres et leur comportement : choisissez une seule implémentation.
Syntaxe
void nes_ppu_seek(unsigned short ppu_addr);Paramètres
ppu_addrAdresse PPU en octets (
0x0000–0x3FFF), et non pointeur CPU. La destination doit être inscriptible : modifier les motifs exige de la CHR RAM, pas de la CHR ROM. Le mappage et le mirroring PPU s’appliquent. Pour les copies et remplissages contigus, choisissez l’incrément 1 dans PPUCTRL. Exécutez à un instant sûr, puis rétablissez le défilement voulu ; l’exécuteur écrit PPUADDR et PPUDATA sans restaurer le défilement.
Valeur renvoyée
Aucune (void).
Conditions et limites
Utilisez les déclarations de runtime.h et incluez ou compilez runtime.c exactement une fois. Outre cette file, il fournit __nes_nmi, le compteur de trames, les fonctions PPU directes et le tampon OAM de la page 02. Coordonnez son gestionnaire NMI avec votre programme ; une déclaration seule ne lie pas l’implémentation.
L’accès direct à la PPU exige de désactiver le rendu ou de terminer toute l’opération dans un intervalle VBlank sûr. Ces fonctions n’attendent pas, ne mettent rien en file, ne bloquent pas NMI et ne rétablissent pas le défilement. Empêchez une interruption de modifier le verrou ou l’adresse partagés pendant l’appel. Le bit 2 de PPUCTRL choisit un pas de destination de 1 ou 32 par octet. La PPU gère les miroirs et le bouclage des adresses ; la CHR-ROM n’est pas inscriptible. Rétablissez le défilement voulu avant le rendu.
Exemple d’utilisation
PPUADDR=0x21; // Deliberately leave the shared address latch half-written.
nes_ppu_seek(0x2342); // This runtime function resets the latch itself.
PPUDATA=1; // Red 8x8 marker at pixel (16,208).Cet extrait montre l’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 du runtime présente le transfert direct et les deux attentes. En (0,16), un motif bleu alterne tuiles pleines, barres occupant la moitié gauche et triangles ; en (0,96), un bloc vert est plein. Chaque bloc mesure 256×64 pixels et provient de 256 octets de tuiles. La première tuile bleue reste pleine après modification de la source. À y=208, les repères rouges en x=16, 224 et 240 illustrent l’adresse, l’écriture de longueur nulle et le remplissage de longueur nulle : carré de 8×8, barre gauche de 4×8 et triangle de huit lignes. Les deux attentes indiquent 1 et FAILED CHECKS indique 0.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\runtime_ppu.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\runtime_ppu.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/runtime.h:28
Reset the PPU address latch with a status read, then write the high/low address bytes.
kitaqfc/lib/runtime.c:207
void nes_ppu_seek(unsigned short ppu_addr)
{
unsigned char latch;
latch = PPUSTATUS;
PPUADDR = (unsigned char)(ppu_addr >> 8);
PPUADDR = (unsigned char)ppu_addr;
latch = latch;
}nes_ppu_stream_fill
Définit ppu_addr, puis écrit le même octet value dans PPUDATA exactement len fois. Ce remplissage direct est terminé au retour. Il ne tient compte ni des dimensions des tuiles, ni des attributs, ni des limites d’un rectangle.
Syntaxe
void nes_ppu_stream_fill(unsigned short ppu_addr, unsigned char value, unsigned short len);Paramètres
ppu_addrAdresse PPU en octets (
0x0000–0x3FFF), et non pointeur CPU. La destination doit être inscriptible : modifier les motifs exige de la CHR RAM, pas de la CHR ROM. Le mappage et le mirroring PPU s’appliquent. Pour les copies et remplissages contigus, choisissez l’incrément 1 dans PPUCTRL. Exécutez à un instant sûr, puis rétablissez le défilement voulu ; l’exécuteur écrit PPUADDR et PPUDATA sans restaurer le défilement.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, de
0..65535(entier non signé sur 16 bits). Zéro définit tout de même l’adresse PPU et réinitialise le verrou, sans écrire dans PPUDATA. Aucune vérification de capacité ni division du transfert n’est effectuée ; un grand nombre peut boucler dans l’espace d’adressage PPU.
Valeur renvoyée
Aucune (void).
Conditions et limites
Utilisez les déclarations de runtime.h et incluez ou compilez runtime.c exactement une fois. Outre cette file, il fournit __nes_nmi, le compteur de trames, les fonctions PPU directes et le tampon OAM de la page 02. Coordonnez son gestionnaire NMI avec votre programme ; une déclaration seule ne lie pas l’implémentation.
L’accès direct à la PPU exige de désactiver le rendu ou de terminer toute l’opération dans un intervalle VBlank sûr. Ces fonctions n’attendent pas, ne mettent rien en file, ne bloquent pas NMI et ne rétablissent pas le défilement. Empêchez une interruption de modifier le verrou ou l’adresse partagés pendant l’appel. Le bit 2 de PPUCTRL choisit un pas de destination de 1 ou 32 par octet. La PPU gère les miroirs et le bouclage des adresses ; la CHR-ROM n’est pas inscriptible. Rétablissez le défilement voulu avant le rendu.
Exemple d’utilisation
nes_ppu_stream_fill(0x2180,1,256); // Eight complete rows of solid green tiles.Cet extrait montre l’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 du runtime présente le transfert direct et les deux attentes. En (0,16), un motif bleu alterne tuiles pleines, barres occupant la moitié gauche et triangles ; en (0,96), un bloc vert est plein. Chaque bloc mesure 256×64 pixels et provient de 256 octets de tuiles. La première tuile bleue reste pleine après modification de la source. À y=208, les repères rouges en x=16, 224 et 240 illustrent l’adresse, l’écriture de longueur nulle et le remplissage de longueur nulle : carré de 8×8, barre gauche de 4×8 et triangle de huit lignes. Les deux attentes indiquent 1 et FAILED CHECKS indique 0.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\runtime_ppu.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\runtime_ppu.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/runtime.h:34
Write value repeatedly through PPUDATA, using the current PPU address increment mode. This routine does not wait for VBlank or disable rendering.
kitaqfc/lib/runtime.c:232
void nes_ppu_stream_fill(unsigned short ppu_addr, unsigned char value, unsigned short len)
{
nes_ppu_seek(ppu_addr);
while (len != 0)
{
PPUDATA = value;
len = len - 1;
}
}nes_ppu_stream_write
Écrit directement dans PPUDATA len octets consécutifs de la source, à partir de ppu_addr. L’adresse est définie une seule fois et la copie locale du pointeur avance après chaque écriture. Le transfert est terminé au retour ; modifier ensuite la source ne change pas la VRAM. Le pointeur de l’appelant reste inchangé.
Syntaxe
void nes_ppu_stream_write(unsigned short ppu_addr, unsigned char* src, unsigned short len);Paramètres
ppu_addrAdresse PPU en octets (
0x0000–0x3FFF), et non pointeur CPU. La destination doit être inscriptible : modifier les motifs exige de la CHR RAM, pas de la CHR ROM. Le mappage et le mirroring PPU s’appliquent. Pour les copies et remplissages contigus, choisissez l’incrément 1 dans PPUCTRL. Exécutez à un instant sûr, puis rétablissez le défilement voulu ; l’exécuteur écrit PPUADDR et PPUDATA sans restaurer le défilement.srcPointeur CPU vers au moins le nombre demandé d’octets lisibles. Maintenez la source accessible et stable jusqu’au retour de ce transfert synchrone. Aucun changement de banque, stockage du pointeur dans une file ou contrôle de longueur n’est effectué ; un nombre nul ne déréférence pas le pointeur.
lenNombre d’octets, de
0..65535(entier non signé sur 16 bits). Zéro définit tout de même l’adresse PPU et réinitialise le verrou, sans écrire dans PPUDATA. Aucune vérification de capacité ni division du transfert n’est effectuée ; un grand nombre peut boucler dans l’espace d’adressage PPU.
Valeur renvoyée
Aucune (void).
Conditions et limites
Utilisez les déclarations de runtime.h et incluez ou compilez runtime.c exactement une fois. Outre cette file, il fournit __nes_nmi, le compteur de trames, les fonctions PPU directes et le tampon OAM de la page 02. Coordonnez son gestionnaire NMI avec votre programme ; une déclaration seule ne lie pas l’implémentation.
L’accès direct à la PPU exige de désactiver le rendu ou de terminer toute l’opération dans un intervalle VBlank sûr. Ces fonctions n’attendent pas, ne mettent rien en file, ne bloquent pas NMI et ne rétablissent pas le défilement. Empêchez une interruption de modifier le verrou ou l’adresse partagés pendant l’appel. Le bit 2 de PPUCTRL choisit un pas de destination de 1 ou 32 par octet. La PPU gère les miroirs et le bouclage des adresses ; la CHR-ROM n’est pas inscriptible. Rétablissez le défilement voulu avant le rendu.
Exemple d’utilisation
// Rendering/NMI are off; PPUCTRL increment is 1. Transfer 256 bytes now.
nes_ppu_stream_write(0x2040,source_bytes,256);
source_bytes[0]=3; // VRAM already holds tile 1 at the first blue cell.Cet extrait montre l’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 du runtime présente le transfert direct et les deux attentes. En (0,16), un motif bleu alterne tuiles pleines, barres occupant la moitié gauche et triangles ; en (0,96), un bloc vert est plein. Chaque bloc mesure 256×64 pixels et provient de 256 octets de tuiles. La première tuile bleue reste pleine après modification de la source. À y=208, les repères rouges en x=16, 224 et 240 illustrent l’adresse, l’écriture de longueur nulle et le remplissage de longueur nulle : carré de 8×8, barre gauche de 4×8 et triangle de huit lignes. Les deux attentes indiquent 1 et FAILED CHECKS indique 0.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\runtime_ppu.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\runtime_ppu.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/runtime.h:31
Write len source bytes directly through PPUDATA. Call only during an appropriate PPU access period; the address increment mode comes from the current PPUCTRL.
kitaqfc/lib/runtime.c:219
void nes_ppu_stream_write(unsigned short ppu_addr, unsigned char* src, unsigned short len)
{
nes_ppu_seek(ppu_addr);
while (len != 0)
{
PPUDATA = *src;
src = src + 1;
len = len - 1;
}
}nes_vblank_wait
Interroge le bit 7 de PPUSTATUS pour attendre une nouvelle indication de VBlank, après avoir consommé toute indication déjà présente. Fonctionne avec NMI désactivée, sans exécuter la file ni modifier le compteur NMI du runtime. Chaque lecture efface le drapeau VBlank et réinitialise le verrou partagé de défilement et d’adresse. Utilisez cette attente séparément de l’ordonnancement par NMI : les lectures peuvent en modifier le déclenchement. Aucun délai maximal, transfert ou rétablissement du défilement n’est prévu.
Syntaxe
void nes_vblank_wait(void);Valeur renvoyée
Aucune (void).
Conditions et limites
Utilisez les déclarations de runtime.h et incluez ou compilez runtime.c exactement une fois. Outre cette file, il fournit __nes_nmi, le compteur de trames, les fonctions PPU directes et le tampon OAM de la page 02. Coordonnez son gestionnaire NMI avec votre programme ; une déclaration seule ne lie pas l’implémentation.
Exemple d’utilisation
// With NMI disabled, poll a new PPU VBlank flag. No queued work is flushed.
nes_vblank_wait();blank_seen=1;
if((PPUSTATUS&0x80)!=0)failures++; // The wait's status read cleared the flag.Cet extrait montre l’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 du runtime présente le transfert direct et les deux attentes. En (0,16), un motif bleu alterne tuiles pleines, barres occupant la moitié gauche et triangles ; en (0,96), un bloc vert est plein. Chaque bloc mesure 256×64 pixels et provient de 256 octets de tuiles. La première tuile bleue reste pleine après modification de la source. À y=208, les repères rouges en x=16, 224 et 240 illustrent l’adresse, l’écriture de longueur nulle et le remplissage de longueur nulle : carré de 8×8, barre gauche de 4×8 et triangle de huit lignes. Les deux attentes indiquent 1 et FAILED CHECKS indique 0.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\runtime_ppu.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\runtime_ppu.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/runtime.h:26
Wait for the current VBlank to end, then for the next one to begin. Each PPUSTATUS read has hardware side effects, including clearing the VBlank flag.
kitaqfc/lib/runtime.c:196
void nes_vblank_wait(void)
{
while ((PPUSTATUS & 0x80) != 0)
{
}
while ((PPUSTATUS & 0x80) == 0)
{
}
}nes_vram_queue_clear
Abandonne tous les enregistrements en attente dans la file C et remet nes_vram_queue_used et nes_vram_queue_overflow à zéro. Aucune écriture PPU n’a lieu ; les octets du tampon ne sont pas effacés. La file intrinsèque du compilateur n’est pas affectée.
Syntaxe
void nes_vram_queue_clear(void);Valeur renvoyée
Aucune (void).
Conditions et limites
Il s’agit d’une file distincte de 192 octets de runtime.c, aux adresses CPU 0x0300–0x03BF. Un enregistrement de données coûte 3+len octets ; un remplissage en coûte quatre. nes_vram_queue_used mesure les octets encodés, pas les écritures PPU en attente ni la VRAM libre. La file intrinsèque __vramq_* a un autre format ; ces fonctions ne l’effacent, ne la consultent et ne l’exécutent pas.
Utilisez les déclarations de runtime.h et incluez ou compilez runtime.c exactement une fois. Outre cette file, il fournit __nes_nmi, le compteur de trames, les fonctions PPU directes et le tampon OAM de la page 02. Coordonnez son gestionnaire NMI avec votre programme ; une déclaration seule ne lie pas l’implémentation.
Séparez la préparation et l’exécution des lots ; aucun verrou ni double tampon n’est fourni. Pour une préparation déterministe, désactivez NMI pendant les ajouts, puis exécutez avec le rendu coupé, ou réactivez NMI pour un lot tenant dans VBlank. runtime.c vide automatiquement une file non vide depuis __nes_nmi, sans validation préalable. Le vidage ne limite pas le temps, ne fractionne pas le travail et ne restaure pas le défilement. La place dans la file ne garantit pas de tenir dans VBlank.
Exemple d’utilisation
nes_vram_queue_clear(); // Discard all records AND clear the overflow latch.
if(nes_vram_queue_used!=0 || nes_vram_queue_overflow!=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
L’exemple remplit d’abord les 192 octets et provoque le refus d’un enregistrement supplémentaire. Il efface ce lot, vérifie le refus d’une longueur de 128, puis ajoute cinq enregistrements : 145 octets pour 255 écritures PPU. Il doit afficher CAPACITY 192, ENCODED BYTES 145, AFTER FLUSH 000, REJECTED LENGTH 001, OVERFLOW SEEN 001 et FAILED CHECKS 000. Les indicateurs de refus conservent les observations d’étapes précédentes du programme, pas l’état final du drapeau.
Les copies bleues commencent à (0,16), le remplissage vert à (0,64). Chaque zone contient 127 tuiles : trois lignes complètes et 31 tuiles sur la quatrième ; la dernière case 8×8 reste noire. La séquence bleue alterne tuiles pleines, de demi-largeur et triangulaires ; la première reste pleine malgré la modification de la source. À y=112, le carré rouge en x=16 résiste aux enregistrements vides, la demi-tuile rouge en x=224 prouve le vidage NMI et la case annulée en x=248 reste noire. La vérification compare 18 432 pixels et contrôle l’absence d’écritures VRAM pendant le rendu actif. Le matériel physique n’a pas été testé.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\runtime_queue.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\runtime_queue.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/runtime.h:40
Discard pending VRAM commands and clear the overflow latch; no PPU writes occur.
kitaqfc/lib/runtime.c:31
void nes_vram_queue_clear(void)
{
nes_vram_queue_used = 0;
nes_vram_queue_overflow = 0;
}nes_vram_queue_nmi_flush
Exécute dans l’ordre tous les enregistrements en attente de la file C, sans drapeau de validation. Positionne l’adresse PPU pour chacun, puis transfère ses données stockées ou répète son octet de remplissage. À la fin, remet nes_vram_queue_used à zéro en conservant le drapeau de dépassement. Une file vide n’accède pas à la PPU.
Syntaxe
void nes_vram_queue_nmi_flush(void);Valeur renvoyée
Aucune (void).
Conditions et limites
Il s’agit d’une file distincte de 192 octets de runtime.c, aux adresses CPU 0x0300–0x03BF. Un enregistrement de données coûte 3+len octets ; un remplissage en coûte quatre. nes_vram_queue_used mesure les octets encodés, pas les écritures PPU en attente ni la VRAM libre. La file intrinsèque __vramq_* a un autre format ; ces fonctions ne l’effacent, ne la consultent et ne l’exécutent pas.
Utilisez les déclarations de runtime.h et incluez ou compilez runtime.c exactement une fois. Outre cette file, il fournit __nes_nmi, le compteur de trames, les fonctions PPU directes et le tampon OAM de la page 02. Coordonnez son gestionnaire NMI avec votre programme ; une déclaration seule ne lie pas l’implémentation.
Séparez la préparation et l’exécution des lots ; aucun verrou ni double tampon n’est fourni. Pour une préparation déterministe, désactivez NMI pendant les ajouts, puis exécutez avec le rendu coupé, ou réactivez NMI pour un lot tenant dans VBlank. runtime.c vide automatiquement une file non vide depuis __nes_nmi, sans validation préalable. Le vidage ne limite pas le temps, ne fractionne pas le travail et ne restaure pas le défilement. La place dans la file ne garantit pas de tenir dans VBlank.
Adresse PPU en octets (0x0000–0x3FFF), et non pointeur CPU. La destination doit être inscriptible : modifier les motifs exige de la CHR RAM, pas de la CHR ROM. Le mappage et le mirroring PPU s’appliquent. Pour les copies et remplissages contigus, choisissez l’incrément 1 dans PPUCTRL. Exécutez à un instant sûr, puis rétablissez le défilement voulu ; l’exécuteur écrit PPUADDR et PPUDATA sans restaurer le défilement.
Exemple d’utilisation
// Rendering and NMI are disabled; PPUCTRL selects increment 1.
nes_vram_queue_nmi_flush(); // No commit flag: consume all queued records now.
after_flush=nes_vram_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
L’exemple remplit d’abord les 192 octets et provoque le refus d’un enregistrement supplémentaire. Il efface ce lot, vérifie le refus d’une longueur de 128, puis ajoute cinq enregistrements : 145 octets pour 255 écritures PPU. Il doit afficher CAPACITY 192, ENCODED BYTES 145, AFTER FLUSH 000, REJECTED LENGTH 001, OVERFLOW SEEN 001 et FAILED CHECKS 000. Les indicateurs de refus conservent les observations d’étapes précédentes du programme, pas l’état final du drapeau.
Les copies bleues commencent à (0,16), le remplissage vert à (0,64). Chaque zone contient 127 tuiles : trois lignes complètes et 31 tuiles sur la quatrième ; la dernière case 8×8 reste noire. La séquence bleue alterne tuiles pleines, de demi-largeur et triangulaires ; la première reste pleine malgré la modification de la source. À y=112, le carré rouge en x=16 résiste aux enregistrements vides, la demi-tuile rouge en x=224 prouve le vidage NMI et la case annulée en x=248 reste noire. La vérification compare 18 432 pixels et contrôle l’absence d’écritures VRAM pendant le rendu actif. Le matériel physique n’a pas été testé.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\runtime_queue.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\runtime_queue.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/runtime.h:51
Consume complete records in order during a safe PPU access period. Reading PPUSTATUS resets the shared address latch before each address pair. The caller is responsible for ensuring the transfer fits its NMI/VBlank time budget.
kitaqfc/lib/runtime.c:127
void nes_vram_queue_nmi_flush(void)
{
unsigned char i;
unsigned char cmd;
unsigned char len;
unsigned char data_index;
unsigned char latch;
i = 0;
while (i != nes_vram_queue_used)
{
latch = PPUSTATUS;
PPUADDR = nes_vram_queue_data[i];
PPUADDR = nes_vram_queue_data[(unsigned char)(i + 1)];
cmd = nes_vram_queue_data[(unsigned char)(i + 2)];
if ((cmd & 0x80) != 0)
{
len = (unsigned char)(cmd & 0x7F);
data_index = nes_vram_queue_data[(unsigned char)(i + 3)];
while (len != 0)
{
PPUDATA = data_index;
len = len - 1;
}
i = (unsigned char)(i + 4);
}
else
{
len = cmd;
data_index = (unsigned char)(i + 3);
while (len != 0)
{
PPUDATA = nes_vram_queue_data[data_index];
data_index = data_index + 1;
len = len - 1;
}
i = data_index;
}
latch = latch;
}
nes_vram_queue_used = 0;
}nes_vram_queue_try_fill
Ajoute à la file C un enregistrement de remplissage de quatre octets. À l’exécution, écrit value dans PPUDATA len fois. La valeur est stockée immédiatement ; modifier ensuite la variable appelante ne change pas le remplissage. Il s’agit de répéter un octet, pas un motif de tuile.
Syntaxe
unsigned char nes_vram_queue_try_fill(unsigned short ppu_addr, unsigned char value, unsigned char len);Paramètres
ppu_addrAdresse PPU en octets (
0x0000–0x3FFF), et non pointeur CPU. La destination doit être inscriptible : modifier les motifs exige de la CHR RAM, pas de la CHR ROM. Le mappage et le mirroring PPU s’appliquent. Pour les copies et remplissages contigus, choisissez l’incrément 1 dans PPUCTRL. Exécutez à un instant sûr, puis rétablissez le défilement voulu ; l’exécuteur écrit PPUADDR et PPUDATA sans restaurer le défilement.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 PPU, de 0 à 127. Le bit 7 de la longueur identifie les remplissages ; 128–255 sont donc refusés. Une écriture de longueur nulle occupe trois octets de file ; un remplissage vide en occupe quatre. Tous deux positionnent l’adresse PPU lors du vidage, sans écrire dans PPUDATA.
Valeur renvoyée
Renvoie 1 si l’enregistrement entier est accepté, ou 0 si la longueur est invalide ou l’espace insuffisant. Un refus met nes_vram_queue_overflow à 1 sans modifier les enregistrements existants ni la longueur utilisée. Le drapeau reste actif jusqu’à son effacement, mais n’empêche pas un ajout ultérieur qui tient dans le tampon. Vérifiez chaque retour.
Conditions et limites
Il s’agit d’une file distincte de 192 octets de runtime.c, aux adresses CPU 0x0300–0x03BF. Un enregistrement de données coûte 3+len octets ; un remplissage en coûte quatre. nes_vram_queue_used mesure les octets encodés, pas les écritures PPU en attente ni la VRAM libre. La file intrinsèque __vramq_* a un autre format ; ces fonctions ne l’effacent, ne la consultent et ne l’exécutent pas.
Utilisez les déclarations de runtime.h et incluez ou compilez runtime.c exactement une fois. Outre cette file, il fournit __nes_nmi, le compteur de trames, les fonctions PPU directes et le tampon OAM de la page 02. Coordonnez son gestionnaire NMI avec votre programme ; une déclaration seule ne lie pas l’implémentation.
Séparez la préparation et l’exécution des lots ; aucun verrou ni double tampon n’est fourni. Pour une préparation déterministe, désactivez NMI pendant les ajouts, puis exécutez avec le rendu coupé, ou réactivez NMI pour un lot tenant dans VBlank. runtime.c vide automatiquement une file non vide depuis __nes_nmi, sans validation préalable. Le vidage ne limite pas le temps, ne fractionne pas le travail et ne restaure pas le défilement. La place dans la file ne garantit pas de tenir dans VBlank.
Exemple d’utilisation
if(nes_vram_queue_try_fill(0x2100,fill_value,127)!=1)failures++;
fill_value=3; // The queued fill remains the solid tile 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 remplit d’abord les 192 octets et provoque le refus d’un enregistrement supplémentaire. Il efface ce lot, vérifie le refus d’une longueur de 128, puis ajoute cinq enregistrements : 145 octets pour 255 écritures PPU. Il doit afficher CAPACITY 192, ENCODED BYTES 145, AFTER FLUSH 000, REJECTED LENGTH 001, OVERFLOW SEEN 001 et FAILED CHECKS 000. Les indicateurs de refus conservent les observations d’étapes précédentes du programme, pas l’état final du drapeau.
Les copies bleues commencent à (0,16), le remplissage vert à (0,64). Chaque zone contient 127 tuiles : trois lignes complètes et 31 tuiles sur la quatrième ; la dernière case 8×8 reste noire. La séquence bleue alterne tuiles pleines, de demi-largeur et triangulaires ; la première reste pleine malgré la modification de la source. À y=112, le carré rouge en x=16 résiste aux enregistrements vides, la demi-tuile rouge en x=224 prouve le vidage NMI et la case annulée en x=248 reste noire. La vérification compare 18 432 pixels et contrôle l’absence d’écritures VRAM pendant le rendu actif. Le matériel physique n’a pas été testé.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\runtime_queue.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\runtime_queue.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/runtime.h:47
Queue a four-byte fill record: address high/low, length with bit 7 set, value. Reject lengths above 127 and latch overflow on any capacity/format failure.
kitaqfc/lib/runtime.c:90
unsigned char nes_vram_queue_try_fill(unsigned short ppu_addr, unsigned char value, unsigned char len)
{
unsigned char used;
unsigned char need;
used = nes_vram_queue_used;
need = 4;
if ((unsigned char)(used + need) < used)
{
nes_vram_queue_overflow = 1;
return 0;
}
if ((unsigned char)(used + need) > 192)
{
nes_vram_queue_overflow = 1;
return 0;
}
if ((len & 0x80) != 0)
{
nes_vram_queue_overflow = 1;
return 0;
}
nes_vram_queue_data[used] = (unsigned char)(ppu_addr >> 8);
nes_vram_queue_data[(unsigned char)(used + 1)] = (unsigned char)ppu_addr;
nes_vram_queue_data[(unsigned char)(used + 2)] = (unsigned char)(len | 0x80);
nes_vram_queue_data[(unsigned char)(used + 3)] = value;
nes_vram_queue_used = (unsigned char)(used + need);
return 1;
}nes_vram_queue_try_write
Ajoute à la file C un enregistrement contenant les données. Copie les len octets source pendant cet appel, puis publie la nouvelle longueur utilisée. Le transfert PPU a lieu lors du vidage de la file. Modifier ou réutiliser la source après un appel réussi ne change pas les données en attente.
Syntaxe
unsigned char nes_vram_queue_try_write(unsigned short ppu_addr, unsigned char* src, unsigned char len);Paramètres
ppu_addrAdresse PPU en octets (
0x0000–0x3FFF), et non pointeur CPU. La destination doit être inscriptible : modifier les motifs exige de la CHR RAM, pas de la CHR ROM. Le mappage et le mirroring PPU s’appliquent. Pour les copies et remplissages contigus, choisissez l’incrément 1 dans PPUCTRL. Exécutez à un instant sûr, puis rétablissez le défilement voulu ; l’exécuteur écrit PPUADDR et PPUDATA sans restaurer le défilement.srcPointeur vers au moins
lenoctets lisibles dans la mémoire actuellement mappée. La source doit rester valide uniquement pendant cet appel : le contenu est copié et n’est jamais modifié. Une longueur nulle ne lit aucun octet source.lenNombre d’octets PPU, de 0 à 127. Le bit 7 de la longueur identifie les remplissages ; 128–255 sont donc refusés. Une écriture de longueur nulle occupe trois octets de file ; un remplissage vide en occupe quatre. Tous deux positionnent l’adresse PPU lors du vidage, sans écrire dans PPUDATA.
Valeur renvoyée
Renvoie 1 si l’enregistrement entier est accepté, ou 0 si la longueur est invalide ou l’espace insuffisant. Un refus met nes_vram_queue_overflow à 1 sans modifier les enregistrements existants ni la longueur utilisée. Le drapeau reste actif jusqu’à son effacement, mais n’empêche pas un ajout ultérieur qui tient dans le tampon. Vérifiez chaque retour.
Conditions et limites
Il s’agit d’une file distincte de 192 octets de runtime.c, aux adresses CPU 0x0300–0x03BF. Un enregistrement de données coûte 3+len octets ; un remplissage en coûte quatre. nes_vram_queue_used mesure les octets encodés, pas les écritures PPU en attente ni la VRAM libre. La file intrinsèque __vramq_* a un autre format ; ces fonctions ne l’effacent, ne la consultent et ne l’exécutent pas.
Utilisez les déclarations de runtime.h et incluez ou compilez runtime.c exactement une fois. Outre cette file, il fournit __nes_nmi, le compteur de trames, les fonctions PPU directes et le tampon OAM de la page 02. Coordonnez son gestionnaire NMI avec votre programme ; une déclaration seule ne lie pas l’implémentation.
Séparez la préparation et l’exécution des lots ; aucun verrou ni double tampon n’est fourni. Pour une préparation déterministe, désactivez NMI pendant les ajouts, puis exécutez avec le rendu coupé, ou réactivez NMI pour un lot tenant dans VBlank. runtime.c vide automatiquement une file non vide depuis __nes_nmi, sans validation préalable. Le vidage ne limite pas le temps, ne fractionne pas le travail et ne restaure pas le défilement. La place dans la file ne garantit pas de tenir dans VBlank.
Exemple d’utilisation
if(nes_vram_queue_try_write(0x2040,source_bytes,127)!=1)failures++;
source_bytes[0]=3; // The queued first tile stays 1: payload was copied immediately.Cet extrait montre l’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 remplit d’abord les 192 octets et provoque le refus d’un enregistrement supplémentaire. Il efface ce lot, vérifie le refus d’une longueur de 128, puis ajoute cinq enregistrements : 145 octets pour 255 écritures PPU. Il doit afficher CAPACITY 192, ENCODED BYTES 145, AFTER FLUSH 000, REJECTED LENGTH 001, OVERFLOW SEEN 001 et FAILED CHECKS 000. Les indicateurs de refus conservent les observations d’étapes précédentes du programme, pas l’état final du drapeau.
Les copies bleues commencent à (0,16), le remplissage vert à (0,64). Chaque zone contient 127 tuiles : trois lignes complètes et 31 tuiles sur la quatrième ; la dernière case 8×8 reste noire. La séquence bleue alterne tuiles pleines, de demi-largeur et triangulaires ; la première reste pleine malgré la modification de la source. À y=112, le carré rouge en x=16 résiste aux enregistrements vides, la demi-tuile rouge en x=224 prouve le vidage NMI et la case annulée en x=248 reste noire. La vérification compare 18 432 pixels et contrôle l’absence d’écritures VRAM pendant le rendu actif. Le matériel physique n’a pas été testé.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\runtime_queue.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\runtime_queue.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/runtime.h:44
Copy a literal payload into the queue and publish its new used length last. Accept lengths 0..127; reject larger lengths and latch overflow without changing the queue. The caller must ensure queue production cannot race its NMI consumer.
kitaqfc/lib/runtime.c:40
unsigned char nes_vram_queue_try_write(unsigned short ppu_addr, unsigned char* src, unsigned char len)
{
unsigned char used;
unsigned char need;
unsigned char i;
unsigned char dst_index;
// Bit 7 selects a fill record; accepting it here would misdecode a literal
// and lengths 253..255 would also wrap the byte-sized allocation cost.
if ((len & 0x80) != 0)
{
nes_vram_queue_overflow = 1;
return 0;
}
used = nes_vram_queue_used;
// Each literal record costs three header bytes plus len payload bytes.
need = (unsigned char)(len + 3);
if ((unsigned char)(used + need) < used)
{
nes_vram_queue_overflow = 1;
return 0;
}
if ((unsigned char)(used + need) > 192)
{
nes_vram_queue_overflow = 1;
return 0;
}
nes_vram_queue_data[used] = (unsigned char)(ppu_addr >> 8);
nes_vram_queue_data[(unsigned char)(used + 1)] = (unsigned char)ppu_addr;
nes_vram_queue_data[(unsigned char)(used + 2)] = len;
i = 0;
dst_index = (unsigned char)(used + 3);
while (i != len)
{
nes_vram_queue_data[dst_index] = src[i];
dst_index = dst_index + 1;
i = i + 1;
}
nes_vram_queue_used = (unsigned char)(used + need);
return 1;
}nes_wait_nmi
Attend que nes_nmi_counter diffère de la valeur mémorisée à l’entrée. Le gestionnaire __nes_nmi de runtime.c incrémente ce compteur sur huit bits après avoir vidé sa file. La comparaison d’inégalité gère aussi le passage de 255 à 0. Activez NMI et utilisez ce gestionnaire ou une mise à jour équivalente du compteur. Cette boucle n’a pas de délai maximal, n’active pas NMI, ne rétablit pas le défilement et ne garantit pas une durée exacte d’une trame.
Syntaxe
void nes_wait_nmi(void);Valeur renvoyée
Aucune (void).
Conditions et limites
Utilisez les déclarations de runtime.h et incluez ou compilez runtime.c exactement une fois. Outre cette file, il fournit __nes_nmi, le compteur de trames, les fonctions PPU directes et le tampon OAM de la page 02. Coordonnez son gestionnaire NMI avec votre programme ; une déclaration seule ne lie pas l’implémentation.
Exemple d’utilisation
__scroll_set(0,0);start_counter=nes_nmi_counter;
__ppu_ctrl_set(0x80); // Enable runtime.c's NMI handler before waiting.
nes_wait_nmi(); // Returns after the runtime completion counter changes.
nmi_seen=(u8)(nes_nmi_counter!=start_counter);
if(nmi_seen!=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
L’exemple du runtime présente le transfert direct et les deux attentes. En (0,16), un motif bleu alterne tuiles pleines, barres occupant la moitié gauche et triangles ; en (0,96), un bloc vert est plein. Chaque bloc mesure 256×64 pixels et provient de 256 octets de tuiles. La première tuile bleue reste pleine après modification de la source. À y=208, les repères rouges en x=16, 224 et 240 illustrent l’adresse, l’écriture de longueur nulle et le remplissage de longueur nulle : carré de 8×8, barre gauche de 4×8 et triangle de huit lignes. Les deux attentes indiquent 1 et FAILED CHECKS indique 0.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\runtime_ppu.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\runtime_ppu.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/runtime.h:23
Wait until the NMI handler advances its counter. NMI must already be enabled and able to execute; this polling loop has no timeout.
kitaqfc/lib/runtime.c:185
void nes_wait_nmi(void)
{
unsigned char start;
start = nes_nmi_counter;
while (nes_nmi_counter == start)
{
}
}scene.h — Enregistrement, changement et mise à jour des scènes
Transfère les graphismes de scène vers la file VRAM à l’aide d’un état de transfert partagé unique. Distinguez la fin de step de la fin des écritures PPU effectuées par le consommateur de la file.
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.
nes_scene_stream_begin
Enregistre la destination, la source, la longueur et la taille des blocs, puis marque le flux partagé comme actif.
Syntaxe
void nes_scene_stream_begin(unsigned short ppu_addr, unsigned char* src, unsigned short len, unsigned char chunk);Paramètres
ppu_addrAdresse PPU de destination, et non adresse CPU.
srcSource contenant
lenoctets ; gardez-la lisible jusqu’à la mise en file de tous les octets.lenNombre d’octets, de 0 à 65535 ; l’appelant vérifie aussi les limites de la zone de destination.
chunkCharge utile maximale par enregistrement de file : zéro signifie 32 et les valeurs supérieures à 127 sont limitées à 127. Ce n’est pas la limite totale d’un appel step.
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 seul flux est suivi. Un appel begin le remplace sans annuler les données déjà copiées dans la file. Gardez le stockage source et le mappage ROM valides ; l’appelant doit piloter les appels step et la consommation de la file.
Exemple d’utilisation
nes_scene_stream_begin(0x2100,small,4,2);result[0]=nes_scene_stream_state.remaining;Cet extrait montre l’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 comment copier un flux en blocs dans la file, puis consommer celle-ci vers le PPU. Transférez 960 octets de tuiles, 64 d’attributs et 32 de palette pour afficher un rectangle rouge de 64×32 en (16,32). Appeler begin seul ne met pas l’affichage à jour.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch2_stream.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_stream.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/scene.h:47
Replace the single active transfer and retain its source pointer. Keep the source storage and any required ROM bank readable until all bytes are queued.
kitaqfc/lib/scene.c:86
void nes_scene_stream_begin(unsigned short ppu_addr, unsigned char* src, unsigned short len, unsigned char chunk)
{
nes_scene_stream_state.ppu_addr = ppu_addr;
nes_scene_stream_state.src = src;
nes_scene_stream_state.remaining = len;
nes_scene_stream_state.chunk = chunk;
nes_scene_stream_state.active = 1;
}nes_scene_stream_begin_attr
Prépare 64 octets d’attributs à l’adresse de base de la table de noms +0x03C0, avec des enregistrements de file de 16 octets.
Syntaxe
void nes_scene_stream_begin_attr(unsigned short nt_base, unsigned char* src64);Paramètres
nt_baseAdresse PPU de base d’une table de noms, par exemple 0x2000.
src6464 octets d’attributs ; conservez-les jusqu’à leur mise en file complète.
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 seul flux est suivi. Un appel begin le remplace sans annuler les données déjà copiées dans la file. Gardez le stockage source et le mappage ROM valides ; l’appelant doit piloter les appels step et la consommation de la file.
Exemple d’utilisation
nes_scene_stream_begin_attr(0x2000,attrs);while(nes_scene_stream_step()!=0){nes_vram_queue_nmi_flush();}nes_vram_queue_nmi_flush();Cet extrait montre l’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 comment copier un flux en blocs dans la file, puis consommer celle-ci vers le PPU. Transférez 960 octets de tuiles, 64 d’attributs et 32 de palette pour afficher un rectangle rouge de 64×32 en (16,32). Appeler begin seul ne met pas l’affichage à jour.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch2_stream.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_stream.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/scene.h:51
Prepare the 64-byte attribute table at nametable base + 0x03C0.
kitaqfc/lib/scene.c:102
void nes_scene_stream_begin_attr(unsigned short nt_base, unsigned char* src64)
{
nes_scene_stream_begin((unsigned short)(nt_base + 0x03C0), src64, 64, 16);
}nes_scene_stream_begin_nametable
Prépare le transfert de 960 octets de tuiles d’une table de noms avec des enregistrements de file de 32 octets.
Syntaxe
void nes_scene_stream_begin_nametable(unsigned short nt_base, unsigned char* src960);Paramètres
nt_baseAdresse PPU de base d’une table de noms, par exemple 0x2000.
src960960 octets de tuiles d’une table de noms, sans ses 64 octets d’attributs.
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 seul flux est suivi. Un appel begin le remplace sans annuler les données déjà copiées dans la file. Gardez le stockage source et le mappage ROM valides ; l’appelant doit piloter les appels step et la consommation de la file.
Exemple d’utilisation
nes_scene_stream_begin_nametable(0x2000,tiles960);while(nes_scene_stream_step()!=0){nes_vram_queue_nmi_flush();}nes_vram_queue_nmi_flush();result[4]=nes_scene_stream_state.remaining;Cet extrait montre l’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 comment copier un flux en blocs dans la file, puis consommer celle-ci vers le PPU. Transférez 960 octets de tuiles, 64 d’attributs et 32 de palette pour afficher un rectangle rouge de 64×32 en (16,32). Appeler begin seul ne met pas l’affichage à jour.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch2_stream.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_stream.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/scene.h:49
Prepare the 960-byte tile portion of a nametable using 32-byte queue records.
kitaqfc/lib/scene.c:96
void nes_scene_stream_begin_nametable(unsigned short nt_base, unsigned char* src960)
{
nes_scene_stream_begin(nt_base, src960, 960, 32);
}nes_scene_stream_begin_palette
Prépare 32 octets de palette pour l’adresse PPU 0x3F00 avec des enregistrements de file de 16 octets.
Syntaxe
void nes_scene_stream_begin_palette(unsigned char* src32);Paramètres
src3232 octets de palette : 16 couleurs de fond et 16 de sprites ; respectez les limites des codes couleur et le miroir des adresses PPU.
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 seul flux est suivi. Un appel begin le remplace sans annuler les données déjà copiées dans la file. Gardez le stockage source et le mappage ROM valides ; l’appelant doit piloter les appels step et la consommation de la file.
Exemple d’utilisation
nes_scene_stream_begin_palette(colors);while(nes_scene_stream_step()!=0){nes_vram_queue_nmi_flush();}nes_vram_queue_nmi_flush();Cet extrait montre l’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 comment copier un flux en blocs dans la file, puis consommer celle-ci vers le PPU. Transférez 960 octets de tuiles, 64 d’attributs et 32 de palette pour afficher un rectangle rouge de 64×32 en (16,32). Appeler begin seul ne met pas l’affichage à jour.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch2_stream.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_stream.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/scene.h:53
Prepare a 32-byte palette transfer to PPU address 0x3F00.
kitaqfc/lib/scene.c:108
void nes_scene_stream_begin_palette(unsigned char* src32)
{
nes_scene_stream_begin(0x3F00, src32, 32, 16);
}nes_scene_stream_step
Copie les données restantes en autant de blocs que la file VRAM du runtime peut en accepter.
Syntaxe
unsigned char nes_scene_stream_step(void);Valeur renvoyée
1 si la capacité de la file laisse des données en attente ; 0 si tout est en file ou si le flux est inactif. Un bloc refusé ne fait avancer ni la source ni la destination, ce qui permet de réessayer. Un retour à zéro peut laisser des transferts PPU en attente.
Conditions et limites
Un seul flux est suivi. Un appel begin le remplace sans annuler les données déjà copiées dans la file. Gardez le stockage source et le mappage ROM valides ; l’appelant doit piloter les appels step et la consommation de la file.
Exemple d’utilisation
result[1]=nes_scene_stream_step();result[2]=nes_scene_stream_state.active;result[3]=nes_vram_queue_used;nes_vram_queue_nmi_flush();Cet extrait montre l’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 comment copier un flux en blocs dans la file, puis consommer celle-ci vers le PPU. Transférez 960 octets de tuiles, 64 d’attributs et 32 de palette pour afficher un rectangle rouge de 64×32 en (16,32). Appeler begin seul ne met pas l’affichage à jour.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch2_stream.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_stream.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chrImplémentation et source
kitaqfc/lib/scene.h:57
Queue as many chunks as available capacity allows, capped at 127 bytes each. Return one when queue exhaustion requires a later retry, zero when all data has been queued. Zero does not mean the NMI consumer has already written the PPU.
kitaqfc/lib/scene.c:116
unsigned char nes_scene_stream_step(void)
{
unsigned char chunk;
while (nes_scene_stream_state.active != 0)
{
if (nes_scene_stream_state.remaining == 0)
{
nes_scene_stream_state.active = 0;
return 0;
}
// A step may enqueue several chunks; chunk limits record size, not the total bytes or time per frame.
chunk = nes_scene_stream_state.chunk;
if (chunk == 0)
{
chunk = 32;
}
if ((unsigned short)chunk > nes_scene_stream_state.remaining)
{
chunk = (unsigned char)nes_scene_stream_state.remaining;
}
if (chunk > 127)
{
chunk = 127;
}
// A failed enqueue leaves this chunk pending so a later step can retry after the queue drains.
if (nes_vram_queue_try_write(nes_scene_stream_state.ppu_addr, nes_scene_stream_state.src, chunk) == 0)
{
return 1;
}
nes_scene_stream_state.ppu_addr = (unsigned short)(nes_scene_stream_state.ppu_addr + chunk);
nes_scene_stream_state.src = nes_scene_stream_state.src + chunk;
nes_scene_stream_state.remaining = (unsigned short)(nes_scene_stream_state.remaining - chunk);
}
return 0;
}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.
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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/scene.h:33
Ignore invalid IDs; otherwise exit the current scene and enter the requested one. Selecting the current ID still performs exit/enter. Callbacks run synchronously.
kitaqfc/lib/scene.c:28
void scene_change(u8 scene_id)
{
SceneFunc fn;
if (scene_id >= kq_scene_count) return;
// Exit/enter handlers must not recursively change scenes or replace this shared table.
if (kq_scene_has_current != 0) {
fn = kq_scene_table[(__safe_index u8)kq_scene_current].exit;
if (fn != 0) fn();
}
kq_scene_current = scene_id;
kq_scene_has_current = 1;
kq_scene_changed = 1;
fn = kq_scene_table[(__safe_index u8)kq_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.
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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/scene.h:38
Call the active scene's draw handler if one exists; no current scene is a no-op.
kitaqfc/lib/scene.c:61
void scene_draw()
{
SceneFunc fn;
if (kq_scene_has_current == 0) return;
fn = kq_scene_table[(__safe_index u8)kq_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.
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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/scene.h:40
Return the stored scene ID; zero is also returned before the first transition.
kitaqfc/lib/scene.c:71
u8 scene_get_current()
{
return kq_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.
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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/scene.h:28
Attach the caller-owned scene table and clear current-scene state without invoking callbacks.
kitaqfc/lib/scene.c:11
void scene_init(const SceneDef* scenes, u8 count)
{
kq_scene_table = scenes;
kq_scene_count = count;
kq_scene_current = 0;
kq_scene_changed = 0;
kq_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.
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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/scene.h:30
Replace the table by resetting scene state; this does not call the old scene's exit handler.
kitaqfc/lib/scene.c:21
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.
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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/scene.h:36
Clear the change flag before calling the active scene's update handler, so a transition made during that handler is visible afterward.
kitaqfc/lib/scene.c:50
void scene_update()
{
SceneFunc fn;
if (kq_scene_has_current == 0) return;
kq_scene_changed = 0;
fn = kq_scene_table[(__safe_index u8)kq_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.
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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/scene.h:42
Read the transition flag, which is cleared at the start of an active scene update.
kitaqfc/lib/scene.c:77
u8 scene_was_changed()
{
return kq_scene_changed;
}scroll.h — Arrière-plan, fenêtre et défilement fractionné
Construit la sélection de table de noms de PPUCTRL et PPUSCROLL à partir de coordonnées du monde sur 16 bits. Y est aussi divisé en plages de 256 unités ; tenez compte de la hauteur d’écran de 240 pixels.
nes_camera_follow_center
Soustrait le point d’ancrage à l’écran de la position de la cible dans le monde et enregistre le résultat comme coordonnées de caméra.
Syntaxe
void nes_camera_follow_center(unsigned short target_x, unsigned short target_y, unsigned char center_x, unsigned char center_y);Paramètres
target_xX de la cible dans le monde, en pixels, de 0 à 65535.
target_yY de la cible dans le monde, en pixels, de 0 à 65535.
center_xX souhaité de la cible à l’écran, de 0 à 255.
center_yY souhaité de la cible à l’écran, 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
Une seule paire de coordonnées est partagée. Appelez nes_scroll_apply pour mettre le matériel à jour. Les résultats négatifs d’une soustraction rebouclent dans u16 ; gérez les limites du monde dans le jeu.
Exemple d’utilisation
nes_camera_follow_center(300,260,128,120);result[4]=nes_scroll_camera_x;result[5]=nes_scroll_camera_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
Cet exemple montre comment les coordonnées enregistrées sur 16 bits produisent PPUCTRL et le défilement. Le contrôle de base vaut 144 ; appliquer (264,272) donne 147. Suivre la cible (300,260) avec l’ancrage (128,120) donne une caméra en (172,140). Des contrôles d’état séparés examinent les écritures PPU effectives.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_scroll.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrExemple d’utilisation
nes_scroll_set_base_ctrl(0);
nes_scroll_set(264,16);
nes_scroll_apply();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Affichez la table de noms 1 avec le miroir vertical sur NROM. Un rectangle rouge de 32×16 en (288,32) dans le monde apparaît en (24,16) à l’écran avec la caméra en (264,16), illustrant la sélection de table par le bit 8 et le défilement par l’octet faible.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_scroll_view.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_view.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --mirroring=verticalImplémentation et source
kitaqfc/lib/scroll.h:21
Subtract the screen anchor from the world point into unsigned camera coordinates. Underflow wraps; world-edge clamping belongs to the game.
kitaqfc/lib/scroll.c:56
void nes_camera_follow_center(unsigned short target_x, unsigned short target_y, unsigned char center_x, unsigned char center_y)
{
nes_scroll_camera_x = target_x - center_x;
nes_scroll_camera_y = target_y - center_y;
}nes_scroll_apply
Combine les coordonnées enregistrées avec le PPUCTRL de base, réinitialise le verrou et écrit PPUCTRL ainsi que le défilement X/Y.
Syntaxe
void nes_scroll_apply(void);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 bit 8 de chaque axe choisit une table de noms ; l’octet faible fournit le défilement. Les valeurs Y de 240 à 255 ne sont pas des positions ordinaires de défilement vertical. Tout PPUCTRL est remplacé : initialisez donc délibérément NMI et les autres bits de base. Aucune attente VBlank n’a lieu ; la lecture de PPUSTATUS affecte aussi le drapeau VBlank et le verrou partagé.
Exemple d’utilisation
nes_scroll_apply();result[3]=nes_scroll_ctrl_base|((nes_scroll_camera_x>>8)&1)|((nes_scroll_camera_y>>7)&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 montre comment les coordonnées enregistrées sur 16 bits produisent PPUCTRL et le défilement. Le contrôle de base vaut 144 ; appliquer (264,272) donne 147. Suivre la cible (300,260) avec l’ancrage (128,120) donne une caméra en (172,140). Des contrôles d’état séparés examinent les écritures PPU effectives.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_scroll.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrExemple d’utilisation
nes_scroll_set_base_ctrl(0);
nes_scroll_set(264,16);
nes_scroll_apply();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Affichez la table de noms 1 avec le miroir vertical sur NROM. Un rectangle rouge de 32×16 en (288,32) dans le monde apparaît en (24,16) à l’écran avec la caméra en (264,16), illustrant la sélection de table par le bit 8 et le défilement par l’octet faible.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_scroll_view.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_view.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --mirroring=verticalImplémentation et source
kitaqfc/lib/scroll.h:18
Combine bit 8 of each camera coordinate with base PPUCTRL, reset the latch by reading PPUSTATUS, and write low-byte X/Y scroll. This uses 256-unit wrapping on both axes rather than normalizing Y to a 240-pixel nametable height. Initialize base control to the intended PPUCTRL value, including NMI enable, before applying. Only coordinate bits 0..8 are used; arrange safe PPU timing in the caller.
kitaqfc/lib/scroll.c:34
void nes_scroll_apply(void)
{
unsigned char ctrl;
unsigned char x_hi;
unsigned char y_hi;
unsigned char latch;
x_hi = (unsigned char)((nes_scroll_camera_x >> 8) & 1);
y_hi = (unsigned char)((nes_scroll_camera_y >> 8) & 1);
ctrl = (unsigned char)(nes_scroll_ctrl_base | x_hi | (unsigned char)(y_hi << 1));
// Replace the whole control register, so the saved base also determines NMI and increment mode.
PPUCTRL = ctrl;
latch = PPUSTATUS;
PPUSCROLL = (unsigned char)nes_scroll_camera_x;
PPUSCROLL = (unsigned char)nes_scroll_camera_y;
latch = latch;
}nes_scroll_set
Enregistre les coordonnées de caméra sur 16 bits sans écrire dans le PPU.
Syntaxe
void nes_scroll_set(unsigned short camera_x, unsigned short camera_y);Paramètres
camera_xCoordonnée horizontale en pixels entiers ; l’application utilise ses neuf bits de poids faible.
camera_yCoordonnée verticale ; l’application utilise les neuf bits de poids faible sans normaliser à la hauteur de 240 pixels d’une table de noms.
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 seule paire de coordonnées est partagée. Appelez nes_scroll_apply pour mettre le matériel à jour. Les résultats négatifs d’une soustraction rebouclent dans u16 ; gérez les limites du monde dans le jeu.
Exemple d’utilisation
nes_scroll_set(264,272);result[1]=nes_scroll_camera_x;result[2]=nes_scroll_camera_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
Cet exemple montre comment les coordonnées enregistrées sur 16 bits produisent PPUCTRL et le défilement. Le contrôle de base vaut 144 ; appliquer (264,272) donne 147. Suivre la cible (300,260) avec l’ancrage (128,120) donne une caméra en (172,140). Des contrôles d’état séparés examinent les écritures PPU effectives.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_scroll.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrExemple d’utilisation
nes_scroll_set_base_ctrl(0);
nes_scroll_set(264,16);
nes_scroll_apply();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Affichez la table de noms 1 avec le miroir vertical sur NROM. Un rectangle rouge de 32×16 en (288,32) dans le monde apparaît en (24,16) à l’écran avec la caméra en (264,16), illustrant la sélection de table par le bit 8 et le défilement par l’octet faible.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_scroll_view.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_view.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --mirroring=verticalImplémentation et source
kitaqfc/lib/scroll.h:12
Store camera coordinates without touching hardware registers.
kitaqfc/lib/scroll.c:25
void nes_scroll_set(unsigned short camera_x, unsigned short camera_y)
{
nes_scroll_camera_x = camera_x;
nes_scroll_camera_y = camera_y;
}nes_scroll_set_base_ctrl
Enregistre la valeur de base de PPUCTRL avec ses deux bits de sélection de table de noms effacés.
Syntaxe
void nes_scroll_set_base_ctrl(unsigned char ctrl);Paramètres
ctrlValeur PPUCTRL comprenant les réglages NMI, de table de motifs et d’incrément ; ses deux bits de poids faible sont déterminés par les coordonnées.
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 seule paire de coordonnées est partagée. Appelez nes_scroll_apply pour mettre le matériel à jour. Les résultats négatifs d’une soustraction rebouclent dans u16 ; gérez les limites du monde dans le jeu.
Exemple d’utilisation
nes_scroll_set_base_ctrl(0x93);result[0]=nes_scroll_ctrl_base;Cet extrait montre l’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 comment les coordonnées enregistrées sur 16 bits produisent PPUCTRL et le défilement. Le contrôle de base vaut 144 ; appliquer (264,272) donne 147. Suivre la cible (300,260) avec l’ancrage (128,120) donne une caméra en (172,140). Des contrôles d’état séparés examinent les écritures PPU effectives.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_scroll.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrExemple d’utilisation
nes_scroll_set_base_ctrl(0);
nes_scroll_set(264,16);
nes_scroll_apply();Cet extrait montre l’appel. Avant de l’intégrer à un programme complet, respectez les conditions d’initialisation et de dimensionnement des tampons indiquées.
Résultat attendu
Affichez la table de noms 1 avec le miroir vertical sur NROM. Un rectangle rouge de 32×16 en (288,32) dans le monde apparaît en (24,16) à l’écran avec la caméra en (264,16), illustrant la sélection de table par le bit 8 et le défilement par l’octet faible.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_scroll_view.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_view.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --mirroring=verticalImplémentation et source
kitaqfc/lib/scroll.h:10
Store PPUCTRL bits other than the two nametable-selection bits for later application.
kitaqfc/lib/scroll.c:19
void nes_scroll_set_base_ctrl(unsigned char ctrl)
{
nes_scroll_ctrl_base = (unsigned char)(ctrl & 0xFC);
}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 FC : 0..1 choisissent l’une des quatre palettes ; 5 place le sprite derrière les pixels de fond d’indice non nul ; 6/7 retournent X/Y. Laissez 2..4 à zéro. Les valeurs diffèrent du GB : utilisez les constantes de chaque plateforme.
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.
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/sprite.h:74
Advance animation ticks and wrap the frame index, returning the selected tile. Zero ticks-per-frame freezes advancement; null state returns zero.
kitaqfc/lib/sprite.c:174
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 = (u8)(anim->ticks + 1);
if (anim->ticks >= anim->ticks_per_frame) {
anim->ticks = 0;
anim->frame = (u8)(anim->frame + 1);
if (anim->frame >= anim->frame_count) anim->frame = 0;
}
return (u8)(anim->first_tile + anim->frame);
}metasprite_draw
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.
yOctet Y de l’OAM. Pour placer le haut sous la ligne zéro, passez sa position moins un ; 239..255 sont hors des 240 lignes visibles.
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.
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/sprite.h:71
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.
kitaqfc/lib/sprite.c:152
u8 metasprite_draw(u8 first_id, u8 x, u8 y, const MetaSpritePart* parts, u8 count)
{
u8 i;
i = 0;
while (i < count) {
u8 id;
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(id, (u8)(x + parts[i].dx), (u8)(y + parts[i].dy), parts[i].tile, parts[i].flags);
kq_sprite_x[id] = (u8)(x + parts[i].dx);
kq_sprite_y[id] = (u8)(y + parts[i].dy);
i = (u8)(i + 1);
}
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(void);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.
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/sprite.h:45
Claim and hide the first free slot, or return 0xFF if all slots are active.
kitaqfc/lib/sprite.c:35
u8 sprite_alloc(void)
{
u8 i;
i = 0;
while (i < SPRITE_MAX) {
if (kq_sprite_active[i] == 0) {
kq_sprite_active[i] = 1;
kq_sprite_used = (u8)(kq_sprite_used + 1);
sprite_hide(i);
return i;
}
i = (u8)(i + 1);
}
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(void);Valeur renvoyée
Octet non signé entre 0 et SPRITE_MAX.
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/sprite.h:62
Return the number of active slots, including slots activated by metasprite_draw. Hidden allocated slots remain active until sprite_free releases them.
kitaqfc/lib/sprite.c:108
u8 sprite_count_used(void)
{
return kq_sprite_used;
}sprite_flush_oam
Attend l’avancement du compteur d’images NMI, puis transfère la page OAM de 256 octets. La NMI doit être activée et son gestionnaire doit actualiser ce compteur.
Syntaxe
void sprite_flush_oam(void);Valeur renvoyée
Aucune (void).
Conditions et limites
La routine FC met OAMADDR à zéro et lance le DMA depuis la page CPU $02 ($0200–$02FF). Utilisez-la pendant le VBlank ou avec le rendu désactivé ; évitez les modifications concurrentes de cette page avec une interruption.
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/sprite.h:59
Wait for NMI before requesting OAM DMA.
kitaqfc/lib/sprite.c:100
void sprite_flush_oam(void)
{
__nmi_wait();
__oam_dma();
}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(void);Valeur renvoyée
Aucune (void).
Conditions et limites
La routine FC met OAMADDR à zéro et lance le DMA depuis la page CPU $02 ($0200–$02FF). Utilisez-la pendant le VBlank ou avec le rendu désactivé ; évitez les modifications concurrentes de cette page avec une interruption.
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/sprite.h:57
Transfer intrinsic shadow OAM immediately; this wrapper does not wait for VBlank.
kitaqfc/lib/sprite.c:94
void sprite_flush_oam_now(void)
{
__oam_dma();
}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.
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/sprite.h:47
Release an active valid slot and hide it; invalid/repeated frees are ignored.
kitaqfc/lib/sprite.c:52
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 = (u8)(kq_sprite_used - 1);
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.
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/sprite.h:55
Mark the software position off screen and hide its OAM entry without freeing it.
kitaqfc/lib/sprite.c:85
void sprite_hide(u8 id)
{
if (sprite_valid(id) == 0) return;
kq_sprite_x[id] = 0;
kq_sprite_y[id] = 0xF0;
__sprite_hide(id);
}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(void);Valeur renvoyée
Aucune (void).
Conditions et limites
Sur FC, l’allocation et les coordonnées suivies sont réinitialisées, mais le masquage conserve les octets de tuile et d’attributs. SPRITE_MAX doit rester entre 1 et 64.
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/sprite.h:43
Reset allocation/position state and hide each OAM slot through the intrinsic. The software height defaults to eight; hardware sprite size is configured elsewhere.
kitaqfc/lib/sprite.c:19
void sprite_init(void)
{
u8 i;
kq_sprite_used = 0;
kq_sprite_height = 8;
i = 0;
while (i < SPRITE_MAX) {
kq_sprite_active[i] = 0;
kq_sprite_x[i] = 0;
kq_sprite_y[i] = 0;
__sprite_hide(i);
i = (u8)(i + 1);
}
}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(void);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.
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/sprite.h:67
Estimate peak overlap across 240 lines from software Y/height values. This does not model pixel transparency, OAM priority or every hardware overflow quirk.
kitaqfc/lib/sprite.c:117
u8 sprite_max_scanline_count(void)
{
u8 line;
u8 best;
line = 0;
best = 0;
while (line < 240) {
u8 i;
u8 count;
i = 0;
count = 0;
while (i < SPRITE_MAX) {
if (kq_sprite_active[i] != 0) {
if (line > kq_sprite_y[i] && (u8)(line - kq_sprite_y[i]) <= kq_sprite_height) {
count = (u8)(count + 1);
}
}
i = (u8)(i + 1);
}
if (count > best) best = count;
line = (u8)(line + 1);
}
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 FC : 0..1 choisissent l’une des quatre palettes ; 5 place le sprite derrière les pixels de fond d’indice non nul ; 6/7 retournent X/Y. Laissez 2..4 à zéro. Les valeurs diffèrent du GB : utilisez les constantes de chaque plateforme.
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/sprite.h:53
Replace the hardware attribute byte of a valid OAM slot.
kitaqfc/lib/sprite.c:78
void sprite_set_flags(u8 id, u8 flags)
{
if (sprite_valid(id) == 0) return;
__sprite_attr(id, flags);
}sprite_set_pos
Met à jour la position logicielle et les coordonnées OAM du sprite FC. X est la position à l’écran ; Y est l’octet OAM. Pour placer le haut au pixel 32, passez Y=31.
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.
yOctet Y de l’OAM. Pour placer le haut sous la ligne zéro, passez sa position moins un ; 239..255 sont hors des 240 lignes visibles.
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.
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/sprite.h:49
Update software coordinates and the intrinsic OAM position for a valid slot.
kitaqfc/lib/sprite.c:62
void sprite_set_pos(u8 id, u8 x, u8 y)
{
if (sprite_valid(id) == 0) return;
kq_sprite_x[id] = x;
kq_sprite_y[id] = y;
__sprite_move(id, x, y);
}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.
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/sprite.h:51
Replace the tile byte of a valid OAM slot without changing allocation state.
kitaqfc/lib/sprite.c:71
void sprite_set_tile(u8 id, u8 tile)
{
if (sprite_valid(id) == 0) return;
__sprite_tile(id, 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(void);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.
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
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sprite_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.nes --nes-chr=.\kitaq-docs\samples\sprite_example.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/sprite.h:64
Flag software overlap estimates above eight sprites on one scanline.
kitaqfc/lib/sprite.c:143
u8 sprite_warn_scanline_overflow(void)
{
return (u8)(sprite_max_scanline_count() > 8);
}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.
fc_frame_count
fc_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 fc_frame_count(void);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.
L’initialisation FC active la NMI. L’attente exige que les NMI soient correctement délivrées. Masquer les IRQ du CPU n’arrête pas les NMI.
Exemple d’utilisation
result[3]=fc_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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\system_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\system_aliases.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/system.h:30
#define fc_frame_count system_get_framekitaqfc/lib/system.c:30
u16 system_get_frame(void)
{
return kq_system_frame;
}fc_init
fc_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 fc_init(void);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.
L’initialisation FC active la NMI. L’attente exige que les NMI soient correctement délivrées. Masquer les IRQ du CPU n’arrête pas les NMI.
Exemple d’utilisation
fc_init();result[0]=fc_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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\system_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\system_aliases.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/system.h:27
#define fc_init system_initkitaqfc/lib/system.c:7
void system_init(void)
{
kq_system_frame = 0;
system_vblank_callback = 0;
// NMI waits require a running PPU and its enabled NMI source, independently of the CPU IRQ mask.
__nmi_enable();
}fc_set_vblank_callback
fc_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 fc_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.
L’initialisation FC active la NMI. L’attente exige que les NMI soient correctement délivrées. Masquer les IRQ du CPU n’arrête pas les NMI.
Exemple d’utilisation
fc_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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\system_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\system_aliases.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/system.h:29
#define fc_set_vblank_callback system_set_vblank_callbackkitaqfc/lib/system.c:24
void system_set_vblank_callback(SystemCallback callback)
{
system_vblank_callback = callback;
}fc_wait_vblank
fc_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 fc_wait_vblank(void);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.
L’initialisation FC active la NMI. L’attente exige que les NMI soient correctement délivrées. Masquer les IRQ du CPU n’arrête pas les NMI.
Exemple d’utilisation
fc_wait_vblank();fc_wait_vblank();fc_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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\system_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\system_aliases.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/system.h:28
#define fc_wait_vblank system_wait_vblankkitaqfc/lib/system.c:16
void system_wait_vblank(void)
{
__nmi_wait();
kq_system_frame = (u16)(kq_system_frame + 1);
if (system_vblank_callback != 0) system_vblank_callback();
}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(void);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.
C’est la forme gb_ fournie par la bibliothèque FC. Elle appelle l’implémentation FC system_*, pas le matériel Game Boy. Le nom fc_ correspondant appelle cette même implémentation FC.
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.
L’initialisation FC active la NMI. L’attente exige que les NMI soient correctement délivrées. Masquer les IRQ du CPU n’arrête pas les NMI.
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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\system_gb_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\system_gb_aliases.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/system.h:34
#define gb_frame_count system_get_framekitaqfc/lib/system.c:30
u16 system_get_frame(void)
{
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(void);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.
C’est la forme gb_ fournie par la bibliothèque FC. Elle appelle l’implémentation FC system_*, pas le matériel Game Boy. Le nom fc_ correspondant appelle cette même implémentation FC.
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.
L’initialisation FC active la NMI. L’attente exige que les NMI soient correctement délivrées. Masquer les IRQ du CPU n’arrête pas les NMI.
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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\system_gb_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\system_gb_aliases.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/system.h:31
#define gb_init system_initkitaqfc/lib/system.c:7
void system_init(void)
{
kq_system_frame = 0;
system_vblank_callback = 0;
// NMI waits require a running PPU and its enabled NMI source, independently of the CPU IRQ mask.
__nmi_enable();
}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.
C’est la forme gb_ fournie par la bibliothèque FC. Elle appelle l’implémentation FC system_*, pas le matériel Game Boy. Le nom fc_ correspondant appelle cette même implémentation FC.
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.
L’initialisation FC active la NMI. L’attente exige que les NMI soient correctement délivrées. Masquer les IRQ du CPU n’arrête pas les NMI.
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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\system_gb_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\system_gb_aliases.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/system.h:33
#define gb_set_vblank_callback system_set_vblank_callbackkitaqfc/lib/system.c:24
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(void);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.
C’est la forme gb_ fournie par la bibliothèque FC. Elle appelle l’implémentation FC system_*, pas le matériel Game Boy. Le nom fc_ correspondant appelle cette même implémentation FC.
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.
L’initialisation FC active la NMI. L’attente exige que les NMI soient correctement délivrées. Masquer les IRQ du CPU n’arrête pas les NMI.
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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\system_gb_aliases.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\system_gb_aliases.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/system.h:32
#define gb_wait_vblank system_wait_vblankkitaqfc/lib/system.c:16
void system_wait_vblank(void)
{
__nmi_wait();
kq_system_frame = (u16)(kq_system_frame + 1);
if (system_vblank_callback != 0) system_vblank_callback();
}system_disable_interrupts
Désactive les interruptions masquables du processeur.
Syntaxe
void system_disable_interrupts(void);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.
L’initialisation FC active la NMI. L’attente exige que les NMI soient correctement délivrées. Masquer les IRQ du CPU n’arrête pas les NMI.
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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/system.h:25
Disable maskable CPU IRQs; this does not disable the PPU's NMI source.
kitaqfc/lib/system.c:48
void system_disable_interrupts(void)
{
__irq_disable();
}system_enable_interrupts
Active les interruptions masquables du processeur.
Syntaxe
void system_enable_interrupts(void);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.
L’initialisation FC active la NMI. L’attente exige que les NMI soient correctement délivrées. Masquer les IRQ du CPU n’arrête pas les NMI.
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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/system.h:23
Enable maskable CPU IRQs through the intrinsic; NMI is controlled separately.
kitaqfc/lib/system.c:42
void system_enable_interrupts(void)
{
__irq_enable();
}system_get_frame
Lit le compteur sur 16 bits de la fonction d’attente de trame.
Syntaxe
u16 system_get_frame(void);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.
L’initialisation FC active la NMI. L’attente exige que les NMI soient correctement délivrées. Masquer les IRQ du CPU n’arrête pas les NMI.
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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/system.h:19
Return the wrapping 16-bit count of completed waits through this wrapper.
kitaqfc/lib/system.c:30
u16 system_get_frame(void)
{
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(void);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.
L’initialisation FC active la NMI. L’attente exige que les NMI soient correctement délivrées. Masquer les IRQ du CPU n’arrête pas les NMI.
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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/system.h:21
Return the low byte of the software frame counter.
kitaqfc/lib/system.c:36
u8 system_get_frame8(void)
{
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(void);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.
L’initialisation FC active la NMI. L’attente exige que les NMI soient correctement délivrées. Masquer les IRQ du CPU n’arrête pas les NMI.
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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/system.h:13
Reset the software frame counter and callback storage, then enable NMI.
kitaqfc/lib/system.c:7
void system_init(void)
{
kq_system_frame = 0;
system_vblank_callback = 0;
// NMI waits require a running PPU and its enabled NMI source, independently of the CPU IRQ mask.
__nmi_enable();
}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.
L’initialisation FC active la NMI. L’attente exige que les NMI soient correctement délivrées. Masquer les IRQ du CPU n’arrête pas les NMI.
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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/system.h:17
Replace the per-wait callback; null disables callback dispatch.
kitaqfc/lib/system.c:24
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(void);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.
L’initialisation FC active la NMI. L’attente exige que les NMI soient correctement délivrées. Masquer les IRQ du CPU n’arrête pas les NMI.
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
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\runtime.c .\kitaq-docs\samples\api-examples\fc\batch_services.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch_services.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/system.h:15
Wait for NMI, count the completed wait, then invoke the registered callback.
kitaqfc/lib/system.c:16
void system_wait_vblank(void)
{
__nmi_wait();
kq_system_frame = (u16)(kq_system_frame + 1);
if (system_vblank_callback != 0) system_vblank_callback();
}tilemap.h — Opérations rectangulaires sur les cartes de tuiles
Lit un tableau de tuiles rangé par lignes et teste la solidité à partir d’un seuil d’identifiant. Les tests de rectangle n’inspectent que les quatre coins, sans parcourir tout l’intérieur.
nes_tilemap_get
Lit l’identifiant de tuile et renvoie 255 pour des coordonnées hors de la carte.
Syntaxe
unsigned char nes_tilemap_get(struct NesTilemap* map, unsigned char tx, unsigned char ty);Paramètres
mapCarte valide avec tableau de tuiles rangé par lignes, dimensions et seuil de solidité ; son stockage doit rester lisible pendant l’appel.
txCoordonnée X de tuile ; une unité vaut huit pixels.
tyCoordonnée Y de tuile ; une unité vaut huit pixels.
Valeur renvoyée
Octet de la tuile ou 255 ; un 255 stocké ne se distingue pas d’un résultat hors limites.
Conditions et limites
Exige une carte valide et un tableau non vide accessible en lecture. Le caractère solide dépend d’un seuil d’identifiant de tuile, pas d’un masque de collision distinct.
Exemple d’utilisation
result[1]=nes_tilemap_get(&map,2,1);result[2]=nes_tilemap_get(&map,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
Placez la tuile solide 5 en (2,1) dans une carte de 5×3 : son indice de tableau est 7 et une lecture extérieure renvoie 255. Un coin touchant l’obstacle donne 1 ; un rectangle de 40×24 qui l’enferme seulement dans son intérieur donne 0, illustrant la limite du test des seuls coins.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_tilemap.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_tilemap.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/tilemap.h:19
Return a tile byte, or 0xFF when coordinates exceed map dimensions. The map/storage pointers must be valid; 0xFF may also be an actual stored tile.
kitaqfc/lib/tilemap.c:32
unsigned char nes_tilemap_get(struct NesTilemap* map, unsigned char tx, unsigned char ty)
{
if (tx >= map->width)
{
return 0xFF;
}
if (ty >= map->height)
{
return 0xFF;
}
return map->tiles[nes_tilemap_index(map, tx, ty)];
}nes_tilemap_index
Convertit les coordonnées de tuile en décalage d’octet par lignes ty*width+tx.
Syntaxe
unsigned short nes_tilemap_index(struct NesTilemap* map, unsigned char tx, unsigned char ty);Paramètres
mapCarte valide avec tableau de tuiles rangé par lignes, dimensions et seuil de solidité ; son stockage doit rester lisible pendant l’appel.
txCoordonnée X de tuile ; une unité vaut huit pixels.
tyCoordonnée Y de tuile ; une unité vaut huit pixels.
Valeur renvoyée
Décalage calculé sur 16 bits ; les coordonnées ne sont pas vérifiées par rapport aux limites.
Conditions et limites
Exige une carte valide et un tableau non vide accessible en lecture. Le caractère solide dépend d’un seuil d’identifiant de tuile, pas d’un masque de collision distinct.
Exemple d’utilisation
result[0]=nes_tilemap_index(&map,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
Placez la tuile solide 5 en (2,1) dans une carte de 5×3 : son indice de tableau est 7 et une lecture extérieure renvoie 255. Un coin touchant l’obstacle donne 1 ; un rectangle de 40×24 qui l’enferme seulement dans son intérieur donne 0, illustrant la limite du test des seuls coins.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_tilemap.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_tilemap.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/tilemap.h:16
Compute a row-major byte offset by adding the row stride ty times. This internal arithmetic helper does not validate coordinates.
kitaqfc/lib/tilemap.c:14
unsigned short nes_tilemap_index(struct NesTilemap* map, unsigned char tx, unsigned char ty)
{
unsigned short index;
unsigned char y;
index = tx;
y = 0;
while (y != ty)
{
index = (unsigned short)(index + map->width);
y = y + 1;
}
return index;
}nes_tilemap_point_solid
Teste la tuile par rapport à solid_from ; la tuile 255 et les coordonnées hors limites sont toujours solides.
Syntaxe
unsigned char nes_tilemap_point_solid(struct NesTilemap* map, unsigned char tx, unsigned char ty);Paramètres
mapCarte valide avec tableau de tuiles rangé par lignes, dimensions et seuil de solidité ; son stockage doit rester lisible pendant l’appel.
txCoordonnée X de tuile ; une unité vaut huit pixels.
tyCoordonnée Y de tuile ; une unité vaut huit pixels.
Valeur renvoyée
1 si solide, sinon 0.
Conditions et limites
Exige une carte valide et un tableau non vide accessible en lecture. Le caractère solide dépend d’un seuil d’identifiant de tuile, pas d’un masque de collision distinct.
Exemple d’utilisation
result[3]=nes_tilemap_point_solid(&map,2,1);result[4]=nes_tilemap_point_solid(&map,0,0);result[5]=nes_tilemap_point_solid(&map,5,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
Placez la tuile solide 5 en (2,1) dans une carte de 5×3 : son indice de tableau est 7 et une lecture extérieure renvoie 255. Un coin touchant l’obstacle donne 1 ; un rectangle de 40×24 qui l’enferme seulement dans son intérieur donne 0, illustrant la limite du test des seuls coins.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_tilemap.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_tilemap.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/tilemap.h:22
Treat out-of-bounds/0xFF tiles as solid, then compare other tile IDs with the map's solid_from threshold.
kitaqfc/lib/tilemap.c:47
unsigned char nes_tilemap_point_solid(struct NesTilemap* map, unsigned char tx, unsigned char ty)
{
unsigned char tile;
tile = nes_tilemap_get(map, tx, ty);
if (tile == 0xFF)
{
return 1;
}
if (tile >= map->solid_from)
{
return 1;
}
return 0;
}nes_tilemap_world_box_solid
Teste les coins supérieur gauche, supérieur droit, inférieur gauche et inférieur droit d’un rectangle du monde.
Syntaxe
unsigned char nes_tilemap_world_box_solid(struct NesTilemap* map, unsigned short world_x, unsigned short world_y, unsigned char width, unsigned char height);Paramètres
mapCarte valide avec tableau de tuiles rangé par lignes, dimensions et seuil de solidité ; son stockage doit rester lisible pendant l’appel.
world_xX du monde en pixels entiers ; gardez-le inférieur à 2048 pour éviter le rebouclage.
world_yY du monde en pixels entiers ; gardez-le inférieur à 2048 pour éviter le rebouclage.
widthLargeur du rectangle, de 1 à 255 pixels ; gardez son bord éloigné
world_x+width-1inférieur à 2048.heightHauteur du rectangle, de 1 à 255 pixels ; gardez son bord éloigné
world_y+height-1inférieur à 2048.
Valeur renvoyée
1 si au moins un coin est solide, sinon 0.
Conditions et limites
La largeur et la hauteur doivent être non nulles. Les bords entre les coins et l’intérieur ne sont pas parcourus ; de grands rectangles peuvent donc manquer des obstacles. L’exemple renvoie zéro pour un obstacle central lorsque les quatre coins sont vides.
Exemple d’utilisation
result[12]=nes_tilemap_world_box_solid(&map,8,8,16,8);result[13]=nes_tilemap_world_box_solid(&map,0,0,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
Placez la tuile solide 5 en (2,1) dans une carte de 5×3 : son indice de tableau est 7 et une lecture extérieure renvoie 255. Un coin touchant l’obstacle donne 1 ; un rectangle de 40×24 qui l’enferme seulement dans son intérieur donne 0, illustrant la limite du test des seuls coins.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_tilemap.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_tilemap.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/tilemap.h:33
Test only the four corners of a nonempty world box. Interior/edge tiles between the corners are not scanned, so large boxes can miss obstacles. Width/height must be nonzero and endpoint arithmetic must not overflow.
kitaqfc/lib/tilemap.c:86
unsigned char nes_tilemap_world_box_solid(struct NesTilemap* map, unsigned short world_x, unsigned short world_y, unsigned char width, unsigned char height)
{
unsigned short x2;
unsigned short y2;
x2 = (unsigned short)(world_x + width - 1);
y2 = (unsigned short)(world_y + height - 1);
if (nes_tilemap_world_point_solid(map, world_x, world_y) != 0)
{
return 1;
}
if (nes_tilemap_world_point_solid(map, x2, world_y) != 0)
{
return 1;
}
if (nes_tilemap_world_point_solid(map, world_x, y2) != 0)
{
return 1;
}
if (nes_tilemap_world_point_solid(map, x2, y2) != 0)
{
return 1;
}
return 0;
}nes_tilemap_world_point_solid
Convertit un point du monde en coordonnées de tuiles de huit pixels et teste sa solidité.
Syntaxe
unsigned char nes_tilemap_world_point_solid(struct NesTilemap* map, unsigned short world_x, unsigned short world_y);Paramètres
mapCarte valide avec tableau de tuiles rangé par lignes, dimensions et seuil de solidité ; son stockage doit rester lisible pendant l’appel.
world_xX du monde en pixels entiers ; gardez-le inférieur à 2048 pour éviter le rebouclage.
world_yY du monde en pixels entiers ; gardez-le inférieur à 2048 pour éviter le rebouclage.
Valeur renvoyée
1 si la tuile correspondante est solide, sinon 0.
Conditions et limites
Exige une carte valide et un tableau non vide accessible en lecture. Le caractère solide dépend d’un seuil d’identifiant de tuile, pas d’un masque de collision distinct.
Exemple d’utilisation
result[10]=nes_tilemap_world_point_solid(&map,16,8);result[11]=nes_tilemap_world_point_solid(&map,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
Placez la tuile solide 5 en (2,1) dans une carte de 5×3 : son indice de tableau est 7 et une lecture extérieure renvoie 255. Un coin touchant l’obstacle donne 1 ; un rectangle de 40×24 qui l’enferme seulement dans son intérieur donne 0, illustrant la limite du test des seuls coins.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_tilemap.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_tilemap.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/tilemap.h:29
Convert a world point to tile coordinates and apply the tile solidity rule.
kitaqfc/lib/tilemap.c:77
unsigned char nes_tilemap_world_point_solid(struct NesTilemap* map, unsigned short world_x, unsigned short world_y)
{
return nes_tilemap_point_solid(map, nes_world_to_tile8_x(world_x), nes_world_to_tile8_y(world_y));
}nes_world_to_tile8_x
Divise le X du monde par huit et le réduit à une coordonnée de tuile sur un octet.
Syntaxe
unsigned char nes_world_to_tile8_x(unsigned short world_x);Paramètres
world_xX du monde en pixels entiers ; gardez-le inférieur à 2048 pour éviter le rebouclage.
Valeur renvoyée
Les huit bits de poids faible de world_x >> 3 ; reboucle tous les 2048 pixels.
Conditions et limites
Exige une carte valide et un tableau non vide accessible en lecture. Le caractère solide dépend d’un seuil d’identifiant de tuile, pas d’un masque de collision distinct.
Exemple d’utilisation
result[6]=nes_world_to_tile8_x(23);result[7]=nes_world_to_tile8_x(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
Placez la tuile solide 5 en (2,1) dans une carte de 5×3 : son indice de tableau est 7 et une lecture extérieure renvoie 255. Un coin touchant l’obstacle donne 1 ; un rectangle de 40×24 qui l’enferme seulement dans son intérieur donne 0, illustrant la limite du test des seuls coins.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_tilemap.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_tilemap.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/tilemap.h:25
Convert pixels to eight-pixel tile X and narrow to a byte. Keep world X below 2048 when wraparound is not intended.
kitaqfc/lib/tilemap.c:65
unsigned char nes_world_to_tile8_x(unsigned short world_x)
{
return (unsigned char)(world_x >> 3);
}nes_world_to_tile8_y
Divise le Y du monde par huit et le réduit à une coordonnée de tuile sur un octet.
Syntaxe
unsigned char nes_world_to_tile8_y(unsigned short world_y);Paramètres
world_yY du monde en pixels entiers ; gardez-le inférieur à 2048 pour éviter le rebouclage.
Valeur renvoyée
Les huit bits de poids faible de world_y >> 3 ; reboucle tous les 2048 pixels.
Conditions et limites
Exige une carte valide et un tableau non vide accessible en lecture. Le caractère solide dépend d’un seuil d’identifiant de tuile, pas d’un masque de collision distinct.
Exemple d’utilisation
result[8]=nes_world_to_tile8_y(15);result[9]=nes_world_to_tile8_y(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
Placez la tuile solide 5 en (2,1) dans une carte de 5×3 : son indice de tableau est 7 et une lecture extérieure renvoie 255. Un coin touchant l’obstacle donne 1 ; un rectangle de 40×24 qui l’enferme seulement dans son intérieur donne 0, illustrant la limite du test des seuls coins.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\batch2_tilemap.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\batch2_tilemap.nes --no-cache --no-disasm --mapper=nrom --nes-chr=.\kitaq-docs\samples\font.chrImplémentation et source
kitaqfc/lib/tilemap.h:27
Convert pixels to eight-pixel tile Y with the same byte-coordinate limit.
kitaqfc/lib/tilemap.c:71
unsigned char nes_world_to_tile8_y(unsigned short world_y)
{
return (unsigned char)(world_y >> 3);
}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.
FC compte les octets d’ordres encodés dans un tampon intrinsèque fixe de 128 octets. Une écriture de tuile coûte 4 octets, un remplissage 5 et une copie par pointeur 6, métadonnées comprises. NMI peut consommer une file prête ; inspectez-la et construisez-la avant validation, en coordonnant production et consommation.
Valide la file intrinsèque avec __vramq_commit, puis attend le traitement NMI avec __nmi_wait. Le gestionnaire par défaut traite la file prête. Gardez NMI activée et son gestionnaire fonctionnel ; cet appel ne répartit pas un gros transfert sur plusieurs 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(void);Valeur renvoyée
Aucune (void).
Conditions et limites
FC compte les octets d’ordres encodés dans un tampon intrinsèque fixe de 128 octets. Une écriture de tuile coûte 4 octets, un remplissage 5 et une copie par pointeur 6, métadonnées comprises. NMI peut consommer une file prête ; inspectez-la et construisez-la avant validation, en coordonnant production et consommation.
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 FC, le rouge identifie les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank. Le bleu identifie le rectangle de 32 × 24 et la copie de deux motifs. Le vert identifie le bloc de 3 × 2 tuiles et la barre de 40 × 8. Le fond est noir ; la position et la couleur de chaque pixel dessiné sont vérifiées.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vram.h:15
Discard queued commands and explicitly reset the overflow latch.
kitaqfc/lib/vram.c:17
void vram_clear_queue(void)
{
__vramq_clear();
__vramq_clear_overflow();
}vram_flush
Valide la file intrinsèque avec __vramq_commit, puis attend le traitement NMI avec __nmi_wait. Le gestionnaire par défaut traite la file prête. Gardez NMI activée et son gestionnaire fonctionnel ; cet appel ne répartit pas un gros transfert sur plusieurs VBlank.
Syntaxe
void vram_flush(void);Valeur renvoyée
Aucune (void).
Conditions et limites
FC compte les octets d’ordres encodés dans un tampon intrinsèque fixe de 128 octets. Une écriture de tuile coûte 4 octets, un remplissage 5 et une copie par pointeur 6, métadonnées comprises. NMI peut consommer une file prête ; inspectez-la et construisez-la avant validation, en coordonnant production et consommation.
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 PPU en octets (0x0000–0x3FFF), et non pointeur CPU. La destination doit être inscriptible : modifier les motifs exige de la CHR RAM, pas de la CHR ROM. Le mappage et le mirroring PPU s’appliquent. Pour les copies et remplissages contigus, choisissez l’incrément 1 dans PPUCTRL. Exécutez à un instant sûr, puis rétablissez le défilement voulu ; l’exécuteur écrit PPUADDR et PPUDATA sans restaurer le défilement.
Exemple d’utilisation
vram_flush(); // One small write through the VBlank/NMI path.
__scroll_set(0,0);
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 FC, le rouge identifie les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank. Le bleu identifie le rectangle de 32 × 24 et la copie de deux motifs. Le vert identifie le bloc de 3 × 2 tuiles et la barre de 40 × 8. Le fond est noir ; la position et la couleur de chaque pixel dessiné sont vérifiées.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vram.h:41
Commit queued records for consumption and wait for the NMI path.
kitaqfc/lib/vram.c:115
void vram_flush(void)
{
__vramq_commit();
__nmi_wait();
}vram_flush_now
Appelle immédiatement __vramq_exec. L’exécution n’a lieu que si __vramq_commit a activé le drapeau prêt ; une file non validée reste intacte. À la fin, longueur et drapeau prêt sont effacés, mais pas le débordement. Cette fonction ne valide pas la file et n’attend pas un instant sûr pour la PPU.
Syntaxe
void vram_flush_now(void);Valeur renvoyée
Aucune (void).
Conditions et limites
FC compte les octets d’ordres encodés dans un tampon intrinsèque fixe de 128 octets. Une écriture de tuile coûte 4 octets, un remplissage 5 et une copie par pointeur 6, métadonnées comprises. NMI peut consommer une file prête ; inspectez-la et construisez-la avant validation, en coordonnant production et consommation.
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 PPU en octets (0x0000–0x3FFF), et non pointeur CPU. La destination doit être inscriptible : modifier les motifs exige de la CHR RAM, pas de la CHR ROM. Le mappage et le mirroring PPU s’appliquent. Pour les copies et remplissages contigus, choisissez l’incrément 1 dans PPUCTRL. Exécutez à un instant sûr, puis rétablissez le défilement voulu ; l’exécuteur écrit PPUADDR et PPUDATA sans restaurer le défilement.
Exemple d’utilisation
// Rendering is stopped here. On FC, commit readiness before direct execution.
__vramq_commit();
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 FC, le rouge identifie les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank. Le bleu identifie le rectangle de 32 × 24 et la copie de deux motifs. Le vert identifie le bloc de 3 × 2 tuiles et la barre de 40 × 8. Le fond est noir ; la position et la couleur de chaque pixel dessiné sont vérifiées.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vram.h:39
Invoke the queue executor directly. Its ready flag must already be set by commit, and the caller supplies appropriate PPU timing.
kitaqfc/lib/vram.c:109
void vram_flush_now(void)
{
__vramq_exec();
}vram_get_overflowed
Lit le drapeau de débordement sans l’effacer ; il peut conserver un échec antérieur.
Syntaxe
u8 vram_get_overflowed(void);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
FC compte les octets d’ordres encodés dans un tampon intrinsèque fixe de 128 octets. Une écriture de tuile coûte 4 octets, un remplissage 5 et une copie par pointeur 6, métadonnées comprises. NMI peut consommer une file prête ; inspectez-la et construisez-la avant validation, en coordonnant production et consommation.
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 FC, le rouge identifie les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank. Le bleu identifie le rectangle de 32 × 24 et la copie de deux motifs. Le vert identifie le bloc de 3 × 2 tuiles et la barre de 40 × 8. Le fond est noir ; la position et la couleur de chaque pixel dessiné sont vérifiées.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vram.h:52
Read the overflow latch without clearing it.
kitaqfc/lib/vram.c:144
u8 vram_get_overflowed(void)
{
return __vramq_overflow();
}vram_get_queue_capacity
Renvoie la capacité totale du tampon d’ordres, quelle que soit son occupation actuelle.
Syntaxe
u8 vram_get_queue_capacity(void);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
FC compte les octets d’ordres encodés dans un tampon intrinsèque fixe de 128 octets. Une écriture de tuile coûte 4 octets, un remplissage 5 et une copie par pointeur 6, métadonnées comprises. NMI peut consommer une file prête ; inspectez-la et construisez-la avant validation, en coordonnant production et consommation.
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 FC, le rouge identifie les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank. Le bleu identifie le rectangle de 32 × 24 et la copie de deux motifs. Le vert identifie le bloc de 3 × 2 tuiles et la barre de 40 × 8. Le fond est noir ; la position et la couleur de chaque pixel dessiné sont vérifiées.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vram.h:50
Return the queue's total capacity in bytes, independent of its current usage. This describes the command buffer, not free space in PPU VRAM.
kitaqfc/lib/vram.c:138
u8 vram_get_queue_capacity(void)
{
return __vramq_capacity();
}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(void);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
FC compte les octets d’ordres encodés dans un tampon intrinsèque fixe de 128 octets. Une écriture de tuile coûte 4 octets, un remplissage 5 et une copie par pointeur 6, métadonnées comprises. NMI peut consommer une file prête ; inspectez-la et construisez-la avant validation, en coordonnant production et consommation.
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 FC, le rouge identifie les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank. Le bleu identifie le rectangle de 32 × 24 et la copie de deux motifs. Le vert identifie le bloc de 3 × 2 tuiles et la barre de 40 × 8. Le fond est noir ; la position et la couleur de chaque pixel dessiné sont vérifiées.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vram.h:47
Return the remaining command-buffer capacity in bytes. A command requires space for its complete encoded record, including its address and metadata. Read before committing: NMI may consume a committed queue asynchronously.
kitaqfc/lib/vram.c:131
u8 vram_get_queue_free(void)
{
return (u8)(__vramq_capacity() - __vramq_len());
}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(void);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
FC compte les octets d’ordres encodés dans un tampon intrinsèque fixe de 128 octets. Une écriture de tuile coûte 4 octets, un remplissage 5 et une copie par pointeur 6, métadonnées comprises. NMI peut consommer une file prête ; inspectez-la et construisez-la avant validation, en coordonnant production et consommation.
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 FC, le rouge identifie les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank. Le bleu identifie le rectangle de 32 × 24 et la copie de deux motifs. Le vert identifie le bloc de 3 × 2 tuiles et la barre de 40 × 8. Le fond est noir ; la position et la couleur de chaque pixel dessiné sont vérifiées.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vram.h:43
Return the encoded queue length in bytes, not the number of commands.
kitaqfc/lib/vram.c:122
u8 vram_get_queue_used(void)
{
return __vramq_len();
}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(void);Valeur renvoyée
Aucune (void).
Conditions et limites
FC compte les octets d’ordres encodés dans un tampon intrinsèque fixe de 128 octets. Une écriture de tuile coûte 4 octets, un remplissage 5 et une copie par pointeur 6, métadonnées comprises. NMI peut consommer une file prête ; inspectez-la et construisez-la avant validation, en coordonnant production et consommation.
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 FC, le rouge identifie les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank. Le bleu identifie le rectangle de 32 × 24 et la copie de deux motifs. Le vert identifie le bloc de 3 × 2 tuiles et la barre de 40 × 8. Le fond est noir ; la position et la couleur de chaque pixel dessiné sont vérifiées.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vram.h:13
Clear the intrinsic queue and its overflow latch.
kitaqfc/lib/vram.c:10
void vram_init(void)
{
__vramq_clear();
__vramq_clear_overflow();
}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 utilisent
VRAM_NT_BASE, fixé par défaut à0x2000à la compilation. Le bloc utilise la base indiquée (0x2000,0x2400,0x2800ou0x2C00), avec le mirroring applicable. L’adresse est calculée à l’ajout, à raison de 32 octets par ligne. Restez dans la zone de 32 × 30 tuiles pour ne pas écraser les attributs.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 l’indicateur de débordement est effacé après la tentative, sinon 0. Un débordement ancien peut être signalé même si l’enregistrement actuel tient. Une opération à plusieurs enregistrements peut être partiellement ajoutée, sans annulation. Même une longueur nulle peut renvoyer 0 à cause d’un indicateur déjà actif.
Conditions et limites
FC compte les octets d’ordres encodés dans un tampon intrinsèque fixe de 128 octets. Une écriture de tuile coûte 4 octets, un remplissage 5 et une copie par pointeur 6, métadonnées comprises. NMI peut consommer une file prête ; inspectez-la et construisez-la avant validation, en coordonnant production et consommation.
Cet appel nécessite 6 * h octets de tampon pour enregistrer toute l’opération. La formule compte les enregistrements codés, métadonnées comprises, pas les données transférées. Vérifiez la place libre avant une opération à plusieurs enregistrements.
Les ordres de tuile et de rectangle utilisent VRAM_NT_BASE, fixé par défaut à 0x2000 à la compilation. Le bloc utilise la base indiquée (0x2000, 0x2400, 0x2800 ou 0x2C00), avec le mirroring applicable. L’adresse est calculée à l’ajout, à raison de 32 octets par ligne. Restez dans la zone de 32 × 30 tuiles pour ne pas écraser les attributs.
Chaque ligne utilise un enregistrement. Une hauteur nulle n’en ajoute aucun ; une largeur nulle en ajoute encore un par ligne, sans écrire d’octets. La coordonnée est convertie en u8 : y + row reboucle à 256. Aucun recadrage ni annulation des ajouts partiels.
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 FC, le rouge identifie les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank. Le bleu identifie le rectangle de 32 × 24 et la copie de deux motifs. Le vert identifie le bloc de 3 × 2 tuiles et la barre de 40 × 8. Le fond est noir ; la position et la couleur de chaque pixel dessiné sont vérifiées.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vram.h:27
Queue each tightly packed source row as a pointer-based copy record. Keep source storage and its ROM bank accessible until queue execution finishes; partial queuing remains possible on overflow.
kitaqfc/lib/vram.c:54
u8 vram_queue_bg_block(u16 base, u8 x, u8 y, u8 w, u8 h, const u8* src)
{
u8 row;
row = 0;
while (row < h) {
__vramq_copy(vram_xy_addr(base, x, (u8)(y + row)), src, w);
src = src + w;
row = (u8)(row + 1);
}
return (u8)(__vramq_overflow() == 0);
}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 l’indicateur de débordement est effacé après la tentative, sinon 0. Un débordement ancien peut être signalé même si l’enregistrement actuel tient. Une opération à plusieurs enregistrements peut être partiellement ajoutée, sans annulation. Même une longueur nulle peut renvoyer 0 à cause d’un indicateur déjà actif.
Conditions et limites
FC compte les octets d’ordres encodés dans un tampon intrinsèque fixe de 128 octets. Une écriture de tuile coûte 4 octets, un remplissage 5 et une copie par pointeur 6, métadonnées comprises. NMI peut consommer une file prête ; inspectez-la et construisez-la avant validation, en coordonnant production et consommation.
Cet appel nécessite 5 * h octets de tampon pour enregistrer toute l’opération. La formule compte les enregistrements codés, métadonnées comprises, pas les données transférées. Vérifiez la place libre avant une opération à plusieurs enregistrements.
Les ordres de tuile et de rectangle utilisent VRAM_NT_BASE, fixé par défaut à 0x2000 à la compilation. Le bloc utilise la base indiquée (0x2000, 0x2400, 0x2800 ou 0x2C00), avec le mirroring applicable. L’adresse est calculée à l’ajout, à raison de 32 octets par ligne. Restez dans la zone de 32 × 30 tuiles pour ne pas écraser les attributs.
Chaque ligne utilise un enregistrement. Une hauteur nulle n’en ajoute aucun ; une largeur nulle en ajoute encore un par ligne, sans écrire d’octets. La coordonnée est convertie en u8 : y + row reboucle à 256. Aucun recadrage ni annulation des ajouts partiels.
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 FC, le rouge identifie les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank. Le bleu identifie le rectangle de 32 × 24 et la copie de deux motifs. Le vert identifie le bloc de 3 × 2 tuiles et la barre de 40 × 8. Le fond est noir ; la position et la couleur de chaque pixel dessiné sont vérifiées.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vram.h:23
Queue one fill per row. This is not transactional: capacity exhaustion can leave earlier rows queued, and the loop continues attempting later rows.
kitaqfc/lib/vram.c:40
u8 vram_queue_bg_rect(u8 x, u8 y, u8 w, u8 h, u8 tile)
{
u8 row;
row = 0;
while (row < h) {
__vramq_fill(vram_xy_addr(VRAM_NT_BASE, x, (u8)(y + row)), tile, w);
row = (u8)(row + 1);
}
return (u8)(__vramq_overflow() == 0);
}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 l’indicateur de débordement est effacé après la tentative, sinon 0. Un débordement ancien peut être signalé même si l’enregistrement actuel tient. Une opération à plusieurs enregistrements peut être partiellement ajoutée, sans annulation. Même une longueur nulle peut renvoyer 0 à cause d’un indicateur déjà actif.
Conditions et limites
FC compte les octets d’ordres encodés dans un tampon intrinsèque fixe de 128 octets. Une écriture de tuile coûte 4 octets, un remplissage 5 et une copie par pointeur 6, métadonnées comprises. NMI peut consommer une file prête ; inspectez-la et construisez-la avant validation, en coordonnant production et consommation.
Cet appel nécessite 4 octets de tampon pour enregistrer toute l’opération. La formule compte les enregistrements codés, métadonnées comprises, pas les données transférées. Vérifiez la place libre avant une opération à plusieurs enregistrements.
Les ordres de tuile et de rectangle utilisent VRAM_NT_BASE, fixé par défaut à 0x2000 à la compilation. Le bloc utilise la base indiquée (0x2000, 0x2400, 0x2800 ou 0x2C00), avec le mirroring applicable. L’adresse est calculée à l’ajout, à raison de 32 octets par ligne. Restez dans la zone de 32 × 30 tuiles pour ne pas écraser les attributs.
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 FC, le rouge identifie les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank. Le bleu identifie le rectangle de 32 × 24 et la copie de deux motifs. Le vert identifie le bloc de 3 × 2 tuiles et la barre de 40 × 8. Le fond est noir ; la position et la couleur de chaque pixel dessiné sont vérifiées.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vram.h:18
Queue one tile at the default nametable base. Return the current overflow status, which may include a failure from an earlier operation.
kitaqfc/lib/vram.c:25
u8 vram_queue_bg_tile(u8 x, u8 y, u8 tile)
{
__vramq_put(vram_xy_addr(VRAM_NT_BASE, x, y), tile);
return (u8)(__vramq_overflow() == 0);
}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 PPU en octets (
0x0000–0x3FFF), et non pointeur CPU. La destination doit être inscriptible : modifier les motifs exige de la CHR RAM, pas de la CHR ROM. Le mappage et le mirroring PPU s’appliquent. Pour les copies et remplissages contigus, choisissez l’incrément 1 dans PPUCTRL. Exécutez à un instant sûr, puis rétablissez le défilement voulu ; l’exécuteur écrit PPUADDR et PPUDATA sans restaurer le défilement.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 l’indicateur de débordement est effacé après la tentative, sinon 0. Un débordement ancien peut être signalé même si l’enregistrement actuel tient. Une opération à plusieurs enregistrements peut être partiellement ajoutée, sans annulation. Même une longueur nulle peut renvoyer 0 à cause d’un indicateur déjà actif.
Conditions et limites
FC compte les octets d’ordres encodés dans un tampon intrinsèque fixe de 128 octets. Une écriture de tuile coûte 4 octets, un remplissage 5 et une copie par pointeur 6, métadonnées comprises. NMI peut consommer une file prête ; inspectez-la et construisez-la avant validation, en coordonnant production et consommation.
Cet appel nécessite 6 * ceil(len / 127) octets de tampon pour enregistrer toute l’opération. La formule compte les enregistrements codés, métadonnées comprises, pas les données transférées. Vérifiez la place libre avant une opération à plusieurs enregistrements.
Divise len en morceaux de 127 octets au plus ; ceil arrondit à l’entier supérieur. len=0 n’ajoute rien. Cette division appartient à la fonction de bibliothèque ; l’intrinsèque accepte un compte sur 8 bits non signés. Les tentatives continuent après débordement, sans annuler les enregistrements précédents.
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 FC, le rouge identifie les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank. Le bleu identifie le rectangle de 32 × 24 et la copie de deux motifs. Le vert identifie le bloc de 3 × 2 tuiles et la barre de 40 × 8. Le fond est noir ; la position et la couleur de chaque pixel dessiné sont vérifiées.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vram.h:31
Split a byte transfer into copy records of at most 127 bytes. The runtime retains source pointers rather than copying payloads into the queue. Return the overflow latch state after all records have been attempted.
kitaqfc/lib/vram.c:70
u8 vram_queue_memcpy(u16 dst, const void* src, u16 len)
{
const u8* p;
u8 chunk;
p = (const u8*)src;
while (len != 0) {
if (len > 127) chunk = 127;
else chunk = (u8)len;
__vramq_copy(dst, p, chunk);
dst = (u16)(dst + chunk);
p = p + chunk;
len = (u16)(len - chunk);
}
return (u8)(__vramq_overflow() == 0);
}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 PPU en octets (
0x0000–0x3FFF), et non pointeur CPU. La destination doit être inscriptible : modifier les motifs exige de la CHR RAM, pas de la CHR ROM. Le mappage et le mirroring PPU s’appliquent. Pour les copies et remplissages contigus, choisissez l’incrément 1 dans PPUCTRL. Exécutez à un instant sûr, puis rétablissez le défilement voulu ; l’exécuteur écrit PPUADDR et PPUDATA sans restaurer le défilement.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 l’indicateur de débordement est effacé après la tentative, sinon 0. Un débordement ancien peut être signalé même si l’enregistrement actuel tient. Une opération à plusieurs enregistrements peut être partiellement ajoutée, sans annulation. Même une longueur nulle peut renvoyer 0 à cause d’un indicateur déjà actif.
Conditions et limites
FC compte les octets d’ordres encodés dans un tampon intrinsèque fixe de 128 octets. Une écriture de tuile coûte 4 octets, un remplissage 5 et une copie par pointeur 6, métadonnées comprises. NMI peut consommer une file prête ; inspectez-la et construisez-la avant validation, en coordonnant production et consommation.
Cet appel nécessite 5 * ceil(len / 127) octets de tampon pour enregistrer toute l’opération. La formule compte les enregistrements codés, métadonnées comprises, pas les données transférées. Vérifiez la place libre avant une opération à plusieurs enregistrements.
Divise len en morceaux de 127 octets au plus ; ceil arrondit à l’entier supérieur. len=0 n’ajoute rien. Cette division appartient à la fonction de bibliothèque ; l’intrinsèque accepte un compte sur 8 bits non signés. Les tentatives continuent après débordement, sans annuler les enregistrements précédents.
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 FC, le rouge identifie les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank. Le bleu identifie le rectangle de 32 × 24 et la copie de deux motifs. Le vert identifie le bloc de 3 × 2 tuiles et la barre de 40 × 8. Le fond est noir ; la position et la couleur de chaque pixel dessiné sont vérifiées.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vram.h:36
Queue fills of at most 127 bytes each. Overflow can leave a partially queued transfer; no rollback is performed.
kitaqfc/lib/vram.c:94
u8 vram_queue_memset(u16 dst, u8 value, u16 len)
{
u8 chunk;
while (len != 0) {
if (len > 127) chunk = 127;
else chunk = (u8)len;
__vramq_fill(dst, value, chunk);
dst = (u16)(dst + chunk);
len = (u16)(len - chunk);
}
return (u8)(__vramq_overflow() == 0);
}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 l’indicateur de débordement est effacé après la tentative, sinon 0. Un débordement ancien peut être signalé même si l’enregistrement actuel tient. Une opération à plusieurs enregistrements peut être partiellement ajoutée, sans annulation. Même une longueur nulle peut renvoyer 0 à cause d’un indicateur déjà actif.
Conditions et limites
FC compte les octets d’ordres encodés dans un tampon intrinsèque fixe de 128 octets. Une écriture de tuile coûte 4 octets, un remplissage 5 et une copie par pointeur 6, métadonnées comprises. NMI peut consommer une file prête ; inspectez-la et construisez-la avant validation, en coordonnant production et consommation.
Cet appel nécessite 4 octets de tampon pour enregistrer toute l’opération. La formule compte les enregistrements codés, métadonnées comprises, pas les données transférées. Vérifiez la place libre avant une opération à plusieurs enregistrements.
Les ordres de tuile et de rectangle utilisent VRAM_NT_BASE, fixé par défaut à 0x2000 à la compilation. Le bloc utilise la base indiquée (0x2000, 0x2400, 0x2800 ou 0x2C00), avec le mirroring applicable. L’adresse est calculée à l’ajout, à raison de 32 octets par ligne. Restez dans la zone de 32 × 30 tuiles pour ne pas écraser les attributs.
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 FC, le rouge identifie les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank. Le bleu identifie le rectangle de 32 × 24 et la copie de deux motifs. Le vert identifie le bloc de 3 × 2 tuiles et la barre de 40 × 8. Le fond est noir ; la position et la couleur de chaque pixel dessiné sont vérifiées.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vram.h:20
Alias the queued background-tile operation.
kitaqfc/lib/vram.c:32
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 PPU en octets (
0x0000–0x3FFF), et non pointeur CPU. La destination doit être inscriptible : modifier les motifs exige de la CHR RAM, pas de la CHR ROM. Le mappage et le mirroring PPU s’appliquent. Pour les copies et remplissages contigus, choisissez l’incrément 1 dans PPUCTRL. Exécutez à un instant sûr, puis rétablissez le défilement voulu ; l’exécuteur écrit PPUADDR et PPUDATA sans restaurer le défilement.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 l’indicateur de débordement est effacé après la tentative, sinon 0. Un débordement ancien peut être signalé même si l’enregistrement actuel tient. Une opération à plusieurs enregistrements peut être partiellement ajoutée, sans annulation. Même une longueur nulle peut renvoyer 0 à cause d’un indicateur déjà actif.
Conditions et limites
FC compte les octets d’ordres encodés dans un tampon intrinsèque fixe de 128 octets. Une écriture de tuile coûte 4 octets, un remplissage 5 et une copie par pointeur 6, métadonnées comprises. NMI peut consommer une file prête ; inspectez-la et construisez-la avant validation, en coordonnant production et consommation.
Cet appel nécessite 6 * ceil(len / 127) octets de tampon pour enregistrer toute l’opération. La formule compte les enregistrements codés, métadonnées comprises, pas les données transférées. Vérifiez la place libre avant une opération à plusieurs enregistrements.
Divise len en morceaux de 127 octets au plus ; ceil arrondit à l’entier supérieur. len=0 n’ajoute rien. Cette division appartient à la fonction de bibliothèque ; l’intrinsèque accepte un compte sur 8 bits non signés. Les tentatives continuent après débordement, sans annuler les enregistrements précédents.
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 FC, le rouge identifie les deux carrés du haut, la copie de trois motifs et le dernier carré du VBlank. Le bleu identifie le rectangle de 32 × 24 et la copie de deux motifs. Le vert identifie le bloc de 3 × 2 tuiles et la barre de 40 × 8. Le fond est noir ; la position et la couleur de chaque pixel dessiné sont vérifiées.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\vram.c .\kitaq-docs\samples\api-examples\fc\vram_queue_shapes.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.nes --mapper=nrom --nes-chr=.\kitaq-docs\samples\api-examples\fc\vram_shapes.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vram.h:33
Alias the byte-copy queue helper; len remains a byte count, not a tile count.
kitaqfc/lib/vram.c:87
u8 vram_queue_tiles(u16 dst, const void* src, u16 len)
{
return vram_queue_memcpy(dst, src, len);
}vrc6_sound.h — Extension audio VRC6
Utilisez --mapper=vrc6 (mapper 24) pour ce câblage de registres. Une cartouche sans VRC6 ne peut pas produire ces voix. Seuls les 12 bits bas de period sont utilisés ; ces fonctions ne configurent pas le registre de fréquence $9003.
VRC6_PULSE_DUTY_12/25/50/75 désignent les valeurs 0x00/0x10/0x20/0x30. Leurs suffixes ne sont pas des pourcentages mesurés de rapport cyclique. KUROSAKI modélise le code d par (d+1)/16.
nes_vrc6_pulse1_off
Arrête l’impulsion VRC6 1 en effaçant son registre timer haut/activation.
Syntaxe
void nes_vrc6_pulse1_off(void);Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Utilisez --mapper=vrc6 (mapper 24) pour ce câblage de registres. Une cartouche sans VRC6 ne peut pas produire ces voix. Seuls les 12 bits bas de period sont utilisés ; ces fonctions ne configurent pas le registre de fréquence $9003.
Exemple d’utilisation
// Mapper 24: two pulse voices followed by the saw accumulator.
#include "fc_sound_example.h"
#include "vrc6_sound.c"
void main(void) {
// The background font occupies the first four 1 KiB CHR windows.
*((u8*)0xD000)=0; *((u8*)0xD001)=1;
*((u8*)0xD002)=2; *((u8*)0xD003)=3;
sound_begin("VRC6 PULSE PULSE SAW");
nes_vrc6_silence_all();
nes_vrc6_pulse1_set(0x7C,253);
sound_wait(45); nes_vrc6_pulse1_off(); sound_wait(15);
nes_vrc6_pulse2_set(0x3C,253);
sound_wait(45); nes_vrc6_pulse2_off(); sound_wait(15);
nes_vrc6_saw_set(32,289);
sound_wait(45); nes_vrc6_saw_off(); sound_wait(15);
nes_vrc6_silence_all();
sound_end();
}Résultat attendu
Écoutez l’impulsion VRC6 1, l’impulsion 2 avec un autre rapport cyclique, puis la dent de scie, chacune pendant 45 images avec 15 images de pause. Les trois hauteurs sont proches de 440 Hz et toutes les voix s’arrêtent à la fin.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_vrc6.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-vrc6.nes --mapper=vrc6 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vrc6_sound.h:22
Disable pulse 1 by clearing its high timer/enable register.
kitaqfc/lib/vrc6_sound.c:43
void nes_vrc6_pulse1_off(void)
{
VRC6_P1_HI = 0x00;
}nes_vrc6_pulse1_set
Écrit le contrôle et le timer de 12 bits de l’impulsion VRC6 1, puis l’active.
Syntaxe
void nes_vrc6_pulse1_set(u8 control, u16 period);Paramètres
controlContrôle d’impulsion VRC6 : bit 7 gate, bits 6..4 code de rapport cyclique, demi-octet bas volume 0..15.
periodTimer sur 12 bits, de 0 à 4095 ; les bits supérieurs sont ignorés. L’exemple utilise 253 pour l’impulsion et 289 pour la dent de scie.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Utilisez --mapper=vrc6 (mapper 24) pour ce câblage de registres. Une cartouche sans VRC6 ne peut pas produire ces voix. Seuls les 12 bits bas de period sont utilisés ; ces fonctions ne configurent pas le registre de fréquence $9003.
Exemple d’utilisation
// Mapper 24: two pulse voices followed by the saw accumulator.
#include "fc_sound_example.h"
#include "vrc6_sound.c"
void main(void) {
// The background font occupies the first four 1 KiB CHR windows.
*((u8*)0xD000)=0; *((u8*)0xD001)=1;
*((u8*)0xD002)=2; *((u8*)0xD003)=3;
sound_begin("VRC6 PULSE PULSE SAW");
nes_vrc6_silence_all();
nes_vrc6_pulse1_set(0x7C,253);
sound_wait(45); nes_vrc6_pulse1_off(); sound_wait(15);
nes_vrc6_pulse2_set(0x3C,253);
sound_wait(45); nes_vrc6_pulse2_off(); sound_wait(15);
nes_vrc6_saw_set(32,289);
sound_wait(45); nes_vrc6_saw_off(); sound_wait(15);
nes_vrc6_silence_all();
sound_end();
}Résultat attendu
Écoutez l’impulsion VRC6 1, l’impulsion 2 avec un autre rapport cyclique, puis la dent de scie, chacune pendant 45 images avec 15 images de pause. Les trois hauteurs sont proches de 440 Hz et toutes les voix s’arrêtent à la fin.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_vrc6.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-vrc6.nes --mapper=vrc6 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vrc6_sound.h:18
Write pulse-1 control and the low 12 timer bits, then enable the channel.
kitaqfc/lib/vrc6_sound.c:27
void nes_vrc6_pulse1_set(u8 control, u16 period)
{
VRC6_P1_CTRL = control;
VRC6_P1_LO = (u8)period;
VRC6_P1_HI = (u8)(0x80 | ((period >> 8) & 0x0F));
}nes_vrc6_pulse2_off
Arrête l’impulsion VRC6 2 en effaçant son registre timer haut/activation.
Syntaxe
void nes_vrc6_pulse2_off(void);Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Utilisez --mapper=vrc6 (mapper 24) pour ce câblage de registres. Une cartouche sans VRC6 ne peut pas produire ces voix. Seuls les 12 bits bas de period sont utilisés ; ces fonctions ne configurent pas le registre de fréquence $9003.
Exemple d’utilisation
// Mapper 24: two pulse voices followed by the saw accumulator.
#include "fc_sound_example.h"
#include "vrc6_sound.c"
void main(void) {
// The background font occupies the first four 1 KiB CHR windows.
*((u8*)0xD000)=0; *((u8*)0xD001)=1;
*((u8*)0xD002)=2; *((u8*)0xD003)=3;
sound_begin("VRC6 PULSE PULSE SAW");
nes_vrc6_silence_all();
nes_vrc6_pulse1_set(0x7C,253);
sound_wait(45); nes_vrc6_pulse1_off(); sound_wait(15);
nes_vrc6_pulse2_set(0x3C,253);
sound_wait(45); nes_vrc6_pulse2_off(); sound_wait(15);
nes_vrc6_saw_set(32,289);
sound_wait(45); nes_vrc6_saw_off(); sound_wait(15);
nes_vrc6_silence_all();
sound_end();
}Résultat attendu
Écoutez l’impulsion VRC6 1, l’impulsion 2 avec un autre rapport cyclique, puis la dent de scie, chacune pendant 45 images avec 15 images de pause. Les trois hauteurs sont proches de 440 Hz et toutes les voix s’arrêtent à la fin.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_vrc6.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-vrc6.nes --mapper=vrc6 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vrc6_sound.h:24
Disable pulse 2 by clearing its high timer/enable register.
kitaqfc/lib/vrc6_sound.c:49
void nes_vrc6_pulse2_off(void)
{
VRC6_P2_HI = 0x00;
}nes_vrc6_pulse2_set
Écrit le contrôle et le timer de 12 bits de l’impulsion VRC6 2, puis l’active.
Syntaxe
void nes_vrc6_pulse2_set(u8 control, u16 period);Paramètres
controlContrôle d’impulsion VRC6 : bit 7 gate, bits 6..4 code de rapport cyclique, demi-octet bas volume 0..15.
periodTimer sur 12 bits, de 0 à 4095 ; les bits supérieurs sont ignorés. L’exemple utilise 253 pour l’impulsion et 289 pour la dent de scie.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Utilisez --mapper=vrc6 (mapper 24) pour ce câblage de registres. Une cartouche sans VRC6 ne peut pas produire ces voix. Seuls les 12 bits bas de period sont utilisés ; ces fonctions ne configurent pas le registre de fréquence $9003.
Exemple d’utilisation
// Mapper 24: two pulse voices followed by the saw accumulator.
#include "fc_sound_example.h"
#include "vrc6_sound.c"
void main(void) {
// The background font occupies the first four 1 KiB CHR windows.
*((u8*)0xD000)=0; *((u8*)0xD001)=1;
*((u8*)0xD002)=2; *((u8*)0xD003)=3;
sound_begin("VRC6 PULSE PULSE SAW");
nes_vrc6_silence_all();
nes_vrc6_pulse1_set(0x7C,253);
sound_wait(45); nes_vrc6_pulse1_off(); sound_wait(15);
nes_vrc6_pulse2_set(0x3C,253);
sound_wait(45); nes_vrc6_pulse2_off(); sound_wait(15);
nes_vrc6_saw_set(32,289);
sound_wait(45); nes_vrc6_saw_off(); sound_wait(15);
nes_vrc6_silence_all();
sound_end();
}Résultat attendu
Écoutez l’impulsion VRC6 1, l’impulsion 2 avec un autre rapport cyclique, puis la dent de scie, chacune pendant 45 images avec 15 images de pause. Les trois hauteurs sont proches de 440 Hz et toutes les voix s’arrêtent à la fin.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_vrc6.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-vrc6.nes --mapper=vrc6 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vrc6_sound.h:20
Write pulse-2 control and the low 12 timer bits, then enable the channel.
kitaqfc/lib/vrc6_sound.c:35
void nes_vrc6_pulse2_set(u8 control, u16 period)
{
VRC6_P2_CTRL = control;
VRC6_P2_LO = (u8)period;
VRC6_P2_HI = (u8)(0x80 | ((period >> 8) & 0x0F));
}nes_vrc6_saw_off
Arrête la dent de scie VRC6 en effaçant son registre timer haut/activation.
Syntaxe
void nes_vrc6_saw_off(void);Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Utilisez --mapper=vrc6 (mapper 24) pour ce câblage de registres. Une cartouche sans VRC6 ne peut pas produire ces voix. Seuls les 12 bits bas de period sont utilisés ; ces fonctions ne configurent pas le registre de fréquence $9003.
Exemple d’utilisation
// Mapper 24: two pulse voices followed by the saw accumulator.
#include "fc_sound_example.h"
#include "vrc6_sound.c"
void main(void) {
// The background font occupies the first four 1 KiB CHR windows.
*((u8*)0xD000)=0; *((u8*)0xD001)=1;
*((u8*)0xD002)=2; *((u8*)0xD003)=3;
sound_begin("VRC6 PULSE PULSE SAW");
nes_vrc6_silence_all();
nes_vrc6_pulse1_set(0x7C,253);
sound_wait(45); nes_vrc6_pulse1_off(); sound_wait(15);
nes_vrc6_pulse2_set(0x3C,253);
sound_wait(45); nes_vrc6_pulse2_off(); sound_wait(15);
nes_vrc6_saw_set(32,289);
sound_wait(45); nes_vrc6_saw_off(); sound_wait(15);
nes_vrc6_silence_all();
sound_end();
}Résultat attendu
Écoutez l’impulsion VRC6 1, l’impulsion 2 avec un autre rapport cyclique, puis la dent de scie, chacune pendant 45 images avec 15 images de pause. Les trois hauteurs sont proches de 440 Hz et toutes les voix s’arrêtent à la fin.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_vrc6.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-vrc6.nes --mapper=vrc6 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vrc6_sound.h:28
Disable the saw channel by clearing its high timer/enable register.
kitaqfc/lib/vrc6_sound.c:63
void nes_vrc6_saw_off(void)
{
VRC6_SAW_HI = 0x00;
}nes_vrc6_saw_set
Écrit le taux d’accumulation de 6 bits et le timer de 12 bits de la dent de scie VRC6, puis l’active.
Syntaxe
void nes_vrc6_saw_set(u8 rate, u16 period);Paramètres
rateIncrément de l’accumulateur en dents de scie, de 0 à 63 ; seuls les six bits bas sont utilisés.
periodTimer sur 12 bits, de 0 à 4095 ; les bits supérieurs sont ignorés. L’exemple utilise 253 pour l’impulsion et 289 pour la dent de scie.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Utilisez --mapper=vrc6 (mapper 24) pour ce câblage de registres. Une cartouche sans VRC6 ne peut pas produire ces voix. Seuls les 12 bits bas de period sont utilisés ; ces fonctions ne configurent pas le registre de fréquence $9003.
Exemple d’utilisation
// Mapper 24: two pulse voices followed by the saw accumulator.
#include "fc_sound_example.h"
#include "vrc6_sound.c"
void main(void) {
// The background font occupies the first four 1 KiB CHR windows.
*((u8*)0xD000)=0; *((u8*)0xD001)=1;
*((u8*)0xD002)=2; *((u8*)0xD003)=3;
sound_begin("VRC6 PULSE PULSE SAW");
nes_vrc6_silence_all();
nes_vrc6_pulse1_set(0x7C,253);
sound_wait(45); nes_vrc6_pulse1_off(); sound_wait(15);
nes_vrc6_pulse2_set(0x3C,253);
sound_wait(45); nes_vrc6_pulse2_off(); sound_wait(15);
nes_vrc6_saw_set(32,289);
sound_wait(45); nes_vrc6_saw_off(); sound_wait(15);
nes_vrc6_silence_all();
sound_end();
}Résultat attendu
Écoutez l’impulsion VRC6 1, l’impulsion 2 avec un autre rapport cyclique, puis la dent de scie, chacune pendant 45 images avec 15 images de pause. Les trois hauteurs sont proches de 440 Hz et toutes les voix s’arrêtent à la fin.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_vrc6.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-vrc6.nes --mapper=vrc6 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vrc6_sound.h:26
Mask the saw accumulation rate to six bits, load a 12-bit timer and enable output.
kitaqfc/lib/vrc6_sound.c:55
void nes_vrc6_saw_set(u8 rate, u16 period)
{
VRC6_SAW_RATE = (u8)(rate & 0x3F);
VRC6_SAW_LO = (u8)period;
VRC6_SAW_HI = (u8)(0x80 | ((period >> 8) & 0x0F));
}nes_vrc6_silence_all
Désactive les trois voix VRC6 et efface les contrôles d’impulsion et le taux de dent de scie.
Syntaxe
void nes_vrc6_silence_all(void);Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Utilisez --mapper=vrc6 (mapper 24) pour ce câblage de registres. Une cartouche sans VRC6 ne peut pas produire ces voix. Seuls les 12 bits bas de period sont utilisés ; ces fonctions ne configurent pas le registre de fréquence $9003.
Exemple d’utilisation
// Mapper 24: two pulse voices followed by the saw accumulator.
#include "fc_sound_example.h"
#include "vrc6_sound.c"
void main(void) {
// The background font occupies the first four 1 KiB CHR windows.
*((u8*)0xD000)=0; *((u8*)0xD001)=1;
*((u8*)0xD002)=2; *((u8*)0xD003)=3;
sound_begin("VRC6 PULSE PULSE SAW");
nes_vrc6_silence_all();
nes_vrc6_pulse1_set(0x7C,253);
sound_wait(45); nes_vrc6_pulse1_off(); sound_wait(15);
nes_vrc6_pulse2_set(0x3C,253);
sound_wait(45); nes_vrc6_pulse2_off(); sound_wait(15);
nes_vrc6_saw_set(32,289);
sound_wait(45); nes_vrc6_saw_off(); sound_wait(15);
nes_vrc6_silence_all();
sound_end();
}Résultat attendu
Écoutez l’impulsion VRC6 1, l’impulsion 2 avec un autre rapport cyclique, puis la dent de scie, chacune pendant 45 images avec 15 images de pause. Les trois hauteurs sont proches de 440 Hz et toutes les voix s’arrêtent à la fin.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_vrc6.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-vrc6.nes --mapper=vrc6 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vrc6_sound.h:16
Clear channel-enable/high-timer registers and output controls for all VRC6 voices. Requires the VRC6 register layout used by this module. No mapper setup or global frequency-control write is included.
kitaqfc/lib/vrc6_sound.c:16
void nes_vrc6_silence_all(void)
{
VRC6_P1_HI = 0x00;
VRC6_P2_HI = 0x00;
VRC6_SAW_HI = 0x00;
VRC6_P1_CTRL = 0x00;
VRC6_P2_CTRL = 0x00;
VRC6_SAW_RATE = 0x00;
}vrc7_sound.h — Audio FM VRC7
Pour --mapper=vrc7 (mapper 85). Protégez les paires sélection de registre/donnée contre les écritures d’interruption intercalées. Aucun délai de stabilisation du périphérique n’est ajouté. Les enregistrements capturent le modèle FM de KUROSAKI, pas une vérification du timbre ou du minutage matériel.
nes_vrc7_channel_set
Configure fréquence, bloc, indicateurs de touche, instrument et atténuation d’une voix FM.
Syntaxe
void nes_vrc7_channel_set(u8 channel, u8 instrument, u8 volume, u16 fnum, u8 block, u8 key_flags);Paramètres
channelCanal VRC7 de 0 à 5 ; les valeurs supérieures n’ont aucun effet.
instrumentInstrument de 0 à 15 : 0=son utilisateur, 1..15=préréglages. Seul le demi-octet bas est utilisé.
volumeAtténuation VRC7 de 0 à 15 : 0 est le plus fort, 15 l’atténuation maximale. Seul le demi-octet bas est utilisé.
fnumNombre de fréquence de 0 à 511, combiné à block pour déterminer la hauteur. Seuls neuf bits sont utilisés.
blockBloc d’octave de 0 à 7 ; seuls les trois bits bas sont utilisés.
key_flags0x10 déclenche la note, 0x20 active l’indicateur de maintien ; les autres bits sont ignorés.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Pour --mapper=vrc7 (mapper 85). Protégez les paires sélection de registre/donnée contre les écritures d’interruption intercalées. Aucun délai de stabilisation du périphérique n’est ajouté. Les enregistrements capturent le modèle FM de KUROSAKI, pas une vérification du timbre ou du minutage matériel.
L’instrument 0 est partagé par toutes les voix. channel_set écrit touche/fréquence haute avant instrument/atténuation. Après key_off, la note suivante doit aussi restaurer fréquence haute et bloc.
Exemple d’utilisation
// Mapper 85: an FM preset followed by a simple original user instrument.
#include "fc_sound_example.h"
#include "vrc7_sound.c"
__prg_rom u8 patch[8]={0x21,0x21,0x3F,0x00,0xF0,0xF0,0x0F,0x0F};
void main(void) {
// Map the supplied 8 KiB font as eight consecutive 1 KiB CHR windows.
*((u8*)0xA000)=0; *((u8*)0xA010)=1;
*((u8*)0xB000)=2; *((u8*)0xB010)=3;
*((u8*)0xC000)=4; *((u8*)0xC010)=5;
*((u8*)0xD000)=6; *((u8*)0xD010)=7;
sound_begin("VRC7 PRESET AND PATCH");
nes_vrc7_silence_all();
nes_vrc7_channel_set(0,1,3,290,4,VRC7_KEY_ON);
sound_wait(60); nes_vrc7_key_off(0); sound_wait(30);
nes_vrc7_set_user_patch(patch);
nes_vrc7_channel_set(0,0,3,290,4,VRC7_KEY_ON);
sound_wait(60);
// Raw register 30 selects instrument zero and maximum attenuation.
nes_vrc7_write(0x30,0x0F);
nes_vrc7_key_off(0);
nes_vrc7_silence_all(); sound_wait(30);
sound_end();
}Résultat attendu
Comparez l’instrument préréglé 1 à un instrument utilisateur original 0 à son tenu, chacun pendant 60 images à la même hauteur. La séquence se termine par l’arrêt de note et l’atténuation maximale.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_vrc7.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-vrc7.nes --mapper=vrc7 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vrc7_sound.h:18
Validate channel 0..5, then pack a 9-bit frequency, 3-bit block, key flags, instrument and volume nibbles into its registers. Volume is the raw hardware attenuation field, not a linear loudness value.
kitaqfc/lib/vrc7_sound.c:32
void nes_vrc7_channel_set(u8 channel, u8 instrument, u8 volume, u16 fnum, u8 block, u8 key_flags)
{
u8 reg;
u8 hi;
if (channel >= 6) return;
reg = channel;
hi = (u8)(((fnum >> 8) & 0x01) | ((block & 0x07) << 1) | (key_flags & 0x30));
nes_vrc7_write((u8)(0x10 + reg), (u8)fnum);
// Key/frequency-high is written before instrument/attenuation; this sequence is not an atomic note update.
nes_vrc7_write((u8)(0x20 + reg), hi);
nes_vrc7_write((u8)(0x30 + reg), (u8)(((instrument & 0x0F) << 4) | (volume & 0x0F)));
}nes_vrc7_key_off
Efface tout le registre fréquence haute/bloc/touche de la voix sélectionnée.
Syntaxe
void nes_vrc7_key_off(u8 channel);Paramètres
channelCanal VRC7 de 0 à 5 ; les valeurs supérieures n’ont aucun effet.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Pour --mapper=vrc7 (mapper 85). Protégez les paires sélection de registre/donnée contre les écritures d’interruption intercalées. Aucun délai de stabilisation du périphérique n’est ajouté. Les enregistrements capturent le modèle FM de KUROSAKI, pas une vérification du timbre ou du minutage matériel.
L’instrument 0 est partagé par toutes les voix. channel_set écrit touche/fréquence haute avant instrument/atténuation. Après key_off, la note suivante doit aussi restaurer fréquence haute et bloc.
Exemple d’utilisation
// Mapper 85: an FM preset followed by a simple original user instrument.
#include "fc_sound_example.h"
#include "vrc7_sound.c"
__prg_rom u8 patch[8]={0x21,0x21,0x3F,0x00,0xF0,0xF0,0x0F,0x0F};
void main(void) {
// Map the supplied 8 KiB font as eight consecutive 1 KiB CHR windows.
*((u8*)0xA000)=0; *((u8*)0xA010)=1;
*((u8*)0xB000)=2; *((u8*)0xB010)=3;
*((u8*)0xC000)=4; *((u8*)0xC010)=5;
*((u8*)0xD000)=6; *((u8*)0xD010)=7;
sound_begin("VRC7 PRESET AND PATCH");
nes_vrc7_silence_all();
nes_vrc7_channel_set(0,1,3,290,4,VRC7_KEY_ON);
sound_wait(60); nes_vrc7_key_off(0); sound_wait(30);
nes_vrc7_set_user_patch(patch);
nes_vrc7_channel_set(0,0,3,290,4,VRC7_KEY_ON);
sound_wait(60);
// Raw register 30 selects instrument zero and maximum attenuation.
nes_vrc7_write(0x30,0x0F);
nes_vrc7_key_off(0);
nes_vrc7_silence_all(); sound_wait(30);
sound_end();
}Résultat attendu
Comparez l’instrument préréglé 1 à un instrument utilisateur original 0 à son tenu, chacun pendant 60 images à la même hauteur. La séquence se termine par l’arrêt de note et l’atténuation maximale.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_vrc7.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-vrc7.nes --mapper=vrc7 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vrc7_sound.h:21
Clear the channel's entire frequency-high/block/key register, not just the key-on bit. A later note must restore frequency and block settings.
kitaqfc/lib/vrc7_sound.c:47
void nes_vrc7_key_off(u8 channel)
{
if (channel >= 6) return;
nes_vrc7_write((u8)(0x20 + channel), 0x00);
}nes_vrc7_set_user_patch
Écrit huit octets dans l’ordre dans les registres d’instrument utilisateur VRC7.
Syntaxe
void nes_vrc7_set_user_patch(const u8* patch8);Paramètres
patch8Huit octets définissant l’instrument 0. NULL n’est pas vérifié. Gardez la banque source mappée pendant l’appel.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Pour --mapper=vrc7 (mapper 85). Protégez les paires sélection de registre/donnée contre les écritures d’interruption intercalées. Aucun délai de stabilisation du périphérique n’est ajouté. Les enregistrements capturent le modèle FM de KUROSAKI, pas une vérification du timbre ou du minutage matériel.
L’instrument 0 est partagé par toutes les voix. channel_set écrit touche/fréquence haute avant instrument/atténuation. Après key_off, la note suivante doit aussi restaurer fréquence haute et bloc.
Exemple d’utilisation
// Mapper 85: an FM preset followed by a simple original user instrument.
#include "fc_sound_example.h"
#include "vrc7_sound.c"
__prg_rom u8 patch[8]={0x21,0x21,0x3F,0x00,0xF0,0xF0,0x0F,0x0F};
void main(void) {
// Map the supplied 8 KiB font as eight consecutive 1 KiB CHR windows.
*((u8*)0xA000)=0; *((u8*)0xA010)=1;
*((u8*)0xB000)=2; *((u8*)0xB010)=3;
*((u8*)0xC000)=4; *((u8*)0xC010)=5;
*((u8*)0xD000)=6; *((u8*)0xD010)=7;
sound_begin("VRC7 PRESET AND PATCH");
nes_vrc7_silence_all();
nes_vrc7_channel_set(0,1,3,290,4,VRC7_KEY_ON);
sound_wait(60); nes_vrc7_key_off(0); sound_wait(30);
nes_vrc7_set_user_patch(patch);
nes_vrc7_channel_set(0,0,3,290,4,VRC7_KEY_ON);
sound_wait(60);
// Raw register 30 selects instrument zero and maximum attenuation.
nes_vrc7_write(0x30,0x0F);
nes_vrc7_key_off(0);
nes_vrc7_silence_all(); sound_wait(30);
sound_end();
}Résultat attendu
Comparez l’instrument préréglé 1 à un instrument utilisateur original 0 à son tenu, chacun pendant 60 images à la même hauteur. La séquence se termine par l’arrêt de note et l’atténuation maximale.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_vrc7.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-vrc7.nes --mapper=vrc7 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vrc7_sound.h:14
Copy eight caller-supplied patch bytes into user-instrument registers 0..7.
kitaqfc/lib/vrc7_sound.c:16
void nes_vrc7_set_user_patch(const u8* patch8)
{
const u8* p;
u8 i;
p = patch8;
i = 0;
while (i < 8) {
nes_vrc7_write(i, *p);
p = p + 1;
i = (u8)(i + 1);
}
}nes_vrc7_silence_all
Arrête les notes des six voix et sélectionne l’instrument 0 à atténuation maximale.
Syntaxe
void nes_vrc7_silence_all(void);Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Pour --mapper=vrc7 (mapper 85). Protégez les paires sélection de registre/donnée contre les écritures d’interruption intercalées. Aucun délai de stabilisation du périphérique n’est ajouté. Les enregistrements capturent le modèle FM de KUROSAKI, pas une vérification du timbre ou du minutage matériel.
L’instrument 0 est partagé par toutes les voix. channel_set écrit touche/fréquence haute avant instrument/atténuation. Après key_off, la note suivante doit aussi restaurer fréquence haute et bloc.
Exemple d’utilisation
// Mapper 85: an FM preset followed by a simple original user instrument.
#include "fc_sound_example.h"
#include "vrc7_sound.c"
__prg_rom u8 patch[8]={0x21,0x21,0x3F,0x00,0xF0,0xF0,0x0F,0x0F};
void main(void) {
// Map the supplied 8 KiB font as eight consecutive 1 KiB CHR windows.
*((u8*)0xA000)=0; *((u8*)0xA010)=1;
*((u8*)0xB000)=2; *((u8*)0xB010)=3;
*((u8*)0xC000)=4; *((u8*)0xC010)=5;
*((u8*)0xD000)=6; *((u8*)0xD010)=7;
sound_begin("VRC7 PRESET AND PATCH");
nes_vrc7_silence_all();
nes_vrc7_channel_set(0,1,3,290,4,VRC7_KEY_ON);
sound_wait(60); nes_vrc7_key_off(0); sound_wait(30);
nes_vrc7_set_user_patch(patch);
nes_vrc7_channel_set(0,0,3,290,4,VRC7_KEY_ON);
sound_wait(60);
// Raw register 30 selects instrument zero and maximum attenuation.
nes_vrc7_write(0x30,0x0F);
nes_vrc7_key_off(0);
nes_vrc7_silence_all(); sound_wait(30);
sound_end();
}Résultat attendu
Comparez l’instrument préréglé 1 à un instrument utilisateur original 0 à son tenu, chacun pendant 60 images à la même hauteur. La séquence se termine par l’arrêt de note et l’atténuation maximale.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_vrc7.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-vrc7.nes --mapper=vrc7 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vrc7_sound.h:23
Key off all six voices and set instrument zero with maximum attenuation.
kitaqfc/lib/vrc7_sound.c:54
void nes_vrc7_silence_all(void)
{
u8 i;
i = 0;
while (i < 6) {
nes_vrc7_key_off(i);
nes_vrc7_write((u8)(0x30 + i), 0x0F);
i = (u8)(i + 1);
}
}nes_vrc7_write
Écrit le numéro de registre au port de sélection VRC7, puis sa valeur au port de données.
Syntaxe
void nes_vrc7_write(u8 reg, u8 value);Paramètres
regNuméro de registre VRC7. Pour le canal 0 : 0x10 fréquence basse, 0x20 haute/bloc/touche, 0x30 instrument/atténuation.
valueOctet à écrire dans le registre VRC7 sélectionné.
Valeur renvoyée
Aucune valeur de retour. Modifie les registres audio ou l’état du pilote.
Conditions et limites
Pour --mapper=vrc7 (mapper 85). Protégez les paires sélection de registre/donnée contre les écritures d’interruption intercalées. Aucun délai de stabilisation du périphérique n’est ajouté. Les enregistrements capturent le modèle FM de KUROSAKI, pas une vérification du timbre ou du minutage matériel.
L’instrument 0 est partagé par toutes les voix. channel_set écrit touche/fréquence haute avant instrument/atténuation. Après key_off, la note suivante doit aussi restaurer fréquence haute et bloc.
Exemple d’utilisation
// Mapper 85: an FM preset followed by a simple original user instrument.
#include "fc_sound_example.h"
#include "vrc7_sound.c"
__prg_rom u8 patch[8]={0x21,0x21,0x3F,0x00,0xF0,0xF0,0x0F,0x0F};
void main(void) {
// Map the supplied 8 KiB font as eight consecutive 1 KiB CHR windows.
*((u8*)0xA000)=0; *((u8*)0xA010)=1;
*((u8*)0xB000)=2; *((u8*)0xB010)=3;
*((u8*)0xC000)=4; *((u8*)0xC010)=5;
*((u8*)0xD000)=6; *((u8*)0xD010)=7;
sound_begin("VRC7 PRESET AND PATCH");
nes_vrc7_silence_all();
nes_vrc7_channel_set(0,1,3,290,4,VRC7_KEY_ON);
sound_wait(60); nes_vrc7_key_off(0); sound_wait(30);
nes_vrc7_set_user_patch(patch);
nes_vrc7_channel_set(0,0,3,290,4,VRC7_KEY_ON);
sound_wait(60);
// Raw register 30 selects instrument zero and maximum attenuation.
nes_vrc7_write(0x30,0x0F);
nes_vrc7_key_off(0);
nes_vrc7_silence_all(); sound_wait(30);
sound_end();
}Résultat attendu
Comparez l’instrument préréglé 1 à un instrument utilisateur original 0 à son tenu, chacun pendant 60 images à la même hauteur. La séquence se termine par l’arrêt de note et l’atténuation maximale.

Commande de compilation
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\sound_vrc7.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\fc-vrc7.nes --mapper=vrc7 --nes-chr=.\kitaq-docs\samples\font.chr --no-cache --no-disasmImplémentation et source
kitaqfc/lib/vrc7_sound.h:12
Write register selection followed immediately by data. No explicit device settling delay or cartridge detection is inserted by this wrapper. The caller must arrange device timing and serialize register/data pairs against interrupt writers.
kitaqfc/lib/vrc7_sound.c:8
void nes_vrc7_write(u8 reg, u8 value)
{
VRC7_ADDR = reg;
VRC7_DATA = value;
}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.
actor.h — Tableaux d'acteurs du jeu
/*
* Optional declarations for the phase 11 actor helper.
*/
// Callers initialize size and metadata and pass non-null actors.
// attr/flags are retained fields; this helper does not interpret or apply them.
struct NesActor {
unsigned short world_x;
unsigned short world_y;
unsigned char width;
unsigned char height;
unsigned char screen_x;
unsigned char screen_y;
unsigned char attr;
unsigned char flags;
};
// Set the actor's 16-bit world position without updating cached screen coordinates.
void nes_actor_set_world(struct NesActor* actor, unsigned short x, unsigned short y);
// Subtract the camera and retain only the low coordinate bytes. This performs
// wrapping projection, not clipping; callers must hide actors outside the viewport.
void nes_actor_update_screen(struct NesActor* actor, unsigned short camera_x, unsigned short camera_y);
// Draw the byte-stream metasprite at cached screen coordinates and return its
// next OAM index. Actor attr/flags are not applied by this wrapper.
unsigned char nes_actor_draw_metasprite(struct NesActor* actor, unsigned char oam_index, unsigned char* metasprite);
// Test overlap in world coordinates with exclusive right/bottom edges. Keep
// position-plus-size sums within u16; touching edges are not collisions.
// Require positive widths and heights; zero extents are not rejected before the edge tests.
unsigned char nes_actor_collide(struct NesActor* a, struct NesActor* b);kitaqfc/lib/actor.h
asset.h — Identifiants de ressources et descripteurs de données
#ifndef ASSET_H
#define ASSET_H
#include "core.h"
#include "bank.h"
#define ASSET_TYPE_RAW ((u8)0)
#define ASSET_TYPE_TILES ((u8)1)
#define ASSET_TYPE_MAP ((u8)2)
#define ASSET_TYPE_SONG ((u8)3)
// The descriptor table bank and each payload bank are independent.
// ptr is a CPU-visible address and len counts bytes; type is a tag, not a decoder selection.
typedef __packed struct AssetDesc {
u8 type;
u8 bank;
const u8* ptr;
u16 len;
} AssetDesc;
// Retain a bank-qualified descriptor table; the caller keeps its storage valid.
void asset_set_table(u8 bank, const AssetDesc* table, u8 count);
// Copy a descriptor from its ROM bank into caller storage. Null output or an
// out-of-range ID returns zero without reading the table.
u8 asset_get(u8 asset_id, AssetDesc* out_desc);
// Copy the smaller of the asset length and max_len using a bank-aware transfer.
// Return one for a valid ID even when the payload is truncated.
u8 asset_load_raw(u8 asset_id, void* dst, u16 max_len);
// Switch to the asset bank, upload tile/raw data in chunks of at most 128 bytes,
// then restore the bank recorded by this library. The caller supplies safe PPU timing.
u8 asset_load_tiles(u8 asset_id, u16 vram_dst);
// Return the asset bank or zero on lookup failure; bank zero may also be valid.
u8 asset_get_bank(u8 asset_id);
// Return the stored address without switching banks. Pair it with the descriptor
// bank before reading banked ROM; a failed lookup returns null.
const u8* asset_get_ptr(u8 asset_id);
// Return the descriptor byte length, or zero for an invalid ID.
u16 asset_get_len(u8 asset_id);
#endifkitaqfc/lib/asset.h
attribute.h — Attributs des tables de noms
/*
* KITAQFC phase15 attribute patch helpers.
*/
// Copy 64 already-packed attribute bytes into shadow storage. This does not
// convert one palette ID per tile into NES attribute bitfields.
// The source must expose all 64 packed bytes and stay readable for the duration of this copy.
void nes_attr_shadow_build_from_palette_map(unsigned char* src64);
// Apply a palette to every two-by-two tile quadrant touched by the rectangle.
// Empty or out-of-range rectangles leave the shadow unchanged.
void nes_attr_shadow_fill_rect(unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height, unsigned char pal_index);
// Queue the attribute bytes covering a tile rectangle within 32x30 tiles.
// Empty rectangles succeed; invalid bounds fail without queuing.
// Capacity failure may leave earlier rows queued.
unsigned char nes_attr_queue_rect(unsigned short nt_base, unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height);kitaqfc/lib/attribute.h
audio.h — Musique, effets sonores et commandes audio
#ifndef AUDIO_H
#define AUDIO_H
#include "core.h"
// Channel bits form a complete replacement mask for nes_apu_channel_enable.
#define NES_APU_ENABLE_PULSE1 0x01
#define NES_APU_ENABLE_PULSE2 0x02
#define NES_APU_ENABLE_TRIANGLE 0x04
#define NES_APU_ENABLE_NOISE 0x08
#define NES_APU_ENABLE_DMC 0x10
// Disable frame IRQs, enable the four tonal/noise channels and install quiet
// control defaults. DMC remains disabled.
void nes_apu_init(void);
// Replace all five channel-enable bits in APU_STATUS; this is not an additive enable.
void nes_apu_channel_enable(u8 mask);
// Disable every channel and clear volume/DMC output settings used by this helper.
void nes_apu_silence_all(void);
// Enable only pulse 1, disable its sweep and load control, 11-bit timer and
// length-table index. Starting this effect disables the other APU channels.
void nes_sfx_square1(u8 duty_volume, u16 period, u8 length_index);
// Enable only pulse 2 and load its control/timer/length fields, disabling other channels.
void nes_sfx_square2(u8 duty_volume, u16 period, u8 length_index);
// Enable only triangle and load linear-counter, timer and length fields.
void nes_sfx_triangle(u8 linear, u16 period, u8 length_index);
// Enable only noise and load envelope/control, period/mode and length fields.
void nes_sfx_noise(u8 volume, u8 period_mode, u8 length_index);
// Trigger the predefined pulse-1 tick effect; it inherits the exclusive-channel behavior.
void nes_sfx_tick_blip(void);
// Trigger the predefined pulse-1 movement effect.
void nes_sfx_move_blip(void);
// Convert a CPU sample address and byte length to DMC register units. Supply
// an address in 0xC000-0xFFC0 aligned to 64 bytes and a representable length
// 16*n+1 in 1..4081; inputs are narrowed without validation or bank management.
void nes_dmc_config(u8 flags_rate, u8 output_level, u16 sample_addr, u16 sample_len);
// Enable DMC together with all four other channels by replacing the status mask.
void nes_dmc_start(void);
// Disable DMC while leaving all four other channel-enable bits set.
void nes_dmc_stop(void);
// Install sample parameters, then start DMC using the full-channel enable mask.
void nes_dmc_play(u8 flags_rate, u8 output_level, u16 sample_addr, u16 sample_len);
#endifkitaqfc/lib/audio.h
audio_vblank.h — Lecture musicale par interruption VBlank
#ifndef NES_AUDIO_VBLANK_H
#define NES_AUDIO_VBLANK_H
#include "core.h"
// Original MIT-licensed NMI sequencer. Channel order follows the physical APU:
// CH1 pulse 1, CH2 pulse 2, CH3 triangle, CH4 noise (indices 0, 1, 2, 3).
// Every record is five bytes: delay, CH1, CH2, CH3, CH4.
// Delay 1..255 holds the new state for that many NMI ticks. Delay 0 ends playback.
// Tonal notes 0..71 are C2..B7, tuned for NTSC. Noise 0..15 selects a long-mode
// period; 16..31 selects short mode. HOLD preserves a channel; STOP silences it.
#define NES_AUDIO_NOISE_ENVELOPE 128
#define NES_AUDIO_HOLD 255
#define NES_AUDIO_STOP 254
#define NES_AUDIO_RECORD_BYTES 5
#define NES_AUDIO_QUEUE_CAPACITY 7
// Reset the queue, feeder and diagnostic counters; silence and initialize the
// APU. Owns the four basic channels and disables DMC and APU frame IRQs.
void nes_audio_vblank_init(void);
// Copy one complete validated record to RAM and publish it atomically last.
// Return 1 on success, 0 for null/invalid/full. Call from one foreground producer.
u8 nes_audio_vblank_enqueue(const u8* record);
// Return queued records (0..7), excluding the record whose delay is in progress.
u8 nes_audio_vblank_queued(void);
// Return available record slots (0..7), not bytes.
u8 nes_audio_vblank_free(void);
// Enable consumption at the next NMI. Does not enable PPU NMI itself.
void nes_audio_vblank_start(void);
// Disable consumption, silence, discard queued records and clear the feeder.
void nes_audio_vblank_stop(void);
// Stop and attach a readable five-byte-record stream; return 0 for null, zero
// count or a count above 13107. Nonzero loop repeats the stream. Does not start.
u8 nes_audio_vblank_set_music(const u8* records,u16 count,u8 loop);
// Copy at most seven records from the attached stream. Return copies accepted.
// A one-shot feeder appends a delay-zero terminator after the last timed record.
// Keep the stream's ROM bank mapped during this foreground call only.
u8 nes_audio_vblank_refill(void);
// Set the stream, prefill the queue and start. Return 0 for invalid setup/data.
u8 nes_audio_vblank_play_music(const u8* records,u16 count,u8 loop);
// Return 1 while the BGM consumer is enabled, including a recoverable queue underrun.
u8 nes_audio_vblank_is_playing(void);
// Saturating count of starvation episodes, cleared by init; END is not starvation.
u8 nes_audio_vblank_underruns(void);
// Configure the next note: pulse bits 7..6 select duty and 3..0 select volume;
// noise uses volume 3..0, or NES_AUDIO_NOISE_ENVELOPE | decay_period (0..15)
// for a one-shot hardware envelope (larger periods decay more slowly). The
// next noise note starts at volume 15; its length permits a full decay.
// Triangle uses zero for silent, nonzero for full level.
// Return 0 for channel >=4. Hardware has no triangle volume control.
u8 nes_audio_vblank_set_timbre(u8 channel,u8 control);
// Any nonzero argument freezes both timelines and mutes immediately. Zero
// resumes from the stored delays and restores held notes on the next NMI.
// BGM is_playing remains enabled during pause. Refill may still fill the queue.
void nes_audio_vblank_pause(u8 on);
// Copy 1..7 timed records. Bits 0..3 select channels temporarily owned by SFX.
// BGM continues underneath and its current notes return when the effect ends.
// Return 1 after copying; 0 for null, invalid count/data or an empty low mask.
// Ignore mask bits 4..7. All fields are validated, even unselected channels.
// Delay zero is not accepted for SFX. Invalid input preserves the current SFX.
// Replacement restarts the effect; the first HOLD starts from a stopped note.
// The source need only stay mapped/readable until this foreground call returns.
u8 nes_audio_vblank_play_sfx(const u8* records,u8 count,u8 mask);
// Release effect ownership at the next NMI, restoring current BGM notes.
// This does not stop or restart the BGM and does not write the APU immediately.
void nes_audio_vblank_stop_sfx(void);
// NMI hook: invoke exactly once per NMI. With a custom handler or a compiler
// without automatic audio-hook linking, call it there. Never call from main
// or call it again if the compiler already inserts the hook.
// Saves A/X/Y, uses no compiler scratch bytes and reads only RAM/fixed ROM.
void __nes_audio_vblank_tick(void);
#endifkitaqfc/lib/audio_vblank.h
bank.h — Accès au code et aux données tenant compte des banques
#ifndef BANK_H
#define BANK_H
#include "core.h"
#include "intrinsics.h"
// Pair a bank selector with its CPU-window address; a near pointer alone cannot select the bank.
typedef __packed struct BankPtr {
u8 bank;
const u8* ptr;
} BankPtr;
extern u8 kq_bank_current;
// Record the bank in the library shadow and invoke the mapper-aware compiler intrinsic.
void bank_switch(u8 bank);
// Read this wrapper's bank shadow; arbitrary mapper writes do not update it.
u8 bank_get_current(void);
// Read one byte from an explicit ROM bank and 16-bit CPU address.
u8 far_data_read8(u8 bank, const void* addr);
// Read a 16-bit value through the bank-aware compiler intrinsic.
u16 far_data_read16(u8 bank, const void* addr);
// Copy len bytes from banked ROM to caller-owned writable storage.
void far_data_read(u8 bank, const void* addr, void* dst, u16 len);
// Store a bank/address pair without reading memory; null output is ignored.
void farptr_make(BankPtr* out, u8 bank, const u8* ptr);
// Read one byte using both the bank and address of the supplied far pointer.
u8 farptr_read8(BankPtr ptr);
// Read a 16-bit value using both components of the far pointer.
u16 farptr_read16(BankPtr ptr);
// Copy len bytes from a far pointer; the caller provides a sufficiently large destination.
void farptr_read(BankPtr ptr, void* dst, u16 len);
// Route a declared zero-argument function through the far-call intrinsic; this is not a general
// callback-pointer dispatcher. Mapper support and fixed-bank call-site rules still apply.
#define far_call(bank, func) __farcall((bank), func)
#endifkitaqfc/lib/bank.h
chain.h — Tampons circulaires pour l'historique des positions
#ifndef CHAIN_H
#define CHAIN_H
#include "core.h"
typedef __packed struct ChainPoint {
s16 x;
s16 y;
} ChainPoint;
// head identifies the newest point; count grows to capacity, then old points are overwritten.
// Capacity at most 128 keeps every head + age sum within a byte for this implementation.
typedef __packed struct Chain {
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.
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);
#endifkitaqfc/lib/chain.h
collision.h — Tests de collision rectangulaire et autres formes
/*
* Optional declarations for the phase 11 collision helper.
*/
struct NesBox16 {
unsigned short x;
unsigned short y;
unsigned char w;
unsigned char h;
};
// Test two axis-aligned world boxes using exclusive right/bottom edges.
// Coordinate-plus-size sums must fit u16; touching edges return false.
// Both boxes must have positive dimensions; the overlap test has no separate empty-box guard.
unsigned char nes_box16_intersects(struct NesBox16* a, struct NesBox16* b);
// Test a half-open box: left/top edges are included and right/bottom edges
// excluded. Callers provide valid pointers and non-overflowing edge coordinates.
unsigned char nes_box16_contains_point(struct NesBox16* box, unsigned short px, unsigned short py);kitaqfc/lib/collision.h
core.h — Types entiers de base
#ifndef CORE_H
#define CORE_H
// Public scalar aliases for the compiler's byte and 16-bit integer types.
typedef unsigned char u8;
typedef unsigned short u16;
typedef signed char s8;
typedef signed short s16;
// Boolean convenience values; API functions returning bit masks need not normalize to TRUE.
#define TRUE 1
#define FALSE 0
#endifkitaqfc/lib/core.h
danmaku.h — Réserves de projectiles, éventails, impacts et frôlements
// Copyright (c) 2026 DAISUKE OBA. SPDX-License-Identifier: MIT
#ifndef KITAQFC_DANMAKU_H
#define KITAQFC_DANMAKU_H
#include "core.h"
#include "intrinsics.h"
#define DANMAKU_MAX 64
// Reserve cartridge PRG RAM 0x6000..0x627F (640 bytes), enabled and writable.
// Bullet centers remain in [8,248) x [24,232). These margins prevent byte
// wraparound even at the largest signed Q4.4 velocity accepted by spawn.
extern u8 dm_x[64];
extern u8 dm_y[64];
extern u8 dm_active[64];
extern u8 dm_grazed[64];
extern u8 dm_count;
extern u8 dm_peak;
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 the pool, counters and rotating OAM priority. Player settings survive.
void danmaku_reset(void);
// Remove all bullets and step events; preserve lifetime/peak counters.
void danmaku_clear(void);
// Allocate a bullet at pixel-center x/y with signed 1/16-pixel velocities.
// Return one on success, zero outside the playfield or when all 64 slots are full.
u8 danmaku_spawn(u8 x, u8 y, s8 vx, s8 vy);
// Emit up to 64 bullets. Angles wrap in 32 steps: 0 right, 8 down, 16 left,
// 24 up. Speed is in 1/16 pixel, clamped to 64. Each failed allocation counts.
void danmaku_fan(u8 x, u8 y, u8 direction, u8 step, u8 count, u8 speed);
// Move all live bullets once. Remove offscreen/hitting bullets. Hit uses a
// +/-3-pixel box; graze uses +/-11, once per bullet. Events describe this step.
// This updates logic only; it neither writes OAM nor calls a game damage handler.
void danmaku_step(void);
// Write up to slots consecutive shadow-OAM entries starting at first_oam.
// Rotate bullet priority by 13 modulo 64 and hide unused entries in that range.
// tile is an 8x8 sprite centered at (4,4). Return the number emitted. DMA is
// caller-owned and belongs in VBlank. Hardware's eight-per-scanline limit remains.
u8 danmaku_draw(u8 first_oam, u8 slots, u8 tile, u8 attributes);
#endifkitaqfc/lib/danmaku.h
debug.h — Enregistrements en RAM et assertions
#ifndef DEBUG_H
#define DEBUG_H
#include "core.h"
// Choose 1..255 consistently across units; the valid-entry count is a byte.
#ifndef DEBUG_TRACE_MAX
#define DEBUG_TRACE_MAX 32
#endif
// Names are retained pointers, not copied strings; keep their storage and ROM mapping readable.
typedef __packed struct DebugTraceEntry {
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;
// Build the RAM-resident ASSERT label and reset log length, frame tag and last
// assertion code. Old log storage bytes are not erased.
void debug_init(void);
// Choose the frame tag stored in subsequent debug entries.
void debug_set_frame(u16 frame);
// Append a named marker with the reserved marker value 0xFFFF.
void debug_mark_frame(const u8* label);
// Widen a byte value into the trace entry'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);
// Store the assertion code even if the log is full, then attempt an ASSERT
// entry. The helper records failure but does not stop execution.
void debug_assert_fail(u16 code);
// Read the number of valid entries in the fixed trace buffer.
u8 debug_get_trace_count(void);
// Borrow the internal trace array; bound inspection by debug_get_trace_count.
const DebugTraceEntry* debug_get_trace_log(void);
// Read the latest assertion code, initially zero after debug_init.
u16 debug_get_last_assert(void);
#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)
#endifkitaqfc/lib/debug.h
entity.h — Réserves d'objets fondées sur des tableaux fixes
#ifndef ENTITY_H
#define ENTITY_H
#include "core.h"
// Choose capacity 1..255 consistently across units; counters are bytes and FF is the failure sentinel.
#ifndef ENTITY_MAX
#define ENTITY_MAX ((u8)16)
#endif
// Coordinates, velocities, state and timer have game-defined units.
// The sprite byte is bookkeeping only; releasing a slot does not hide or free its sprite.
typedef __packed struct Entity {
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.
// Use a callback in common PRG bank 0, or keep its bank mapped throughout dispatch.
typedef void (*EntityFn)(u8 id);
// Reset every slot before the game starts using the pool.
void entity_init(void);
// 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(id) for each active slot in ascending order. A null callback does nothing.
// Changes to later slots take effect during the same traversal. Do not reenter this traversal.
void entity_update_all(EntityFn fn);
// Call the drawing callback for each active slot, using the same traversal rules as update.
// The callback submits drawing data; the pool does not allocate sprites.
void entity_draw_all(EntityFn fn);
// Count occupied slots without changing entity state.
u8 entity_count_active(void);
// Release every entity and restore deterministic defaults, including the no-sprite sentinel.
void entity_clear_all(void);
#endifkitaqfc/lib/entity.h
fc.h — En-tête de regroupement de la bibliothèque
#ifndef FC_H
#define FC_H
// Convenience header collecting FC interfaces. Inclusion provides declarations
// and aliases, not every implementation; link only the source modules required
// by the selected runtime, avoiding alternative helpers with conflicting symbols.
#include "core.h"
#include "intrinsics.h"
#include "system.h"
#include "input.h"
#include "runtime.h"
#include "ppu.h"
#include "ppu_direct.h"
#include "vram_queue.h"
#include "vram.h"
#include "oam.h"
#include "sprite.h"
#include "pad.h"
#include "input_repeat.h"
#include "palette.h"
#include "scroll.h"
#include "tilemap.h"
#include "nametable_asset.h"
#include "attribute.h"
#include "scene.h"
#include "metasprite.h"
#include "actor.h"
#include "entity.h"
#include "collision.h"
#include "fixed.h"
#include "physics2d.h"
#include "physics3d.h"
#include "bank.h"
#include "asset.h"
#include "debug.h"
#include "chain.h"
#include "audio.h"
#include "audio_vblank.h"
#include "fds_sound.h"
#include "vrc6_sound.h"
#include "vrc7_sound.h"
#include "mapper.h"
// This final include adds function-like macros, including zero-argument nes_oam_dma.
// Use selective headers when calling the page-argument runtime API with the same name.
#include "nes_game.h"
#endifkitaqfc/lib/fc.h
fds.h — Opérations sur disque FDS
#ifndef FDS_H
#define FDS_H
#include "intrinsics.h"
// Return the compile-time FDS mapper selection as 0 or 1; this is not a hardware probe.
u8 __fds_available(void);
// Return the inverted disk-absent bit from 4032 as 0 or 1; this checks presence, not transfer completion.
u8 __fds_disk_ready(void);
// Return raw status mask 4032 & 04, either 0 or 4. This is not a numbered disk-side identifier.
u8 __fds_side(void);
// Read the entire 4030 status register; this is not a stored BIOS error code.
u8 __fds_error(void);
// Poll disk presence until the absent bit clears. There is no timeout or cancellation path.
void __fds_wait_ready(void);
// Alias the same disk-presence wait as __fds_wait_ready; the call can block indefinitely.
void __fds_wait_insert(void);
#endifkitaqfc/lib/fds.h
fds_file.h — Chargement de fichiers FDS
#ifndef FDS_FILE_H
#define FDS_FILE_H
#include "intrinsics.h"
// Native FDS32: load a non-boot file at its disk-header address, then memmove
// PRG bytes to dst. Null dst keeps the native destination (also for PPU files).
// Both CPU spans must fit $0200-$07FF or $6000-$DFFF and be owned by the caller.
// Return 0, a BIOS error, $40 for a missing transfer, or $FF for invalid input.
// Call from common code with disk-I/O interrupt/display prerequisites satisfied.
u8 __fds_load_file(u8 id, u8* dst);
// Overwrite the final non-boot PRG slot on its side, preserving its ID/name/load
// address. len must equal its packaged size; src must be a valid CPU RAM span.
// The resolved physical ordinal selects the slot, independently of file ID.
// Return 0, a BIOS error, or $FF before any write for an invalid slot/span/size.
u8 __fds_save_file(u8 id, const u8* src, u16 len);
// Query the compiled --fds-meta/--fds-manifest table, not the inserted disk; return 0 or 1.
u8 __fds_file_exists(u8 id);
// Return the compiled metadata size, or zero if id is absent. No disk directory is read.
u16 __fds_file_size(u8 id);
#endifkitaqfc/lib/fds_file.h
fds_overlay.h — Code d'overlay FDS
#ifndef FDS_OVERLAY_H
#define FDS_OVERLAY_H
#include "intrinsics.h"
// Load disk file id through BIOS, return its error byte and mark bank residency FF (unknown).
u8 __fds_load_overlay(u8 id);
// Load logical bank 1 from its separate boot file, or bank 2+ from overlay-start-id+(bank-2).
// Return zero on success, FF for invalid/unavailable mappings, or the BIOS error.
// A failed BIOS transfer marks residency FF (unknown); a matching valid guard can skip loading.
u8 __fds_load_bank(u8 bank);
// Return zero when the software residency record matches, otherwise call __fds_load_bank.
u8 __fds_require_bank(u8 bank);
// Return the software resident-bank byte, or FF after a failed bank transfer.
// This is not a checksum of overlay memory.
u8 __fds_current_bank(void);
// Compare a valid bank with the software resident-bank byte; FF (unknown) never matches.
u8 __fds_is_bank_resident(u8 bank);
// Return the linker-generated overlay-function count; zero if the table is disabled.
u8 __fds_overlay_function_count(void);
// Evaluate bank once and call the named zero-argument function using its linked bank.
// Restore the caller window before returning; restoration failure stops in common code.
u8 __fds_overlay_farcall(u8 bank, u16 func);
// Same named, zero-argument dispatch as __fds_overlay_farcall; evaluate bank once.
u8 __fds_farcall(u8 bank, u16 func);
#endifkitaqfc/lib/fds_overlay.h
fds_save.h — Déclarations de sauvegarde FDS
#ifndef FDS_SAVE_H
#define FDS_SAVE_H
// Compatibility include for FDS file/save declarations; this header adds no storage or implementation.
#include "fds_file.h"
#endifkitaqfc/lib/fds_save.h
fds_sound.h — Audio FDS à table d'ondes
#ifndef FDS_SOUND_H
#define FDS_SOUND_H
#include "intrinsics.h"
// Write 83 to 4023 and zero to 4089/408A to initialize disk/sound register gates.
void __fds_sound_enable(void);
// Copy exactly 64 readable bytes to wave RAM with wave writes enabled, then set 4089 to zero.
void __fds_wave_load(const u8* wave64);
// Stream 32 readable bytes to 4088; the caller prepares modulation state and write conditions.
void __fds_mod_load(const u8* mod32);
// Write a 12-bit frequency to 4082/4083; upper control bits in 4083 are cleared.
void __fds_freq_set(u16 freq);
// Write (volume & 3F) | 80 to 4080 for direct volume control; masking wraps, rather than clamps.
void __fds_volume_set(u8 vol);
// Write the three raw arguments to 4080, 4084 and 408A in that order.
// The legacy parameter names do not describe three independently packed envelope fields.
void __fds_env_set(u8 speed, u8 gain, u8 mode);
#endifkitaqfc/lib/fds_sound.h
fixed.h — Calcul en virgule fixe Q8.8 et rectangles
#ifndef FIXED_H
#define FIXED_H
#include "core.h"
// Signed Q8.8 spans -128 to 127 + 255/256; one integer unit is represented by 256.
typedef s16 fix8;
#define FIX_ONE ((fix8)256)
#define FIX_HALF ((fix8)128)
typedef __packed struct Vec2 {
fix8 x;
fix8 y;
} Vec2;
typedef __packed struct KQRect {
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);
#endifkitaqfc/lib/fixed.h
input.h — État des boutons, appuis, relâchements et répétition
#ifndef INPUT_H
#define INPUT_H
#include "core.h"
#include "intrinsics.h"
// These are shared logical masks, not raw controller-register bit positions.
// input_update translates controller 1 before these masks are applied.
#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 new press pulses immediately; the next pulse occurs DELAY + 1 input updates later.
#ifndef INPUT_REPEAT_DELAY
#define INPUT_REPEAT_DELAY ((u8)18)
#endif
// Later pulses occur RATE + 1 updates apart; zero repeats on each 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;
// Clear held/edge/repeat masks and reset each independent repeat countdown.
void input_init(void);
// Read controller 1 through the safe intrinsic, translate its bit order and
// derive press/release edges. Repeat delays count calls to this function, so
// call it once per intended input tick.
void input_update(void);
// Return true when any masked logical button is held.
u8 input_down(u8 mask);
// Return true when any masked button became pressed in the latest input update.
u8 input_pressed(u8 mask);
// Return true when any masked button became released in the latest update.
u8 input_released(u8 mask);
// Return true for a masked initial press or scheduled repeat pulse.
u8 input_repeat(u8 mask);
// Read the complete translated held-button mask.
u8 input_current(void);
// Read the translated held-button mask from before the latest update.
u8 input_previous(void);
#define btn_down input_down
#define btn_pressed input_pressed
#define btn_released input_released
#define btn_repeat input_repeat
#endifkitaqfc/lib/input.h
input_repeat.h — Répétition d'un bouton maintenu
/*
* Optional declarations for the phase 9 NES pad repeat helper.
*
* Button bit layout:
* bit0=A bit1=B bit2=Select bit3=Start bit4=Up bit5=Down bit6=Left bit7=Right
*/
extern unsigned char nes_pad_repeat_delay;
extern unsigned char nes_pad_repeat_interval;
extern unsigned char nes_pad1_repeat;
// Set initial/repeat countdowns and clear repeat output. Zero countdowns are
// allowed and cause a repeat on the next held-button step.
// A fresh press emits immediately. Held repeats follow after delay+1 and then interval+1 steps.
// These are call counts, not milliseconds; use one fresh pad poll before each step.
void nes_pad_repeat_config(unsigned char delay, unsigned char interval);
// Generate per-button repeat bits from the most recently polled pad state.
// Poll first, then call once per tick; a countdown reaching zero emits on the
// following step, so an interval N leaves N decrement steps between pulses.
void nes_pad_repeat_step(void);
// Return the requested newly-pressed bits, not a normalized Boolean.
unsigned char nes_pad_trigger(unsigned char mask);
// Return the requested repeat-pulse bits from the latest repeat step.
unsigned char nes_pad_repeat(unsigned char mask);
// Return the requested newly-released bits from the latest pad poll.
unsigned char nes_pad_release(unsigned char mask);
// Return the requested currently-held bits in the NES pad layout.
unsigned char nes_pad_held(unsigned char mask);kitaqfc/lib/input_repeat.h
intrinsics.h — Fonctions intrinsèques du compilateur
#ifndef INTRINSICS_H
#define INTRINSICS_H
/*
* FC/NES native intrinsic API.
* This header intentionally does not expose KITAQGB/CGB compatibility stubs.
* The compiler recognizes these names and emits 6502-oriented code or
* calls an internal 6502 helper generated by the backend.
*/
// Direct PPU operations require caller-controlled access timing. Generated helpers share runtime
// argument/scratch storage: do not assume calls are reentrant across NMI or IRQ handlers.
typedef unsigned char u8;
typedef unsigned short u16;
/* memory / bit / math */
// Copy len bytes forward between readable/writable CPU ranges; overlapping copies are not memmove.
// Zero length performs no memory transfer; argument side effects are evaluated before expansion.
void __memcpy(u8* dst, const u8* src, u16 len);
// Fill len CPU bytes with value. Zero length still evaluates argument side effects.
void __memset(u8* dst, u8 value, u16 len);
// Forward copy with an 8-bit length, zero through 255; the dynamic helper promotes it to a word count.
void __memcpy_small(u8* dst, const u8* src, u8 len);
// Fill zero through 255 CPU bytes; this is ordinary RAM access, not a PPU transfer.
void __memset_small(u8* dst, u8 value, u8 len);
// Copy exactly 16 bytes forward; both ranges must be valid and suitably non-overlapping.
void __copy16(u8* dst, const u8* src);
// Copy exactly 32 bytes forward; bank selection and source lifetime belong to the caller.
void __copy32(u8* dst, const u8* src);
// Return 0 or 1 for half-open bounds. Zero extents are empty; coordinates do not wrap across 255.
u8 __xy_in_rect(u8 x, u8 y, u8 rx, u8 ry, u8 rw, u8 rh);
// Return abs(x1-x2)+abs(y1-y2) modulo 256; large distances are not saturated.
u8 __manhattan(u8 x1, u8 y1, u8 x2, u8 y2);
// Return y*width+x as a word without checking coordinates against map dimensions.
u16 __map_index(u8 x, u8 y, u8 width);
// Replace both persistent state bytes. Reusing a seed reproduces the sequence; this is not cryptographic randomness.
void __rng_seed(u16 seed);
// Advance the shared 16-bit LFSR and return the XOR of its two bytes; zero state is reseeded to A55A.
u8 __rng8(void);
// Return base[bit>>3] & (1<<(bit&7)): zero or the bit mask, not a normalized Boolean.
u8 __bit_test(u8* base, u16 bit);
// Set the indexed bit in caller storage without changing the other seven bits in that byte.
void __bit_set(u8* base, u16 bit);
// Clear the indexed bit in caller storage; no bounds check or interrupt exclusion is inserted.
void __bit_clear(u8* base, u16 bit);
// XOR the indexed bit in caller storage; coordinate concurrent writers to avoid lost updates.
void __bit_toggle(u8* base, u16 bit);
// Return the high byte of the unsigned 8-by-8 product, equivalent to floor(a*b/256).
u8 __mul8x8_hi(u8 a, u8 b);
// Return the low word of the unsigned product; overflow wraps without saturation.
u16 __mul16x8(u16 a, u8 b);
// Interpret a and b as signed two's-complement bit patterns and return the low word of their product.
u16 __smul16x8(u16 a, u8 b);
// Return acc+a*b modulo 65536 using unsigned multiplication.
u16 __mac16(u16 acc, u16 a, u8 b);
// Add the signed-pattern product to acc modulo 65536; the API carries the result as u16 bits.
u16 __smac16(u16 acc, u16 a, u8 b);
// FC alias of __smul16x8: signed-pattern raw product, with no Q1.7 scaling shift.
u16 __smul16x8_q1_7(u16 a, u8 b);
// FC alias of __smac16: accumulate a raw signed-pattern product modulo 65536.
u16 __smac16_q1_7(u16 acc, u16 a, u8 b);
// Return a0*b0+a1*b1 modulo 65536. The FC backend inserts no Q8.8 rescaling or rounding.
u16 __dot2_q8_8(u16 a0, u16 a1, u8 b0, u8 b1);
// Sum three unsigned word-by-byte products modulo 65536 without a final scaling shift.
u16 __dot3_q8_8(u16 a0, u16 a1, u16 a2, u8 b0, u8 b1, u8 b2);
// Sum two signed-pattern products modulo 65536; no Q8.8 scaling shift is generated.
u16 __sdot2_q8_8(u16 a0, u16 a1, u8 b0, u8 b1);
// Sum three signed-pattern products modulo 65536; choose operand units explicitly in the caller.
u16 __sdot3_q8_8(u16 a0, u16 a1, u16 a2, u8 b0, u8 b1, u8 b2);
// FC alias of __sdot2_q8_8: two raw signed-pattern products, summed without rescaling.
u16 __sdot2_q1_7(u16 a0, u16 a1, u8 b0, u8 b1);
// FC alias of __sdot3_q8_8: three raw signed-pattern products, summed without rescaling.
u16 __sdot3_q1_7(u16 a0, u16 a1, u16 a2, u8 b0, u8 b1, u8 b2);
/* PRG bank */
// Resolve a symbol or function placement to its byte bank number at compilation time.
u8 __bankof(u16 symbol_or_function);
// Select the mapper-specific PRG bank; the common bank and legal bank range depend on the target board.
void __bankswitch(u8 bank);
// Use the same mapper PRG-switch helper as __bankswitch; retain executable code in a valid mapping.
void __prg_bank_set(u8 bank);
// Call a declared zero-argument function; placement selects its bank and its declared type determines the result.
u8 __farcall(u8 bank, u16 func);
// Switch to the source bank, copy len bytes forward and restore the previous bank.
// Keep destination RAM and helper code accessible throughout; overlapping copies are not memmove.
void __far_memcpy(u8* dst, u8 bank, u16 src, u16 len);
// Temporarily select bank, read one byte at addr and restore the prior bank mapping.
u8 __farpeek8(u8 bank, u16 addr);
// Temporarily select bank and read a little-endian word, then restore the previous mapping.
u16 __farpeek16(u8 bank, u16 addr);
/* PPU / VRAM */
// Invoke the compiler rendering-enable helper; this header contains declarations, not C fallback implementations.
void __ppu_on(void);
// Invoke the compiler rendering-disable helper before bulk direct PPU updates.
void __ppu_off(void);
// Replace PPUMASK with the supplied byte; the caller chooses rendering, clipping and emphasis bits.
void __ppu_mask_set(u8 value);
// Replace PPUCTRL, including NMI enable, pattern-table choices and address increment mode.
void __ppu_ctrl_set(u8 value);
// Read the software PPUCTRL/PPUMASK shadows; use the setters for coherent state.
// Raw writes to $2000/$2001 bypass these shadows. No PPU hardware read occurs.
u8 __ppu_ctrl_get(void);
u8 __ppu_mask_get(void);
// Set the PPU address through the compiler helper; address writes affect the shared scroll/address latch.
void __ppu_addr(u16 ppu_addr);
// Write one PPUDATA byte using the current PPU address and increment mode.
void __ppu_data(u8 value);
// Read PPUSTATUS; the hardware clears VBlank status and resets the shared write latch.
u8 __ppu_read_status(void);
// Read PPUSTATUS to reset the scroll/address write latch; the read also clears VBlank status.
void __scroll_latch_reset(void);
// Save X/Y in runtime shadows, reset the PPU latch and write both scroll bytes immediately.
void __scroll_set(u8 x, u8 y);
// Replace saved X and write an X/Y pair using the retained Y shadow.
void __scroll_x_set(u8 x);
// Replace saved Y and write an X/Y pair using the retained X shadow.
void __scroll_y_set(u8 y);
// Write a byte-counted source range directly; arrange PPU access timing and source-bank visibility.
void __vram_write(u16 ppu_addr, const u8* src, u8 len);
// Write repeated bytes directly; this is not an enqueue operation.
void __vram_fill(u16 ppu_addr, u8 value, u8 len);
// Write one tile directly at 2000+y*32+x; use x<32, y<30 for visible nametable cells.
void __nametable_put(u8 x, u8 y, u8 tile);
// Write one tile in nametable nt&3. Mirroring can alias logical nametables; coordinates are unchecked.
void __nametable_put_nt(u8 nt, u8 x, u8 y, u8 tile);
// Fill rows of nametable zero directly, advancing each row start by 32 bytes.
// Keep the rectangle in bounds and use PPU increment one; this does not enqueue or clip.
void __nametable_rect(u8 x, u8 y, u8 w, u8 h, u8 tile);
// Fill a rectangle in nametable nt&3 with the same unchecked, direct-write row loop.
void __nametable_rect_nt(u8 nt, u8 x, u8 y, u8 w, u8 h, u8 tile);
// Write the entire packed attribute byte at 23C0+(y>>2)*8+(x>>2).
// Use tile coordinates below 32; this does not merge a single palette quadrant.
void __attr_set(u8 x, u8 y, u8 attr);
// Write a whole packed attribute byte in nametable nt&3; other quadrant fields are overwritten.
void __attr_set_nt(u8 nt, u8 x, u8 y, u8 attr);
// Stream exactly 16 source bytes to 3F00. Arrange PPU access timing and increment one.
void __palette_bg_load(const u8* pal16);
// Stream exactly 16 source bytes to 3F10; hardware palette aliases also affect background entries.
void __palette_sp_load(const u8* pal16);
/* NMI VRAM transfer queue. Queue entries are consumed by __vramq_exec(),
* and the default NMI handler calls __vramq_exec() automatically.
*/
// Reset pending intrinsic-queue records; this is separate from runtime.c nes_vram_queue_clear.
void __vramq_clear(void);
// Append one address/value update; use the overflow latch to detect capacity failure.
void __vramq_put(u16 ppu_addr, u8 value);
// Retain the source address for later consumption; keep its storage and bank mapping valid.
void __vramq_copy(u16 ppu_addr, const u8* src, u8 len);
// Append a repeated-byte update; the source value is stored in the record.
void __vramq_fill(u16 ppu_addr, u8 value, u8 len);
// Publish the pending records to the configured consumer. Do not mutate them while consumption can run.
void __vramq_commit(void);
// Execute a ready queue directly; committing and safe PPU timing are caller responsibilities.
void __vramq_exec(void);
// Return encoded bytes currently occupied, not transfer payload bytes or command count.
u8 __vramq_len(void);
// Read the latched capacity failure; reading does not reset it.
u8 __vramq_overflow(void);
// Clear the overflow latch explicitly after handling the failed submission.
void __vramq_clear_overflow(void);
// Return total encoded command-buffer capacity; this is independent of PPU VRAM capacity.
u8 __vramq_capacity(void);
/* NMI / IRQ */
// Spin until the runtime NMI counter changes; the configured handler must advance it. No timeout is emitted.
void __nmi_wait(void);
// Return the current wrapping NMI counter byte, not a Boolean ready flag.
u8 __nmi_ready(void);
// Set bit 7 in the PPUCTRL shadow and write it to hardware, preserving the other shadow bits.
void __nmi_enable(void);
// Clear bit 7 in the PPUCTRL shadow and write it to hardware; CPU IRQ masking is separate.
void __nmi_disable(void);
// Emit SEI to mask CPU IRQs; NMI is unaffected.
void __irq_disable(void);
// Emit CLI to unmask CPU IRQs; the caller must have a valid interrupt handler.
void __irq_enable(void);
// Return the processor-status byte captured before SEI. Pass that byte to __irq_restore.
u8 __irq_save(void);
// Restore processor status with PLP, including arithmetic flags and the saved IRQ mask.
void __irq_restore(u8 state);
/* OAM / input */
// Set OAMADDR to zero and start DMA from CPU page 02; arrange safe PPU timing in the caller.
void __oam_dma(void);
// Set OAMADDR to zero and DMA 256 bytes from page<<8. The source page must remain readable.
void __oam_dma_page(u8 page);
// Hide all 64 page-02 shadow sprites by writing Y=F0; hardware OAM changes only after DMA.
void __oam_clear(void);
// Write Y, tile, attributes and X to one shadow entry. Use indices 0..63; coordinates are raw OAM bytes.
void __sprite_set(u8 index, u8 x, u8 y, u8 tile, u8 attr);
// Replace only shadow X/Y for index 0..63; tile and attribute bytes remain unchanged.
void __sprite_move(u8 index, u8 x, u8 y);
// Replace the selected shadow tile byte; this does not upload tile patterns.
void __sprite_tile(u8 index, u8 tile);
// Replace the selected shadow attribute byte, including palette, priority and flip bits.
void __sprite_attr(u8 index, u8 attr);
// Write F0 to the selected shadow Y byte; issue DMA to make the change visible.
void __sprite_hide(u8 index);
// Expand dx,dy,tile,attr records into page-02 shadow OAM until dx=FF; return the next index.
// Coordinates and the byte OAM cursor wrap; keep the terminated stream within the available slots.
u8 __metasprite_draw(u8 oam_index, u8 base_x, u8 base_y, const u8* metasprite);
// Latch and sample eight D0 bits from port 1; bit order is A,B,Select,Start,Up,Down,Left,Right.
u8 __pad_read1(void);
// Latch and sample eight D0 bits from port 2 in the same NES button order.
u8 __pad_read2(void);
// Repeat pairs of port-1 polls until both bytes match; the retry loop has no fixed limit.
u8 __pad_read1_safe(void);
// Repeat pairs of port-2 polls until both bytes match; this does not populate pad.c globals.
u8 __pad_read2_safe(void);
// Return pad & 0F for A/B/Select/Start; this masks a supplied snapshot and performs no polling.
u8 __pad_buttons(u8 pad);
// Return pad & F0 in the original bit positions; this does not normalize directions to bits 0..3.
u8 __pad_dirs(u8 pad);
/* Famicom/NES expansion input devices.
* D1 readers are for expansion-port controllers/joysticks that expose a
* standard 8-bit joypad stream on data line D1 instead of D0.
* __joypad2p_voice() / __mic_read2p() return the Famicom 2P microphone bit.
*/
// Latch and read an eight-button stream from port-1 data line D1 rather than D0.
u8 __pad_read1_d1(void);
// Latch and read an eight-button stream from port-2 data line D1 rather than D0.
u8 __pad_read2_d1(void);
// Alias the port-1 D1 controller reader; the attached device must use the expected serial protocol.
u8 __exp_pad_read1(void);
// Alias the port-2 D1 controller reader; this is not an expansion-device discovery operation.
u8 __exp_pad_read2(void);
// Return controller-port 4016 bit 2 normalized to 0 or 1; this is a microphone level bit, not PCM audio.
u8 __joypad2p_voice(void);
// Alias the same normalized microphone input bit as __joypad2p_voice.
u8 __mic_read2p(void);
/* Zapper / light gun. The no-suffix names default to the usual port-2/Famicom
* expansion-port mapping. __zapper_light*() returns 1 when light is detected.
*/
// Return raw 4016 & 18, retaining trigger and active-low light bits.
u8 __zapper_raw1(void);
// Return raw 4017 & 18 for the second port.
u8 __zapper_raw2(void);
// Return port-1 trigger bit 4 normalized to 0 or 1.
u8 __zapper_trigger1(void);
// Return port-2 trigger bit 4 normalized to 0 or 1.
u8 __zapper_trigger2(void);
// Invert port-1 bit 3 and normalize: one means light detected.
u8 __zapper_light1(void);
// Invert port-2 bit 3 and normalize: one means light detected.
u8 __zapper_light2(void);
// Default to the port-2 normalized trigger reader.
u8 __zapper_trigger(void);
// Default to the port-2 normalized light reader.
u8 __zapper_light(void);
/* Family BASIC Keyboard. __fkb_scan() writes 18 bytes: 9 rows x 2 columns,
* each byte containing raw $4017 & 0x1E for that row/column.
*/
// Probe selected-row and disabled-matrix bit patterns and return 0 or 1; this is a heuristic detection.
u8 __fkb_detect(void);
// Write 18 raw masked samples (4017 & 1E), two per row, to caller storage; reset 4016 afterward.
void __fkb_scan(u8* dst18);
// Select a matrix row and the low bit of col, then return raw 4017 & 1E.
// Use rows 0..8 for keys; row 9 is used by detection. No row-range validation is emitted.
u8 __fkb_read_row_col(u8 row, u8 col);
/* R.O.B. / Famicom Robot optical flash primitives. These are timing primitives;
* game-specific command sequences should be built on top of __rob_pulse() or
* __rob_send_byte().
*/
// Set PPUMASK and its shadow to 1E or 00, then wait for an NMI-counter change.
// The caller supplies image/palette brightness; rendering enable alone does not create a white screen.
void __rob_flash(u8 bright);
// Run on_frames enabled-mask waits followed by off_frames disabled-mask waits; NMI must advance.
void __rob_pulse(u8 on_frames, u8 off_frames);
// Send eight bits MSB first: one uses 4 on/2 off waits; zero uses 2 on/4 off.
// Requires an advancing runtime NMI counter; 48 waits in total, final PPUMASK=0.
// This raw pattern does not add a robot command preamble or validate reception.
void __rob_send_byte(u8 pattern);
/* Expansion-port TTL serial / MIDI adapter support.
* The low-level serial layer assumes an external adapter that maps OUT0 to TX
* and D4 on $4017 to RX. MIDI helpers bit-bang 8N1 bytes at an approximate
* 31250 bps timing suitable for adapter bring-up and simple music sync.
*/
// Write bit & 1 to 4016, replacing the port output value; coordinate with other port users.
void __serial_tx_bit(u8 bit);
// Read 4017 bit 4 and normalize it to 0 or 1; an external serial adapter supplies the signal.
u8 __serial_rx_bit(void);
// Send start-low, eight least-significant-first bits and stop-high in 57-cycle
// NTSC bit cells (about 31400 bps). Stop DMC DMA and mask IRQ/NMI during transfers;
// PAL timing and electrical adapter compatibility are not established here.
void __midi_out_byte(u8 byte);
// Block for a low start signal and sample eight bits. No timeout, framing check or receive buffer is provided.
u8 __midi_in_byte(void);
// Send 90|(ch&0F), note and velocity. Supply 7-bit data bytes; they are not masked by this helper.
void __midi_note_on(u8 ch, u8 note, u8 velocity);
// Send 80|(ch&0F), note and velocity through the same synchronous serial path.
void __midi_note_off(u8 ch, u8 note, u8 velocity);
// Send B0|(ch&0F), controller and value; both data arguments must be valid 7-bit values.
void __midi_control_change(u8 ch, u8 cc, u8 value);
// Send C0|(ch&0F) followed by the caller-supplied 7-bit program value.
void __midi_program_change(u8 ch, u8 program);
// Transmit the single realtime byte F8 synchronously; this does not schedule future ticks.
void __midi_clock(void);
// Transmit realtime Start (FA) through the serial adapter path.
void __midi_start(void);
// Transmit realtime Continue (FB) through the serial adapter path.
void __midi_continue(void);
// Transmit realtime Stop (FC) through the serial adapter path.
void __midi_stop(void);
/* Mapper */
// Return the low byte of the mapper number selected for this build; no cartridge probe is performed.
u8 __mapper_id(void);
// Select a CNROM bank or MMC3 register 0 bank; unsupported mapper profiles produce a compile error.
void __chr_bank_set(u8 bank);
// Use the same CNROM/MMC3 register 0 selection as __chr_bank_set.
void __chr_bank_set0(u8 bank);
// Select MMC3 register 1, or the same full CNROM bank register; this is mapper-specific banking.
void __chr_bank_set1(u8 bank);
// Emit the selected mapper mirroring operation; available modes and writable control depend on the board.
void __mirroring_set(u8 mode);
// Write the MMC3 IRQ latch and reload registers. This does not enable IRQ delivery.
void __irq_scanline_set(u8 line);
// Alias the MMC3 IRQ latch/reload operation; other mapper profiles are rejected.
void __mapper_irq_set(u8 scanline);
// Write MMC3 E001. The CPU IRQ mask and a valid handler are separate caller responsibilities.
void __mapper_irq_enable(void);
// Write MMC3 E000 to disable and acknowledge mapper IRQs.
void __mapper_irq_disable(void);
// Use the same E000 write as disable; explicitly re-enable when another interrupt is needed.
void __mapper_irq_ack(void);
// Wait for the current hit flag to clear, then for a new hit. No timeout is provided.
void __sprite0_wait_hit(void);
// Wait for a new sprite-zero hit, reset the PPU latch and write X/Y scroll; requires a visible hit setup.
void __split_scroll_sprite0(u8 x, u8 y);
/* FDS. Status and sound primitives are emitted on --mapper=fds.
* File/overlay APIs use the FDS BIOS direct-pointer routines. __fds_load_file()
* and __fds_load_overlay() load to the destination encoded in the disk file
* header. __fds_file_exists() and __fds_file_size() are side-effect-free when
* a disk-builder manifest is supplied with --fds-meta / --fds-manifest.
*/
// Return the compile-time FDS mapper selection as 0 or 1; this is not a hardware probe.
u8 __fds_available(void);
// Return the inverted disk-absent bit from 4032 as 0 or 1; this checks presence, not transfer completion.
u8 __fds_disk_ready(void);
// Return raw status mask 4032 & 04, either 0 or 4. This is not a numbered disk-side identifier.
u8 __fds_side(void);
// Read the entire 4030 status register; this is not a stored BIOS error code.
u8 __fds_error(void);
// Poll disk presence until the absent bit clears. There is no timeout or cancellation path.
void __fds_wait_ready(void);
// Alias the same disk-presence wait as __fds_wait_ready; the call can block indefinitely.
void __fds_wait_insert(void);
// Native FDS32: load a non-boot file at its disk-header address, then memmove
// PRG bytes to dst. Null dst keeps the native destination (also for PPU files).
// Both CPU spans must fit $0200-$07FF or $6000-$DFFF and be owned by the caller.
// Return 0, a BIOS error, $40 for a missing transfer, or $FF for invalid input.
// Call from common code with disk-I/O interrupt/display prerequisites satisfied.
u8 __fds_load_file(u8 id, u8* dst);
// Overwrite the final non-boot PRG slot on its side, preserving its ID/name/load
// address. len must equal its packaged size; src must be a valid CPU RAM span.
// The resolved physical ordinal selects the slot, independently of file ID.
// Return 0, a BIOS error, or $FF before any write for an invalid slot/span/size.
u8 __fds_save_file(u8 id, const u8* src, u16 len);
// Load disk file id through BIOS, return its error byte and mark bank residency FF (unknown).
u8 __fds_load_overlay(u8 id);
// Load logical bank 1 from its separate boot file, or bank 2+ from overlay-start-id+(bank-2).
// Return zero on success, FF for invalid/unavailable mappings, or the BIOS error.
// A failed BIOS transfer marks residency FF (unknown); a matching valid guard can skip loading.
u8 __fds_load_bank(u8 bank);
// Return zero when the software residency record matches, otherwise call __fds_load_bank.
u8 __fds_require_bank(u8 bank);
// Return the software resident-bank byte, or FF after a failed bank transfer.
// This is not a checksum of overlay memory.
u8 __fds_current_bank(void);
// Compare a valid bank with the software resident-bank byte; FF (unknown) never matches.
u8 __fds_is_bank_resident(u8 bank);
// Return the linker-generated overlay-function count; zero if the table is disabled.
u8 __fds_overlay_function_count(void);
// Evaluate bank once and call the named zero-argument function using its linked bank.
// Restore the caller window before returning; restoration failure stops in common code.
u8 __fds_overlay_farcall(u8 bank, u16 func);
// Same named, zero-argument dispatch as __fds_overlay_farcall; evaluate bank once.
u8 __fds_farcall(u8 bank, u16 func);
// Query the compiled --fds-meta/--fds-manifest table, not the inserted disk; return 0 or 1.
u8 __fds_file_exists(u8 id);
// Return the compiled metadata size, or zero if id is absent. No disk directory is read.
u16 __fds_file_size(u8 id);
// Write 83 to 4023 and zero to 4089/408A to initialize disk/sound register gates.
void __fds_sound_enable(void);
// Copy exactly 64 readable bytes to wave RAM with wave writes enabled, then set 4089 to zero.
void __fds_wave_load(const u8* wave);
// Stream 32 readable bytes to 4088; the caller prepares modulation state and write conditions.
void __fds_mod_load(const u8* mod);
// Write a 12-bit frequency to 4082/4083; upper control bits in 4083 are cleared.
void __fds_freq_set(u16 freq);
// Write (volume & 3F) | 80 to 4080 for direct volume control; masking wraps, rather than clamps.
void __fds_volume_set(u8 volume);
// Write the three raw arguments to 4080, 4084 and 408A in that order.
// The legacy parameter names do not describe three independently packed envelope fields.
void __fds_env_set(u8 a, u8 b, u8 c);
#endifkitaqfc/lib/intrinsics.h
keyboard.h — Balayage du clavier
#ifndef KEYBOARD_H
#define KEYBOARD_H
#include "intrinsics.h"
// Probe selected-row and disabled-matrix bit patterns and return 0 or 1; this is a heuristic detection.
u8 __fkb_detect(void);
// Write 18 raw masked samples (4017 & 1E), two per row, to caller storage; reset 4016 afterward.
void __fkb_scan(u8* dst18);
// Select a matrix row and the low bit of col, then return raw 4017 & 1E.
// Use rows 0..8 for keys; row 9 is used by detection. No row-range validation is emitted.
u8 __fkb_read_row_col(u8 row, u8 col);
#endifkitaqfc/lib/keyboard.h
mapper.h — Banques et interruptions du mapper
#ifndef MAPPER_H
#define MAPPER_H
#include "intrinsics.h"
// Resolve a symbol or function placement to its byte bank number at compilation time.
u8 __bankof(u16 symbol_or_function);
// Select the mapper-specific PRG bank; the common bank and legal bank range depend on the target board.
void __bankswitch(u8 bank);
// Use the same mapper PRG-switch helper as __bankswitch; retain executable code in a valid mapping.
void __prg_bank_set(u8 bank);
// Invoke the compiler banked-call path; target placement and calling convention must match the selected mapper.
u8 __farcall(u8 bank, u16 func);
// Switch to the source bank, copy len bytes forward and restore the previous bank.
// Keep destination RAM and helper code accessible throughout; overlapping copies are not memmove.
void __far_memcpy(u8* dst, u8 bank, u16 src, u16 len);
// Temporarily select bank, read one byte at addr and restore the prior bank mapping.
u8 __farpeek8(u8 bank, u16 addr);
// Temporarily select bank and read a little-endian word, then restore the previous mapping.
u16 __farpeek16(u8 bank, u16 addr);
// Return the low byte of the mapper number selected for this build; no cartridge probe is performed.
u8 __mapper_id(void);
// Select a CNROM bank or MMC3 register 0 bank; unsupported mapper profiles produce a compile error.
void __chr_bank_set(u8 bank);
// Use the same CNROM/MMC3 register 0 selection as __chr_bank_set.
void __chr_bank_set0(u8 bank);
// Select MMC3 register 1, or the same full CNROM bank register; this is mapper-specific banking.
void __chr_bank_set1(u8 bank);
// Emit the selected mapper mirroring operation; available modes and writable control depend on the board.
void __mirroring_set(u8 mode);
// Write the MMC3 IRQ latch and reload registers. This does not enable IRQ delivery.
void __irq_scanline_set(u8 line);
// Alias the MMC3 IRQ latch/reload operation; other mapper profiles are rejected.
void __mapper_irq_set(u8 scanline);
// Write MMC3 E001. The CPU IRQ mask and a valid handler are separate caller responsibilities.
void __mapper_irq_enable(void);
// Write MMC3 E000 to disable and acknowledge mapper IRQs.
void __mapper_irq_disable(void);
// Use the same E000 write as disable; explicitly re-enable when another interrupt is needed.
void __mapper_irq_ack(void);
// Wait for the current hit flag to clear, then for a new hit. No timeout is provided.
void __sprite0_wait_hit(void);
// Wait for a new sprite-zero hit, reset the PPU latch and write X/Y scroll; requires a visible hit setup.
void __split_scroll_sprite0(u8 x, u8 y);
#endifkitaqfc/lib/mapper.h
math_fast.h — Calcul entier rapide
#ifndef MATH_FAST_H
#define MATH_FAST_H
#include "intrinsics.h"
/*
* Fast math primitives are compiler intrinsics. These declarations are kept
* here so game code can include a game-facing math header instead of the full
* intrinsic surface.
*/
// Return abs(x1-x2)+abs(y1-y2) modulo 256; large distances are not saturated.
u8 __manhattan(u8 x1, u8 y1, u8 x2, u8 y2);
// Return 0 or 1 for half-open bounds. Zero extents are empty; coordinates do not wrap across 255.
u8 __xy_in_rect(u8 x, u8 y, u8 rx, u8 ry, u8 rw, u8 rh);
// Return y*width+x as a word without checking coordinates against map dimensions.
u16 __map_index(u8 x, u8 y, u8 width);
// Advance the shared 16-bit LFSR and return the XOR of its two bytes; zero state is reseeded to A55A.
u8 __rng8(void);
// Replace both persistent state bytes. Reusing a seed reproduces the sequence; this is not cryptographic randomness.
void __rng_seed(u16 seed);
#endifkitaqfc/lib/math_fast.h
math_fixed.h — Interface intrinsèque de calcul en virgule fixe
#ifndef MATH_FIXED_H
#define MATH_FIXED_H
#include "intrinsics.h"
/* Fixed-point helpers are compiler-recognized intrinsic entry points. */
// Return the high byte of the unsigned 8-by-8 product, equivalent to floor(a*b/256).
u8 __mul8x8_hi(u8 a, u8 b);
// Return the low word of the unsigned product; overflow wraps without saturation.
u16 __mul16x8(u16 a, u8 b);
// Interpret a and b as signed two's-complement bit patterns and return the low word of their product.
u16 __smul16x8(u16 a, u8 b);
// Return acc+a*b modulo 65536 using unsigned multiplication.
u16 __mac16(u16 acc, u16 a, u8 b);
// Add the signed-pattern product to acc modulo 65536; the API carries the result as u16 bits.
u16 __smac16(u16 acc, u16 a, u8 b);
// Return a0*b0+a1*b1 modulo 65536. The FC backend inserts no Q8.8 rescaling or rounding.
u16 __dot2_q8_8(u16 a0, u16 a1, u8 b0, u8 b1);
// Sum three unsigned word-by-byte products modulo 65536 without a final scaling shift.
u16 __dot3_q8_8(u16 a0, u16 a1, u16 a2, u8 b0, u8 b1, u8 b2);
// Sum two signed-pattern products modulo 65536; no Q8.8 scaling shift is generated.
u16 __sdot2_q8_8(u16 a0, u16 a1, u8 b0, u8 b1);
// Sum three signed-pattern products modulo 65536; choose operand units explicitly in the caller.
u16 __sdot3_q8_8(u16 a0, u16 a1, u16 a2, u8 b0, u8 b1, u8 b2);
#endifkitaqfc/lib/math_fixed.h
math_lut.h — Tables de correspondance
#ifndef MATH_LUT_H
#define MATH_LUT_H
// Uniform 256-phase unsigned sine table in ROM. Range 1..255, centered at 128.
// Link math_lut.c once; indices 0..255 are valid and byte phase wrap is supported.
extern unsigned char MATH_SIN[256];
#endifkitaqfc/lib/math_lut.h
metasprite.h — Images composées de plusieurs sprites
/*
* Optional declarations for the phase 10 NES metasprite helper.
*
* Metasprite data layout:
* [dx, dy, tile, attr] repeated, terminated by dx=0xFF
*/
// Read four-byte records [dx,dy,tile,attr] until dx=0xFF, writing them to
// shadow OAM. Coordinates and destination offsets wrap as bytes. The caller
// must supply a terminator and enough unused slots; there is no capacity guard.
// Return the next slot index derived from the final wrapped byte offset.
unsigned char nes_metasprite_draw(unsigned char oam_index, unsigned char base_x, unsigned char base_y, unsigned char* metasprite);
// Compiler intrinsic counterpart; this declaration does not route through the C function above.
unsigned char __metasprite_draw(unsigned char oam_index, unsigned char base_x, unsigned char base_y, const unsigned char* metasprite);
// Hide consecutive shadow slots by setting Y to 0xF8. Keep the requested
// range within 64 slots to avoid wrapping and hiding earlier entries.
void nes_metasprite_hide_from(unsigned char oam_index, unsigned char sprite_count);kitaqfc/lib/metasprite.h
mic.h — Entrée microphone
#ifndef MIC_H
#define MIC_H
#define VOICE_H
#include "intrinsics.h"
// Return controller-port 4016 bit 2 normalized to 0 or 1; this is a microphone level bit, not PCM audio.
u8 __joypad2p_voice(void);
// Alias the same normalized microphone input bit as __joypad2p_voice.
u8 __mic_read2p(void);
#endifkitaqfc/lib/mic.h
midi.h — Interface d'entrée et de sortie MIDI
#ifndef MIDI_H
#define MIDI_H
#include "intrinsics.h"
// Write bit & 1 to 4016, replacing the port output value; coordinate with other port users.
void __serial_tx_bit(u8 bit);
// Read 4017 bit 4 and normalize it to 0 or 1; an external serial adapter supplies the signal.
u8 __serial_rx_bit(void);
// Send start-low, eight least-significant-first bits and stop-high using fixed NOP delays.
// Instruction and interrupt overhead is additional; the emitted loop does not establish a verified MIDI baud rate.
void __midi_out_byte(u8 byte);
// Block for a low start signal and sample eight bits. No timeout, framing check or receive buffer is provided.
u8 __midi_in_byte(void);
// Send 90|(ch&0F), note and velocity. Supply 7-bit data bytes; they are not masked by this helper.
void __midi_note_on(u8 ch, u8 note, u8 velocity);
// Send 80|(ch&0F), note and velocity through the same synchronous serial path.
void __midi_note_off(u8 ch, u8 note, u8 velocity);
// Send B0|(ch&0F), controller and value; both data arguments must be valid 7-bit values.
void __midi_control_change(u8 ch, u8 cc, u8 value);
// Send C0|(ch&0F) followed by the caller-supplied 7-bit program value.
void __midi_program_change(u8 ch, u8 program);
// Transmit the single realtime byte F8 synchronously; this does not schedule future ticks.
void __midi_clock(void);
// Transmit realtime Start (FA) through the serial adapter path.
void __midi_start(void);
// Transmit realtime Continue (FB) through the serial adapter path.
void __midi_continue(void);
// Transmit realtime Stop (FC) through the serial adapter path.
void __midi_stop(void);
#endifkitaqfc/lib/midi.h
nametable_asset.h — Ressources et placement des tables de noms
/*
* Optional declarations for phase12 nametable / attribute asset helpers.
*/
extern unsigned char nes_attr_shadow[64];
// Mask the index to the four logical nametables and return its PPU base.
// Physical storage still depends on the cartridge's mirroring configuration.
unsigned short nes_nt_base_from_index(unsigned char index);
// Locate the 64-byte attribute table at offset 0x03C0 from a nametable base.
unsigned short nes_attr_base_from_nt(unsigned short nt_base);
// Fill all 64 shadow bytes with an already-packed attribute value.
void nes_attr_shadow_clear(unsigned char value);
// Copy an entire packed attribute table into shadow RAM without writing the PPU.
void nes_attr_shadow_copy(unsigned char* src64);
// Replace only the chosen quadrant's palette bits, preserving its neighbors.
// Palette IDs are masked to two bits; tile coordinates must fit the shadow table.
void nes_attr_shadow_set_quad(unsigned char tile_x, unsigned char tile_y, unsigned char pal_index);
// Upload all attribute shadow bytes immediately; the caller provides safe PPU timing.
void nes_attr_apply_now(unsigned short nt_base);
// Copy all shadow attribute bytes into the runtime queue and return its admission result.
unsigned char nes_attr_queue_all(unsigned short nt_base);
// Write one complete 32-tile row directly. The caller validates the row and PPU timing.
void nes_nt_stream_row(unsigned short nt_base, unsigned char row, unsigned char* src32);
// Copy one complete nametable row into the runtime queue.
unsigned char nes_nt_queue_row(unsigned short nt_base, unsigned char row, unsigned char* src32);
// Write each rectangle row immediately, advancing source by pitch rather than
// width. Caller-provided coordinates, storage and timing are not clipped or checked.
void nes_nt_stream_rect(unsigned short nt_base, unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height, unsigned char pitch, unsigned char* src);
// Copy rows into the runtime queue until complete or full. Failure leaves
// earlier rows queued; it does not roll back a partially admitted rectangle.
// Widths must respect the queue literal-record limit.
// Pitch is source bytes per row. Each copied literal record costs width+3 queue bytes;
// check total admission needs when partial updates are unacceptable.
unsigned char nes_nt_queue_rect(unsigned short nt_base, unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height, unsigned char pitch, unsigned char* src);
// Queue one fill record per row, stopping on failure while retaining previously
// queued rows. The runtime fill-length and rectangle bounds requirements apply.
unsigned char nes_nt_queue_fill_rect(unsigned short nt_base, unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height, unsigned char value);
// Upload 960 tile bytes followed by 64 attribute bytes. This bulk operation
// does not disable rendering or wait for VBlank on its own.
void nes_nametable_apply_now(unsigned short nt_base, unsigned char* nam960, unsigned char* attr64);kitaqfc/lib/nametable_asset.h
nes_game.h — Macros d'opérations pour les jeux
#ifndef NES_GAME_H
#define NES_GAME_H
#include "core.h"
#include "intrinsics.h"
/*
* AI-friendly NES operation aliases.
*
* These names intentionally describe gameplay-side operations. They are thin
* aliases over KITAQFC intrinsics so the compiler can still record the exact
* NES action for diagnostics and KUROSAKI metadata.
*/
// These aliases use the compiler intrinsic queue. They do not select the separate C runtime queue.
#define nes_vram_put(addr, value) __vramq_put((addr), (value))
#define nes_vram_copy(addr, src, len) __vramq_copy((addr), (src), (len))
#define nes_vram_fill(addr, value, len) __vramq_fill((addr), (value), (len))
#define nes_vram_commit() __vramq_commit()
#define nes_vram_clear_queue() __vramq_clear()
#define nes_oam_clear() __oam_clear()
// This zero-argument macro hides the same-named page-argument C runtime function in included code.
#define nes_oam_dma() __oam_dma()
#define nes_sprite_set(i,x,y,t,a) __sprite_set((i),(x),(y),(t),(a))
#define nes_sprite_move(i,x,y) __sprite_move((i),(x),(y))
#define nes_sprite_hide(i) __sprite_hide((i))
// Select the compiler intrinsic implementation even when the C metasprite header is also included.
#define nes_metasprite_draw(i,x,y,data) __metasprite_draw((i),(x),(y),(data))
#define nes_pad1() __pad_read1_safe()
#define nes_pad2() __pad_read2_safe()
#define nes_mapper_irq_set(scanline) __mapper_irq_set((scanline))
#define nes_mapper_irq_enable() __mapper_irq_enable()
#define nes_mapper_irq_disable() __mapper_irq_disable()
#define nes_mapper_irq_ack() __mapper_irq_ack()
#define nes_split_scroll_sprite0(x,y) __split_scroll_sprite0((x),(y))
#define nes_fds_wave_load(wave64) __fds_wave_load((wave64))
#define nes_fds_load_bank(bank) __fds_load_bank((bank))
#define nes_fds_farcall(bank, func) __fds_overlay_farcall((bank), (func))
#endifkitaqfc/lib/nes_game.h
oam.h — Opérations sur la copie de travail de l'OAM
#ifndef OAM_H
#define OAM_H
#include "intrinsics.h"
// Set OAMADDR to zero and start DMA from CPU page 02; arrange safe PPU timing in the caller.
void __oam_dma(void);
// Set OAMADDR to zero and DMA 256 bytes from page<<8. The source page must remain readable.
void __oam_dma_page(u8 page);
// Hide all 64 page-02 shadow sprites by writing Y=F0; hardware OAM changes only after DMA.
void __oam_clear(void);
// Write Y, tile, attributes and X to one shadow entry. Use indices 0..63; coordinates are raw OAM bytes.
void __sprite_set(u8 index, u8 x, u8 y, u8 tile, u8 attr);
// Replace only shadow X/Y for index 0..63; tile and attribute bytes remain unchanged.
void __sprite_move(u8 index, u8 x, u8 y);
// Replace the selected shadow tile byte; this does not upload tile patterns.
void __sprite_tile(u8 index, u8 tile);
// Replace the selected shadow attribute byte, including palette, priority and flip bits.
void __sprite_attr(u8 index, u8 attr);
// Write F0 to the selected shadow Y byte; issue DMA to make the change visible.
void __sprite_hide(u8 index);
#endifkitaqfc/lib/oam.h
oam_fair.h — Rotation des sprites avec priorités
#ifndef KQ_OAM_FAIR_H
#define KQ_OAM_FAIR_H
#include "core.h"
/* 64-entry software sprite pool. Define the five arrays/cursor declared below
* and include oam_fair_impl.h in ONE translation unit, in a fixed PRG bank.
* X/Y are center coordinates, ACTIVE is a byte array. OAM is a 256-byte
* DMA shadow; USED is its byte cursor. Entries already in OAM stay first.
* The odd stride selects every starting entry over 64 calls. Hardware still
* has a 64-sprite / 8-sprite-per-scanline limit: this distributes flicker.
* Call only from the main loop; commit the completed OAM in VBlank.
*/
extern u8 oam_fair_phase;
extern u8 oam_fair_x[64];
extern u8 oam_fair_y[64];
extern u8 oam_fair_active[64];
extern u8 oam_fair_shadow[256];
extern u8 oam_fair_used;
extern u8 oam_fair_limit;
extern u8 oam_fair_tile;
extern u8 oam_fair_attr;
extern u8 oam_fair_drawn;
// Append active pool entries using the configured common tile/attributes. The emitter stops at byte cursor 252,
// leaving slot 63 unused to avoid cursor wrap. Hide unused trailing OAM entries separately before DMA.
void OAM_FairDraw(void);
#endifkitaqfc/lib/oam_fair.h
oam_fair_impl.h — Implémentation de la rotation des sprites
#include "oam_fair.h"
u8 oam_fair_phase;
u8 oam_fair_limit;
u8 oam_fair_tile;
u8 oam_fair_attr;
u8 oam_fair_drawn;
u8 oam_fair_scanned;
// Rotate the starting pool entry by 13 modulo 64, then append active sprites
// until the caller's draw limit or OAM byte cursor limit is reached. Coordinates
// describe 8x8 centers: subtract four for X and five for raw OAM Y. Include once
// and invoke it from the main loop with a four-byte-aligned used cursor.
void OAM_FairDraw(void) {
__asm {
LDA oam_fair_phase
CLC
ADC #13
AND #63
STA oam_fair_phase
TAX
LDY oam_fair_used
LDA #0
STA oam_fair_drawn
STA oam_fair_scanned
// Visit each pool entry at most once, preserving already-written OAM entries
// and sharing the configured tile/attribute values across emitted sprites.
kq_fair_loop:
LDA oam_fair_active,X
BEQ kq_fair_next
LDA oam_fair_drawn
CMP oam_fair_limit
BCS kq_fair_done
// Reserve the final four-byte slot so advancing this byte cursor cannot wrap to zero.
CPY #252
BCS kq_fair_done
// Convert the 8x8 center to raw OAM coordinates; Y also needs the hardware minus-one bias.
LDA oam_fair_y,X
SEC
SBC #5
STA oam_fair_shadow,Y
LDA oam_fair_tile
STA oam_fair_shadow+1,Y
LDA oam_fair_attr
STA oam_fair_shadow+2,Y
LDA oam_fair_x,X
SEC
SBC #4
STA oam_fair_shadow+3,Y
INY
INY
INY
INY
INC oam_fair_drawn
// Advance cyclically and stop after returning to this frame's starting entry.
kq_fair_next:
TXA
CLC
ADC #1
AND #63
TAX
CPX oam_fair_phase
BNE kq_fair_loop
// Publish the updated byte cursor for later OAM writers and the VBlank DMA path.
kq_fair_done:
STY oam_fair_used
}
}kitaqfc/lib/oam_fair_impl.h
pad.h — Entrées des manettes NES
/*
* Optional declarations for the phase 8 NES pad runtime.
*
* Button bit layout in nes_pad1_cur / pressed / released:
* bit0=A bit1=B bit2=Select bit3=Start bit4=Up bit5=Down bit6=Left bit7=Right
*/
extern unsigned char nes_pad1_cur;
extern unsigned char nes_pad1_prev;
extern unsigned char nes_pad1_pressed;
extern unsigned char nes_pad1_released;
// Latch controller input with a 1-to-0 strobe and shift eight controller-1 bits
// into held/pressed/released masks. This direct path does not perform repeated
// reads for DMC interference; the final JOY2 read does not populate player-2 state.
void nes_pad_poll(void);kitaqfc/lib/pad.h
palette.h — Palettes NES
/*
* Optional declarations for the phase 11 NES palette helper.
*/
extern unsigned char nes_palette_shadow[32];
// Copy exactly 32 palette bytes to the fixed shadow buffer without writing the PPU.
void nes_palette_copy(unsigned char* src32);
// Replace shadow palette data and upload all 32 bytes immediately. The caller
// provides a safe PPU access period; this helper does not wait for VBlank.
void nes_palette_apply_now(unsigned char* src32);
// Upload the current palette shadow directly, with timing controlled by the caller.
void nes_palette_apply_shadow_now(void);
// Update the shadow and copy all colors into the runtime queue. A queue
// failure leaves the new shadow contents in place.
// Return one if the runtime queue accepted the copied payload, zero if it was full.
// Admission does not mean the NMI consumer has already updated the PPU.
unsigned char nes_palette_queue_all(unsigned char* src32);
// Update and queue four background palette bytes. pal_index must be 0..3;
// there is no range check before writing the shadow.
unsigned char nes_palette_queue_bg4(unsigned char pal_index, unsigned char* src4);
// Update and queue four sprite palette bytes at the 0x3F10 region. The
// caller supplies pal_index 0..3; NES palette mirroring still applies.
unsigned char nes_palette_queue_sprite4(unsigned char pal_index, unsigned char* src4);kitaqfc/lib/palette.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"
// Lightweight deterministic 2D physics for KITAQFC.
// 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 uses non-reentrant helper 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 by a signed eight-bit coefficient divided by 256.
// 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);
// Optional byte-sized eighth-pixel channels for small custom update loops.
#define KQ2D_SUBPIXEL_BITS ((u8)3)
#define KQ2D_SUBPIXEL_ONE ((u8)8)
#define KQ2D_SUBPIXEL_MASK ((u8)7)
// Optional byte-channel identifiers for application-specific movement.
#define KQ2D_DRAG_BRAKE ((u8)1)
#define KQ2D_DRAG_STUN ((u8)2)
#define KQ2D_DRAG_COAST ((u8)3)
#define KQ2D_DRAG_THRUST ((u8)4)
#define KQ2D_DIR_NONE ((u8)0)
#define KQ2D_DIR_NEGATIVE ((u8)1)
#define KQ2D_DIR_POSITIVE ((u8)2)
/*
* Byte-sized Q5.3 channels for KITAQFC.
*
* Keep the channels as flat game-state fields in a hot loop. That avoids
* aggregate/pointer call traffic while retaining eighth-pixel integration.
*/
// Store integer pixel position separately from the 0..7 fractional remainder.
// Speed is an unsigned eighth-pixel magnitude; direction is a separate channel.
typedef u8 KQ2DPosition;
typedef u8 KQ2DFraction;
typedef u8 KQ2DSpeed;
typedef u8 KQ2DDirection;kitaqfc/lib/physics2d.h
physics3d.h — Physique des AABB en 3D
#pragma once
#include "core.h"
// Lightweight deterministic 3D physics for KITAQFC.
// 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 uses non-reentrant helper 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, dividing each by 256 (toward zero) 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);kitaqfc/lib/physics3d.h
ppu.h — Déclarations d'affichage PPU
#ifndef PPU_H
#define PPU_H
// Link ppu.c. Bulk palette/nametable transfers require rendering to be disabled.
// Disable background and sprite rendering, preserving other PPUMASK bits.
void nes_ppu_screen_off(void);
// Set scroll to (0,0), then apply the requested PPUCTRL and PPUMASK values.
void nes_ppu_screen_on(unsigned char ctrl, unsigned char mask);
// Copy 32 bytes into $3F00..$3F1F with increment one; preserve PPUCTRL.
// Null is ignored. Hardware palette mirrors apply; source bank must stay mapped.
void nes_ppu_load_palette(unsigned char* pal32);
// Fill 960 tiles and 64 packed attributes; preserve PPUCTRL.
// Accept exactly $2000/$2400/$2800/$2C00; invalid bases are ignored.
void nes_ppu_clear_nt(unsigned short nt_base, unsigned char tile, unsigned char attr);
// Address-byte variants reset the latch and coexist with runtime.c's word seek.
void nes_ppu_seek_bytes(unsigned char hi, unsigned char lo);
// Direct transfers follow the current PPUCTRL increment; count is 0..255.
void nes_ppu_write_bytes(unsigned char hi, unsigned char lo, const unsigned char* src, unsigned char count);
void nes_ppu_fill(unsigned char hi, unsigned char lo, unsigned char value, unsigned char count);
#endifkitaqfc/lib/ppu.h
ppu_direct.h — Opérations directes sur le PPU
#ifndef PPU_DIRECT_H
#define PPU_DIRECT_H
#include "intrinsics.h"
/* Direct PPU access. Use only during vblank or when rendering is disabled. */
// Invoke the compiler rendering-enable helper; this header contains declarations, not C fallback implementations.
void __ppu_on(void);
// Invoke the compiler rendering-disable helper before bulk direct PPU updates.
void __ppu_off(void);
// Replace PPUMASK with the supplied byte; the caller chooses rendering, clipping and emphasis bits.
void __ppu_mask_set(u8 value);
// Replace PPUCTRL, including NMI enable, pattern-table choices and address increment mode.
void __ppu_ctrl_set(u8 value);
// Set the PPU address through the compiler helper; address writes affect the shared scroll/address latch.
void __ppu_addr(u16 ppu_addr);
// Write one PPUDATA byte using the current PPU address and increment mode.
void __ppu_data(u8 value);
// Read PPUSTATUS; the hardware clears VBlank status and resets the shared write latch.
u8 __ppu_read_status(void);
// Write a byte-counted source range directly; arrange PPU access timing and source-bank visibility.
void __vram_write(u16 ppu_addr, const u8* src, u8 len);
// Write repeated bytes directly; this is not an enqueue operation.
void __vram_fill(u16 ppu_addr, u8 value, u8 len);
#endifkitaqfc/lib/ppu_direct.h
rob.h — Commandes de ROB
#ifndef ROB_H
#define ROB_H
#include "intrinsics.h"
// Set PPUMASK and its shadow to 1E or 00, then wait for an NMI-counter change.
// The caller supplies image/palette brightness; rendering enable alone does not create a white screen.
void __rob_flash(u8 bright);
// Run on_frames enabled-mask waits followed by off_frames disabled-mask waits; NMI must advance.
void __rob_pulse(u8 on_frames, u8 off_frames);
// Send eight bits MSB first, using 4/2-frame pulses for one and 2/4 for zero.
// Preserve the outer bit counter and shifted pattern around each pulse helper.
void __rob_send_byte(u8 pattern);
#endifkitaqfc/lib/rob.h
runtime.h — Fonctions C pour NMI, OAM et transferts PPU
/*
* Core NES runtime declarations.
*
* Declare frame waits, direct PPU transfers, OAM DMA and the copied-payload VRAM queue.
*/
// The four-byte record follows hardware OAM byte order: Y, tile, attributes, X.
struct NesSprite4 {
unsigned char y;
unsigned char tile;
unsigned char attr;
unsigned char x;
};
extern unsigned char nes_nmi_counter;
extern unsigned char nes_oam_shadow[256];
// This counter measures the separate 192-byte copied-payload runtime queue, not the compiler intrinsic queue.
extern unsigned char nes_vram_queue_used;
extern unsigned char nes_vram_queue_overflow;
// Wait until the NMI handler advances its counter. NMI must already be enabled
// and able to execute; this polling loop has no timeout.
void nes_wait_nmi(void);
// Wait for the current VBlank to end, then for the next one to begin. Each
// PPUSTATUS read has hardware side effects, including clearing the VBlank flag.
void nes_vblank_wait(void);
// Reset the PPU address latch with a status read, then write the high/low address bytes.
void nes_ppu_seek(unsigned short ppu_addr);
// Write len source bytes directly through PPUDATA. Call only during an appropriate
// PPU access period; the address increment mode comes from the current PPUCTRL.
void nes_ppu_stream_write(unsigned short ppu_addr, unsigned char* src, unsigned short len);
// Write value repeatedly through PPUDATA, using the current PPU address increment
// mode. This routine does not wait for VBlank or disable rendering.
void nes_ppu_stream_fill(unsigned short ppu_addr, unsigned char value, unsigned short len);
// Reset the OAM destination and DMA one 256-byte CPU page. The hardware stalls
// the CPU during transfer; page is the source address high byte.
void nes_oam_dma(unsigned char page);
// Discard pending VRAM commands and clear the overflow latch; no PPU writes occur.
void nes_vram_queue_clear(void);
// Copy a literal payload into the queue and publish its new used length last.
// Accept lengths 0..127; reject larger lengths and latch overflow without changing the queue.
// The caller must ensure queue production cannot race its NMI consumer.
unsigned char nes_vram_queue_try_write(unsigned short ppu_addr, unsigned char* src, unsigned char len);
// Queue a four-byte fill record: address high/low, length with bit 7 set, value.
// Reject lengths above 127 and latch overflow on any capacity/format failure.
unsigned char nes_vram_queue_try_fill(unsigned short ppu_addr, unsigned char value, unsigned char len);
// Consume complete records in order during a safe PPU access period. Reading
// PPUSTATUS resets the shared address latch before each address pair. The caller
// is responsible for ensuring the transfer fits its NMI/VBlank time budget.
void nes_vram_queue_nmi_flush(void);kitaqfc/lib/runtime.h
scene.h — Enregistrement, changement et mise à jour des scènes
#ifndef SCENE_H
#define SCENE_H
#include "core.h"
typedef void (*SceneFunc)(void);
typedef __packed struct SceneDef {
SceneFunc enter;
SceneFunc update;
SceneFunc draw;
SceneFunc exit;
} SceneDef;
// One shared in-flight transfer. remaining counts source bytes not yet copied into the queue.
// An inactive stream may still have commands awaiting the NMI consumer.
struct NesSceneStreamState {
unsigned char* src;
unsigned short ppu_addr;
unsigned short remaining;
unsigned char chunk;
unsigned char active;
};
extern struct NesSceneStreamState nes_scene_stream_state;
// 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();
// Replace the single active transfer and retain its source pointer. Keep the
// source storage and any required ROM bank readable until all bytes are queued.
void nes_scene_stream_begin(unsigned short ppu_addr, unsigned char* src, unsigned short len, unsigned char chunk);
// Prepare the 960-byte tile portion of a nametable using 32-byte queue records.
void nes_scene_stream_begin_nametable(unsigned short nt_base, unsigned char* src960);
// Prepare the 64-byte attribute table at nametable base + 0x03C0.
void nes_scene_stream_begin_attr(unsigned short nt_base, unsigned char* src64);
// Prepare a 32-byte palette transfer to PPU address 0x3F00.
void nes_scene_stream_begin_palette(unsigned char* src32);
// Queue as many chunks as available capacity allows, capped at 127 bytes each.
// Return one when queue exhaustion requires a later retry, zero when all data has
// been queued. Zero does not mean the NMI consumer has already written the PPU.
unsigned char nes_scene_stream_step(void);
#endifkitaqfc/lib/scene.h
scroll.h — Arrière-plan, fenêtre et défilement fractionné
/*
* Optional declarations for the phase 9 NES scroll helper.
*/
extern unsigned char nes_scroll_ctrl_base;
extern unsigned short nes_scroll_camera_x;
extern unsigned short nes_scroll_camera_y;
// Store PPUCTRL bits other than the two nametable-selection bits for later application.
void nes_scroll_set_base_ctrl(unsigned char ctrl);
// Store camera coordinates without touching hardware registers.
void nes_scroll_set(unsigned short camera_x, unsigned short camera_y);
// Combine bit 8 of each camera coordinate with base PPUCTRL, reset the latch
// by reading PPUSTATUS, and write low-byte X/Y scroll. This uses 256-unit
// wrapping on both axes rather than normalizing Y to a 240-pixel nametable height.
// Initialize base control to the intended PPUCTRL value, including NMI enable, before applying.
// Only coordinate bits 0..8 are used; arrange safe PPU timing in the caller.
void nes_scroll_apply(void);
// Subtract the screen anchor from the world point into unsigned camera
// coordinates. Underflow wraps; world-edge clamping belongs to the game.
void nes_camera_follow_center(unsigned short target_x, unsigned short target_y, unsigned char center_x, unsigned char center_y);kitaqfc/lib/scroll.h
sprite.h — Allocation d'OBJ, placement, métasprites et animation
#ifndef SPRITE_H
#define SPRITE_H
#include "core.h"
#include "intrinsics.h"
// Keep this value within 1..64; tracking arrays and hardware OAM contain exactly 64 slots.
#ifndef SPRITE_MAX
#define SPRITE_MAX ((u8)64)
#endif
#define SPRITE_FLAG_PAL1 ((u8)0x01)
#define SPRITE_FLAG_PAL2 ((u8)0x02)
#define SPRITE_FLAG_PAL3 ((u8)0x03)
#define SPRITE_FLAG_PRIORITY ((u8)0x20)
#define SPRITE_FLAG_XFLIP ((u8)0x40)
#define SPRITE_FLAG_YFLIP ((u8)0x80)
// Signed per-part offsets are added modulo 256. This struct API has an explicit count,
// unlike the FF-terminated byte-stream API in metasprite.h.
typedef struct MetaSpritePart {
s8 dx;
s8 dy;
u8 tile;
u8 flags;
} MetaSpritePart;
// Initialize frame/ticks to valid values. Returned tile IDs advance by one regardless of hardware sprite size.
typedef struct SpriteAnim {
u8 first_tile;
u8 frame_count;
u8 frame;
u8 ticks;
u8 ticks_per_frame;
} SpriteAnim;
extern u8 kq_sprite_active[64];
extern u8 kq_sprite_used;
extern u8 kq_sprite_height;
// Reset allocation/position state and hide each OAM slot through the intrinsic.
// The software height defaults to eight; hardware sprite size is configured elsewhere.
void sprite_init(void);
// Claim and hide the first free slot, or return 0xFF if all slots are active.
u8 sprite_alloc(void);
// Release an active valid slot and hide it; invalid/repeated frees are ignored.
void sprite_free(u8 id);
// Update software coordinates and the intrinsic OAM position for a valid slot.
void sprite_set_pos(u8 id, u8 x, u8 y);
// Replace the tile byte of a valid OAM slot without changing allocation state.
void sprite_set_tile(u8 id, u8 tile);
// Replace the hardware attribute byte of a valid OAM slot.
void sprite_set_flags(u8 id, u8 flags);
// Mark the software position off screen and hide its OAM entry without freeing it.
void sprite_hide(u8 id);
// Transfer intrinsic shadow OAM immediately; this wrapper does not wait for VBlank.
void sprite_flush_oam_now(void);
// Wait for NMI before requesting OAM DMA.
void sprite_flush_oam(void);
// 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(void);
// Flag software overlap estimates above eight sprites on one scanline.
u8 sprite_warn_scanline_overflow(void);
// Estimate peak overlap across 240 lines from software Y/height values.
// This does not model pixel transparency, OAM priority or every hardware overflow quirk.
u8 sprite_max_scanline_count(void);
// 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 and wrap the frame index, returning the selected tile.
// Zero ticks-per-frame freezes advancement; null state returns zero.
u8 anim_update(SpriteAnim* anim);
#endifkitaqfc/lib/sprite.h
system.h — Démarrage, compteurs d'images, attentes et interruptions
#ifndef SYSTEM_H
#define SYSTEM_H
#include "core.h"
#include "intrinsics.h"
// A synchronous callback invoked after the software frame count is incremented.
typedef void (*SystemCallback)(void);
extern u16 kq_system_frame;
// Reset the software frame counter and callback storage, then enable NMI.
void system_init(void);
// Wait for NMI, count the completed wait, then invoke the registered callback.
void system_wait_vblank(void);
// Replace the per-wait callback; null disables callback dispatch.
void system_set_vblank_callback(SystemCallback callback);
// Return the wrapping 16-bit count of completed waits through this wrapper.
u16 system_get_frame(void);
// Return the low byte of the software frame counter.
u8 system_get_frame8(void);
// Enable maskable CPU IRQs through the intrinsic; NMI is controlled separately.
void system_enable_interrupts(void);
// Disable maskable CPU IRQs; this does not disable the PPU's NMI source.
void system_disable_interrupts(void);
#define fc_init system_init
#define fc_wait_vblank system_wait_vblank
#define fc_set_vblank_callback system_set_vblank_callback
#define fc_frame_count system_get_frame
#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
#endifkitaqfc/lib/system.h
tilemap.h — Opérations rectangulaires sur les cartes de tuiles
/*
* Optional declarations for the phase 11 tilemap helper.
*/
// The map borrows row-major tile bytes; keep width*height bytes readable in the active CPU mapping.
// solid_from is a tile-ID threshold, not an independent collision bitmap.
struct NesTilemap {
unsigned char* tiles;
unsigned char width;
unsigned char height;
unsigned char solid_from;
};
// Compute a row-major byte offset by adding the row stride ty times. This
// internal arithmetic helper does not validate coordinates.
unsigned short nes_tilemap_index(struct NesTilemap* map, unsigned char tx, unsigned char ty);
// Return a tile byte, or 0xFF when coordinates exceed map dimensions. The
// map/storage pointers must be valid; 0xFF may also be an actual stored tile.
unsigned char nes_tilemap_get(struct NesTilemap* map, unsigned char tx, unsigned char ty);
// Treat out-of-bounds/0xFF tiles as solid, then compare other tile IDs with
// the map's solid_from threshold.
unsigned char nes_tilemap_point_solid(struct NesTilemap* map, unsigned char tx, unsigned char ty);
// Convert pixels to eight-pixel tile X and narrow to a byte. Keep world X
// below 2048 when wraparound is not intended.
unsigned char nes_world_to_tile8_x(unsigned short world_x);
// Convert pixels to eight-pixel tile Y with the same byte-coordinate limit.
unsigned char nes_world_to_tile8_y(unsigned short world_y);
// Convert a world point to tile coordinates and apply the tile solidity rule.
unsigned char nes_tilemap_world_point_solid(struct NesTilemap* map, unsigned short world_x, unsigned short world_y);
// Test only the four corners of a nonempty world box. Interior/edge tiles
// between the corners are not scanned, so large boxes can miss obstacles.
// Width/height must be nonzero and endpoint arithmetic must not overflow.
unsigned char nes_tilemap_world_box_solid(struct NesTilemap* map, unsigned short world_x, unsigned short world_y, unsigned char width, unsigned char height);kitaqfc/lib/tilemap.h
vram.h — Mises à jour et transferts VRAM en file
#ifndef VRAM_H
#define VRAM_H
#include "core.h"
#include "intrinsics.h"
// Coordinates use 32-byte nametable rows. These wrappers do not clip to the 32x30 visible tile area.
#ifndef VRAM_NT_BASE
#define VRAM_NT_BASE ((u16)0x2000)
#endif
// Clear the intrinsic queue and its overflow latch.
void vram_init(void);
// Discard queued commands and explicitly reset the overflow latch.
void vram_clear_queue(void);
// Queue one tile at the default nametable base. Return the current overflow
// status, which may include a failure from an earlier operation.
u8 vram_queue_bg_tile(u8 x, u8 y, u8 tile);
// Alias the queued background-tile operation.
u8 vram_queue_tile(u8 x, u8 y, u8 tile);
// Queue one fill per row. This is not transactional: capacity exhaustion can
// leave earlier rows queued, and the loop continues attempting later rows.
u8 vram_queue_bg_rect(u8 x, u8 y, u8 w, u8 h, u8 tile);
// Queue each tightly packed source row as a pointer-based copy record. Keep
// source storage and its ROM bank accessible until queue execution finishes;
// partial queuing remains possible on overflow.
u8 vram_queue_bg_block(u16 base, u8 x, u8 y, u8 w, u8 h, const u8* src);
// Split a byte transfer into copy records of at most 127 bytes. The runtime
// retains source pointers rather than copying payloads into the queue. Return
// the overflow latch state after all records have been attempted.
u8 vram_queue_memcpy(u16 dst, const void* src, u16 len);
// Alias the byte-copy queue helper; len remains a byte count, not a tile count.
u8 vram_queue_tiles(u16 dst, const void* src, u16 len);
// Queue fills of at most 127 bytes each. Overflow can leave a partially queued
// transfer; no rollback is performed.
u8 vram_queue_memset(u16 dst, u8 value, u16 len);
// Invoke the queue executor directly. Its ready flag must already be set by
// commit, and the caller supplies appropriate PPU timing.
void vram_flush_now(void);
// Commit queued records for consumption and wait for the NMI path.
void vram_flush(void);
// Return the encoded queue length in bytes, not the number of commands.
u8 vram_get_queue_used(void);
// Return the remaining command-buffer capacity in bytes. A command requires
// space for its complete encoded record, including its address and metadata.
// Read before committing: NMI may consume a committed queue asynchronously.
u8 vram_get_queue_free(void);
// Return the queue's total capacity in bytes, independent of its current usage.
// This describes the command buffer, not free space in PPU VRAM.
u8 vram_get_queue_capacity(void);
// Read the overflow latch without clearing it.
u8 vram_get_overflowed(void);
#endifkitaqfc/lib/vram.h
vram_queue.h — Files VRAM traitées par la NMI
#ifndef VRAM_QUEUE_H
#define VRAM_QUEUE_H
#include "intrinsics.h"
/* Safe frame-time VRAM queue. These names are compiler intrinsic entry points. */
// Reset pending intrinsic-queue records; this is separate from runtime.c nes_vram_queue_clear.
void __vramq_clear(void);
// Append one address/value update; use the overflow latch to detect capacity failure.
void __vramq_put(u16 ppu_addr, u8 value);
// Retain the source address for later consumption; keep its storage and bank mapping valid.
void __vramq_copy(u16 ppu_addr, const u8* src, u8 len);
// Append a repeated-byte update; the source value is stored in the record.
void __vramq_fill(u16 ppu_addr, u8 value, u8 len);
// Publish the pending records to the configured consumer. Do not mutate them while consumption can run.
void __vramq_commit(void);
// Execute a ready queue directly; committing and safe PPU timing are caller responsibilities.
void __vramq_exec(void);
// Return encoded bytes currently occupied, not transfer payload bytes or command count.
u8 __vramq_len(void);
// Read the latched capacity failure; reading does not reset it.
u8 __vramq_overflow(void);
// Clear the overflow latch explicitly after handling the failed submission.
void __vramq_clear_overflow(void);
// Return total encoded command-buffer capacity; this is independent of PPU VRAM capacity.
u8 __vramq_capacity(void);
#endifkitaqfc/lib/vram_queue.h
vrc6_sound.h — Extension audio VRC6
#ifndef VRC6_SOUND_H
#define VRC6_SOUND_H
#include "core.h"
// Retained names for raw control codes 0..3; their numeric suffixes are not measured duty percentages.
// The KUROSAKI pulse model uses (code+1)/16 for these codes. Combine with a low volume nibble.
#define VRC6_PULSE_DUTY_12 0x00
#define VRC6_PULSE_DUTY_25 0x10
#define VRC6_PULSE_DUTY_50 0x20
#define VRC6_PULSE_DUTY_75 0x30
#define VRC6_PULSE_GATE 0x80
// Clear channel-enable/high-timer registers and output controls for all VRC6 voices.
// Requires the VRC6 register layout used by this module. No mapper setup or global frequency-control write is included.
void nes_vrc6_silence_all(void);
// Write pulse-1 control and the low 12 timer bits, then enable the channel.
void nes_vrc6_pulse1_set(u8 control, u16 period);
// Write pulse-2 control and the low 12 timer bits, then enable the channel.
void nes_vrc6_pulse2_set(u8 control, u16 period);
// Disable pulse 1 by clearing its high timer/enable register.
void nes_vrc6_pulse1_off(void);
// Disable pulse 2 by clearing its high timer/enable register.
void nes_vrc6_pulse2_off(void);
// Mask the saw accumulation rate to six bits, load a 12-bit timer and enable output.
void nes_vrc6_saw_set(u8 rate, u16 period);
// Disable the saw channel by clearing its high timer/enable register.
void nes_vrc6_saw_off(void);
#endifkitaqfc/lib/vrc6_sound.h
vrc7_sound.h — Audio FM VRC7
#ifndef VRC7_SOUND_H
#define VRC7_SOUND_H
#include "core.h"
#define VRC7_KEY_ON 0x10
#define VRC7_SUSTAIN 0x20
// Write register selection followed immediately by data. No explicit device
// settling delay or cartridge detection is inserted by this wrapper.
// The caller must arrange device timing and serialize register/data pairs against interrupt writers.
void nes_vrc7_write(u8 reg, u8 value);
// Copy eight caller-supplied patch bytes into user-instrument registers 0..7.
void nes_vrc7_set_user_patch(const u8* patch8);
// Validate channel 0..5, then pack a 9-bit frequency, 3-bit block, key flags,
// instrument and volume nibbles into its registers. Volume is the raw hardware
// attenuation field, not a linear loudness value.
void nes_vrc7_channel_set(u8 channel, u8 instrument, u8 volume, u16 fnum, u8 block, u8 key_flags);
// Clear the channel's entire frequency-high/block/key register, not just the
// key-on bit. A later note must restore frequency and block settings.
void nes_vrc7_key_off(u8 channel);
// Key off all six voices and set instrument zero with maximum attenuation.
void nes_vrc7_silence_all(void);
#endifkitaqfc/lib/vrc7_sound.h
wire3d.h — Rendu filaire pour DMG
// Copyright (c) 2026 DAISUKE OBA. SPDX-License-Identifier: MIT
#ifndef KITAQFC_WIRE3D_H
#define KITAQFC_WIRE3D_H
#include "core.h"
#include "intrinsics.h"
// Choose a supported viewport before including wire3d.c. Smaller views reduce
// line work and dirty CHR transfers; all use original one-bit line graphics.
#ifndef WIRE3D_FC_WIDTH
#define WIRE3D_FC_WIDTH 64
#endif
#ifndef WIRE3D_FC_HEIGHT
#define WIRE3D_FC_HEIGHT 48
#endif
#if WIRE3D_FC_WIDTH == 64 && WIRE3D_FC_HEIGHT == 48
#define WIRE3D_FC_TILES 48
#elif WIRE3D_FC_WIDTH == 96 && WIRE3D_FC_HEIGHT == 64
#define WIRE3D_FC_TILES 96
#elif WIRE3D_FC_WIDTH == 128 && WIRE3D_FC_HEIGHT == 96
#define WIRE3D_FC_TILES 192
#else
#error Select 64x48, 96x64 or 128x96 for the wireframe viewport
#endif
#define WIRE3D_FC_VERTEX_LIMIT 24
typedef struct Wire3DFC_Vec3 { s8 x; s8 y; s8 z; } Wire3DFC_Vec3;
typedef struct Wire3DFC_Edge { u8 a; u8 b; } Wire3DFC_Edge;
extern u8 wire3d_transfer_frames;
extern u8 wire3d_uploaded_tiles;
// Own both CHR-RAM pattern tables and nametable zero. Requires writable 8 KiB
// CHR RAM and PRG RAM 0x6800..0x70BF; reserves ZP 0x00..0x0A for drawing/transfer.
// Build with --nes-chr-ram and provide cartridge PRG RAM for the stage.
// Center the viewport, clear video memory, select cyan-on-dark colors and turn
// on background rendering with NMI disabled. Do not run another PPU writer.
void Wire3DFC_Init(void);
// Clear the previous staged drawing. The displayed front image remains intact.
void Wire3DFC_BeginFrame(void);
// Draw a connected, inclusive segment. Endpoints must be -512..511. Pixels
// outside the viewport are clipped; completely outside bounding boxes return.
void Wire3DFC_DrawLine2D(s16 ax,s16 ay,s16 bx,s16 by);
// Rotate a small model-space point in Y/X/Z order. Angles wrap in 32 steps.
// Start with components in -63..63; supply three distinct writable pointers.
void Wire3DFC_RotatePoint(s16* x,s16* y,s16* z,u8 rx,u8 ry,u8 rz);
// Project camera-space coordinates using an integer reciprocal table. Require
// x/y within -127..127 and z within 32..255. Return zero without touching outputs
// on invalid input; success returns one and writes unclipped screen coordinates.
u8 Wire3DFC_ProjectPoint(s16 x,s16 y,s16 z,s16* sx,s16* sy);
// Draw when both endpoints pass the projection range. Near-plane crossings
// are rejected, not intersected with the near plane; screen pixels are clipped.
void Wire3DFC_DrawLine3D(s16 ax,s16 ay,s16 az,s16 bx,s16 by,s16 bz);
// Rotate, translate and project up to 24 vertices, then draw indexed edges.
// Invalid edge indices/depth endpoints are skipped. Model data must remain
// readable in the current PRG mapping. This draws all edges, without face culling.
void Wire3DFC_DrawModel(const Wire3DFC_Vec3* vertices,u8 vertex_count,const Wire3DFC_Edge* edges,u8 edge_count,s16 x,s16 y,s16 z,u8 rx,u8 ry,u8 rz);
// Upload changed tiles to the hidden CHR table in bounded VBlank batches and
// swap only after completion. Blocks across as many frames as needed. The two
// counters report this call's upload batches plus swap, and tile count.
void Wire3DFC_EndFrame(void);
#endifkitaqfc/lib/wire3d.h
wire3d_tables.h —
// Copyright (c) 2026 DAISUKE OBA. SPDX-License-Identifier: MIT
// Generated from round(64*sin(2*pi*i/32)) and round(64*width/z).
// Depths below 32 are rejected. Saturating 256 to 255 at the largest
// viewport/nearest depth bounds the projection error without a ninth bit.
__prg_rom const s8 w3dfc_sin[32]={
0,12,24,36,45,53,59,63,64,63,59,53,45,36,24,12,
0,-12,-24,-36,-45,-53,-59,-63,-64,-63,-59,-53,-45,-36,-24,-12,
};
#if WIRE3D_FC_WIDTH == 64
__prg_rom const u8 w3dfc_recip[256]={
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
128,124,120,117,114,111,108,105,102,100,98,95,93,91,89,87,
85,84,82,80,79,77,76,74,73,72,71,69,68,67,66,65,
64,63,62,61,60,59,59,58,57,56,55,55,54,53,53,52,
51,51,50,49,49,48,48,47,47,46,46,45,45,44,44,43,
43,42,42,41,41,41,40,40,39,39,39,38,38,38,37,37,
37,36,36,36,35,35,35,34,34,34,34,33,33,33,33,32,
32,32,32,31,31,31,31,30,30,30,30,29,29,29,29,29,
28,28,28,28,28,27,27,27,27,27,27,26,26,26,26,26,
26,25,25,25,25,25,25,25,24,24,24,24,24,24,24,23,
23,23,23,23,23,23,23,22,22,22,22,22,22,22,22,21,
21,21,21,21,21,21,21,21,20,20,20,20,20,20,20,20,
20,20,20,19,19,19,19,19,19,19,19,19,19,19,18,18,
18,18,18,18,18,18,18,18,18,18,18,17,17,17,17,17,
17,17,17,17,17,17,17,17,17,16,16,16,16,16,16,16,
};
__prg_rom const u8 w3dfc_row_lo[48]={
0,1,2,3,4,5,6,7,64,65,66,67,68,69,70,71,
128,129,130,131,132,133,134,135,192,193,194,195,196,197,198,199,
0,1,2,3,4,5,6,7,64,65,66,67,68,69,70,71,
};
__prg_rom const u8 w3dfc_row_hi[48]={
104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,
104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,
105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,
};
__prg_rom const u8 w3dfc_tile_row[48]={
0,0,0,0,0,0,0,0,8,8,8,8,8,8,8,8,
16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24,
32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40,
};
#elif WIRE3D_FC_WIDTH == 96
__prg_rom const u8 w3dfc_recip[256]={
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
192,186,181,176,171,166,162,158,154,150,146,143,140,137,134,131,
128,125,123,120,118,116,114,112,110,108,106,104,102,101,99,98,
96,95,93,92,90,89,88,87,85,84,83,82,81,80,79,78,
77,76,75,74,73,72,71,71,70,69,68,68,67,66,65,65,
64,63,63,62,61,61,60,60,59,59,58,57,57,56,56,55,
55,54,54,53,53,53,52,52,51,51,50,50,50,49,49,48,
48,48,47,47,47,46,46,46,45,45,45,44,44,44,43,43,
43,42,42,42,42,41,41,41,40,40,40,40,39,39,39,39,
38,38,38,38,37,37,37,37,37,36,36,36,36,36,35,35,
35,35,35,34,34,34,34,34,33,33,33,33,33,33,32,32,
32,32,32,32,31,31,31,31,31,31,30,30,30,30,30,30,
30,29,29,29,29,29,29,29,28,28,28,28,28,28,28,28,
27,27,27,27,27,27,27,27,26,26,26,26,26,26,26,26,
26,25,25,25,25,25,25,25,25,25,25,24,24,24,24,24,
};
__prg_rom const u8 w3dfc_row_lo[64]={
0,1,2,3,4,5,6,7,96,97,98,99,100,101,102,103,
192,193,194,195,196,197,198,199,32,33,34,35,36,37,38,39,
128,129,130,131,132,133,134,135,224,225,226,227,228,229,230,231,
64,65,66,67,68,69,70,71,160,161,162,163,164,165,166,167,
};
__prg_rom const u8 w3dfc_row_hi[64]={
104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,
104,104,104,104,104,104,104,104,105,105,105,105,105,105,105,105,
105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,
106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,
};
__prg_rom const u8 w3dfc_tile_row[64]={
0,0,0,0,0,0,0,0,12,12,12,12,12,12,12,12,
24,24,24,24,24,24,24,24,36,36,36,36,36,36,36,36,
48,48,48,48,48,48,48,48,60,60,60,60,60,60,60,60,
72,72,72,72,72,72,72,72,84,84,84,84,84,84,84,84,
};
#elif WIRE3D_FC_WIDTH == 128
__prg_rom const u8 w3dfc_recip[256]={
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
255,248,241,234,228,221,216,210,205,200,195,191,186,182,178,174,
171,167,164,161,158,155,152,149,146,144,141,139,137,134,132,130,
128,126,124,122,120,119,117,115,114,112,111,109,108,106,105,104,
102,101,100,99,98,96,95,94,93,92,91,90,89,88,87,86,
85,84,84,83,82,81,80,80,79,78,77,77,76,75,74,74,
73,72,72,71,71,70,69,69,68,68,67,67,66,66,65,65,
64,64,63,63,62,62,61,61,60,60,59,59,59,58,58,57,
57,56,56,56,55,55,55,54,54,54,53,53,53,52,52,52,
51,51,51,50,50,50,49,49,49,48,48,48,48,47,47,47,
47,46,46,46,46,45,45,45,45,44,44,44,44,43,43,43,
43,42,42,42,42,42,41,41,41,41,41,40,40,40,40,40,
39,39,39,39,39,38,38,38,38,38,38,37,37,37,37,37,
37,36,36,36,36,36,36,35,35,35,35,35,35,35,34,34,
34,34,34,34,34,33,33,33,33,33,33,33,33,32,32,32,
};
__prg_rom const u8 w3dfc_row_lo[96]={
0,1,2,3,4,5,6,7,128,129,130,131,132,133,134,135,
0,1,2,3,4,5,6,7,128,129,130,131,132,133,134,135,
0,1,2,3,4,5,6,7,128,129,130,131,132,133,134,135,
0,1,2,3,4,5,6,7,128,129,130,131,132,133,134,135,
0,1,2,3,4,5,6,7,128,129,130,131,132,133,134,135,
0,1,2,3,4,5,6,7,128,129,130,131,132,133,134,135,
};
__prg_rom const u8 w3dfc_row_hi[96]={
104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,
105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,
106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,
107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,
108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,
109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
};
__prg_rom const u8 w3dfc_tile_row[96]={
0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,
32,32,32,32,32,32,32,32,48,48,48,48,48,48,48,48,
64,64,64,64,64,64,64,64,80,80,80,80,80,80,80,80,
96,96,96,96,96,96,96,96,112,112,112,112,112,112,112,112,
128,128,128,128,128,128,128,128,144,144,144,144,144,144,144,144,
160,160,160,160,160,160,160,160,176,176,176,176,176,176,176,176,
};
#endifkitaqfc/lib/wire3d_tables.h
zapper.h — Interface d'entrée du pistolet optique
#ifndef ZAPPER_H
#define ZAPPER_H
#include "intrinsics.h"
// Return raw 4016 & 18, retaining trigger and active-low light bits.
u8 __zapper_raw1(void);
// Return raw 4017 & 18 for the second port.
u8 __zapper_raw2(void);
// Return port-1 trigger bit 4 normalized to 0 or 1.
u8 __zapper_trigger1(void);
// Return port-2 trigger bit 4 normalized to 0 or 1.
u8 __zapper_trigger2(void);
// Invert port-1 bit 3 and normalize: one means light detected.
u8 __zapper_light1(void);
// Invert port-2 bit 3 and normalize: one means light detected.
u8 __zapper_light2(void);
// Default to the port-2 normalized trigger reader.
u8 __zapper_trigger(void);
// Default to the port-2 normalized light reader.
u8 __zapper_light(void);
#endifkitaqfc/lib/zapper.h
zx0.h —
#pragma once
#include "core.h"
// 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 into caller-owned RAM, then transfer to CHR RAM or nametable memory.
// Rendering must be off. Preserve PPUCTRL; set scroll before enabling rendering.
// The workspace must hold the whole output. No palette upload or CHR ROM writes.
u16 zx0_decompress_vram(u16 ppu_addr,void* workspace,u16 capacity,const void* src,u16 packed_size);kitaqfc/lib/zx0.h






