KITAQ ENTWICKLUNGSSYSTEM
BENUTZERHANDBUCH 2026.09

KITAQ SERIES • REFERENZAUSGABE

KITAQFC-BIBLIOTHEK

NES-Bibliotheken und -Geräte

Von der ersten Codezeile zur Ausführung, Beobachtung und erneuten Prüfung.
Quellenstand: 14. September 2026 · Englische Referenzausgabe: 14. September 2026

Bibliotheken mit dem nativen Compiler verwenden

lib/ enthält C-Header und C-Quellen, die in das Konsolen-ROM übersetzt werden. PC-Compiler und Hilfswerkzeuge sind in Rust geschrieben; Spielquellen, Zielbibliotheken und ihre APIs bleiben C. Die mitgelieferten SOURCE_MANIFEST.json und LIBRARY_MERGE.json dokumentieren die Auswahl der Bibliotheksquellen.

kitaqfc · Nativer Rust-Compiler und Hilfswerkzeuge · GitHub Actions

Native Builds und Ausführungsprüfungen waren unter Windows, Linux, macOS ARM und macOS Intel erfolgreich. KITAQGB bestand pro Umgebung 48 Tests und 395 Werkzeugprüfungen, KITAQFC 55 und 401. Rust 1.85 wurde ebenfalls getestet. PUBLIC_DISTRIBUTION.json enthält die Hashwerte der installierten Programme und die Herkunft der Prüfergebnisse. Die öffentlichen GitHub-Actions-Workflows bauen und testen diese Quellen unabhängig.

Gespeicherte Referenzausgaben prüfen ROM-Bytes, Diagnosen und Werkzeugformate. Frühere C#-Emulatorprüfungen bleiben historische Nachweise mit ihren ursprünglichen Quellfingerabdrücken. Sie belegen nicht automatisch sämtliche Rust-APIs, echte Hardware oder einen vollständigen Spielstart über das FDS-BIOS. Das nicht verfügbare ursprüngliche PNG-Skript wurde nach seiner Spezifikation neu implementiert; Bytegleichheit mit ihm kann nicht bestätigt werden.

KITAQGB · SHA-256 · KITAQFC · SHA-256

Aktuelle Compiler- und Bibliotheksausgabe — 4. Oktober 2026

fc.h enthält die Deklarationen von physics3d und audio_vblank. Binden Sie die benötigten Implementierungsdateien gesondert ein. entity_update_all und entity_draw_all rufen den Callback für aktive Plätze nach aufsteigender ID auf. Legen Sie den Callback in die gemeinsame Bank 0 oder halten Sie seine PRG-Bank während der Aufrufe eingeblendet. Für ZX0 muss zx0.h ausdrücklich eingebunden werden. Die Reihenfolge der audio_vblank-Datensätze lautet delay, CH1, CH2, CH3, CH4.

Der aktuelle C#-Build wurde mit der vorherigen Ausgabe anhand von 29 Eingaben verglichen. Fünfzehn akzeptierte Eingaben erzeugten identische ROM-Bytes; die übrigen vierzehn Eingaben erzeugten identische Ablehnungsdiagnosen. Zwei weitere ROMs liefen je vier Frames in KUROSAKI: Entitätsvergabe, Callbacks und Wiederverwendung von Plätzen; vorzeichenbehaftete Berechnungen, KQBody3D-Layout und Audiowarteschlangenkonstanten. Der Bericht enthält 18 erwartete und beobachtete RAM-Bytes. Audiowiedergabe und sämtliche APIs werden damit nicht geprüft; frühere Regressionen sind in BINARY_BUILD.json gesondert gekennzeichnet.

Quellbeispiele und Ausführungsnachweise

1. Benötigte Bausteine auswählen

fc.h sammelt Deklarationen, core.h definiert Typen und intrinsics.h die Compiler-Operationen. Gewöhnliche C-Bibliotheksfunktionen benötigen die zugehörige .c-Implementierung. Reine Header-Makros und Intrinsics brauchen nicht unbedingt eine gleichnamige Quelldatei.

powershell
.\kitaqfc\kitaqfc.exe .\kitaqfc\lib\audio.c .\kitaq-docs\samples\fc_sound.c -I .\kitaqfc\lib -I .\kitaq-docs\samples --nes-chr=.\kitaq-docs\samples\font.chr --mapper=nrom -o .\out\sound.nes

Richten Sie -I nicht auf die ähnlich benannte GB-Bibliothek. Beispielsweise hat NES __oam_dma() kein Argument, während die GB-Operation einen Zeiger erhält.

2. Laufzeit und System

runtime.c bietet C-Hilfen für PPU-Register, OAM-Schattenpuffer und VRAM-Warteschlangen. Daneben gibt es Intrinsics wie __vramq_*. Prüfen Sie, welche Daten der NMI-Handler verarbeitet, statt getrennte Warteschlangen mit ähnlichen Namen zu vermischen.

system_init initialisiert den Frame-Zustand und aktiviert NMI. system_wait_vblank wartet auf NMI, erhöht den Software-Framezähler und ruft anschließend den registrierten Callback einmal synchron auf. Übergeben Sie null an system_set_vblank_callback, um ihn zu deaktivieren. Der Callback läuft im Kontext des Aufrufers der Wartefunktion, nicht im NMI-Handler.

3. PPU, Kacheln, Attribute und Paletten

ppu_direct.h bietet direkte PPU-Operationen, vram_queue.h Aktualisierungen über NMI. tilemap / nametable_asset bearbeiten Tabellen und Ressourcen, attribute die Attribute und palette die Paletten. Trennen Sie das anfängliche Laden von der Arbeit pro Frame.

Hintergrund- und Sprite-Paletten belegen jeweils eine Gruppe von 16 Bytes. Die Werte sind NES-Farbcodes, keine RGB-Komponenten. Attribute wählen Farben für Kachelgruppen. Eine scheinbar einzelne Palettenänderung kann daher benachbarte Kacheln beeinflussen.

ppu.h und ppu.c bieten Bildschirmsteuerung, die Übertragung einer 32-Byte-Palette und die vollständige Initialisierung einer Namenstabelle. nes_ppu_seek_bytes(hi,lo) setzt das Adress-Latch zurück und stellt eine Adresse aus zwei Bytes ein. Die Funktion lässt sich zusammen mit nes_ppu_seek(address) aus runtime.c linken, das die Adresse als einzelnes Wort entgegennimmt. Deaktivieren Sie die Bildausgabe vor Übertragungen und Initialisierung.

4. OAM, Metasprites und abwechselnde Darstellung

Das NES unterstützt bis zu 64 Sprites, gewöhnlich acht pro Scanline. Neun oder mehr Gegner oder Geschosse auf einer Zeile können nicht alle gleichzeitig erscheinen. Metasprites kombinieren mehrere OBJs zu einem Bild. Prüfen Sie dafür Reservierungsgrenzen und Abschlussmarkierungen.

oam_fair.h und oam_fair_impl.h wechseln die Reihenfolge der Kandidaten unter Wahrung ihrer Prioritäten. So können Spieler oder HUD bevorzugt und weniger wichtige Objekte abwechselnd angezeigt werden. Eine andere OAM-Reihenfolge ändert die Hardwaregrenze pro Scanline nicht.

5. Eingaben, Wiederholung und Zubehör

input.c übersetzt rohe NES-Tastenwerte in BTN_*-Masken im GB-Stil. Der rohe NES-Wert für A ist 0x01, BTN_A der Bibliothek ist 0x10. Übergeben Sie BTN_A daher nicht direkt an KUROSAKIs --pad1.

pad liest grundlegende Eingaben, input_repeat sorgt für Wiederholung bei gehaltenen Tasten. zapper, keyboard, rob, mic und midi bieten hardwarenahe Geräteschnittstellen. Ein Nullwert von einem nicht angeschlossenen Gerät belegt keinen erfolgreichen Betrieb. Prüfen Sie die jeweiligen Anschlussbedingungen.

keyboard.h — Tastaturmatrix-Eingabe

Bietet eine Erkennung anhand von Anwesenheitsmustern, eine vollständige 18-Byte-Abfrage und das Lesen einer Zeile/Gruppe. Zeichenumwandlung und Tastenwiederholung werden nicht implementiert.

__fkb_detect · __fkb_scan · __fkb_read_row_col

zapper.h — Eingangssignale der Lichtpistole

Liest rohe Bits sowie Abzugs- und Lichtsignale an jedem Port. Funktionen ohne Suffix wählen Port 2. Zielkoordinaten und Trefferprüfung sind Aufgabe des Spielcodes.

__zapper_raw1 · __zapper_raw2 · __zapper_trigger1 · __zapper_trigger2 · __zapper_light1 · __zapper_light2 · __zapper_trigger · __zapper_light

intrinsics.h — Bitweise serielle Ein-/Ausgabe

Bietet OUT0-Ausgabe und D4-Eingabe für einen externen Adapter. Jede Operation verarbeitet ein Bit; der Aufrufer steuert Timing und Byte-Rahmung.

__serial_tx_bit · __serial_rx_bit

Diese Bilder stammen aus unverändert in KUROSAKI ausgeführten herunterladbaren ROMs. Sein Eingabebus bildet Gamepads nach, aber keine Tastatur-, Lichtpistolen- oder seriellen Adaptersignale. Externe Eingabebits werden als null gelesen; die Aufnahmen prüfen diese Geräte daher nicht. Physische Tasteneingaben, optische Erfassung und Kommunikation bleiben ungeprüft.

6. Ton

Verwenden Sie audio_vblank.h für NMI-gesteuerte Vierkanalmusik. Die Referenz erklärt das Nachfüllen der RAM-Warteschlange, gehaltene und gestoppte Noten sowie die Schleifenwiedergabe und enthält Audioaufnahmen des vollständigen Beispiels.

Nach nes_apu_init verwenden Sie nes_sfx_square1, nes_sfx_square2, nes_sfx_triangle oder nes_sfx_noise für die eingebaute Soundhardware. Ein Periodenargument bezeichnet die Hardware-Timerperiode, keine Frequenz in Hertz. fc_sound.c ist ein minimales Beispiel für einen Pulston.

DMC-Samples unterliegen Anforderungen an Adresse, Länge, Ausrichtung und Rate. Prüfen Sie die Map, bevor Sie einen Zeiger übergeben. DMC-DMA kann außerdem Controller-Lesezugriffe stören. Kombinieren Sie sichere Leseverfahren mit KUROSAKI-Diagnosen.

VRC6 bietet zusätzliche Puls- und Sägezahnkanäle, VRC7 FM-Register und FDS Wavetable-Sound. Wählen Sie einen passenden Mapper und zeichnen Sie das Ergebnis auf. Diese APIs sind vom GB-Treiber Audio_* getrennt.

7. Szenen, Akteure und Entities

actor und entity speichern Spielobjekte in Arrays fester Größe; scene verwaltet den Szenenzustand. Prüfen Sie auf erschöpfte Kapazität und verwenden Sie gelöschte IDs nicht weiter. Szenenwechsel, Aktualisierung und Zeichnen rufen ihre registrierten Callbacks synchron auf. Beachten Sie die Aufrufreihenfolge und die Einschränkungen zur Reentranz der jeweiligen API.

chain bietet mit ChainBody die Nachführung gegliederter Körper und mit Chain einen Positionsverlauf. collision prüft Kontakte zwischen Formen wie Rechtecken. Die feste Reihenfolge Bewegen, Kollisionsprüfung, Zeichnen verhindert, dass Kollisionsentscheidungen um einen Frame verzögert werden.

8. Mathematik und Physik

fixed.h bietet Q8.8-Arithmetik, math_fast und math_fixed numerische Operationen und math_lut tabellenbasierte Berechnungen. physics2d verarbeitet die Bewegungsintegration von Boxen, Schwerkraft, AABB-Kontakte und Oberflächenreaktionen. physics3d verarbeitet nicht rotierende 3D-Boxen, Rückprall und Aufprallwerte. Reservieren Sie einen Weltzustand und ein Array von Körpern, initialisieren Sie diese, setzen Sie die Parameter und rufen Sie die Simulationsschrittfunktion auf. Positionen und Geschwindigkeiten verwenden einheitliche, vom Aufrufer gewählte ganzzahlige Einheiten.

Q5.3-Bruchteile stellen Achtelpixel dar. Halten Sie ganzzahlige Koordinaten, Bruchteile, Geschwindigkeit und Richtung getrennt und bearbeiten Sie Addition und Übertrag im Spielcode. fc_subpixel.c addiert achtmal 2/8 Pixel und bewegt sich von Pixel 40 zu Pixel 42. Übernehmen Sie die Q8.8-Darstellung 256 nicht unverändert als Q5.3.

8.1 Drahtgitter mit wählbarem Darstellungsbereich

wire3d.c zeichnet unabhängig erstellte 3D-Modelle als cyanfarbene Linien auf dunklem Hintergrund. Zum Einsatz kommen ganzzahlige Rotationen, perspektivische Projektion mit einer Kehrwerttabelle, ein Pixelpuffer auf CPU-Seite und zwei Mustertabellen im CHR-RAM. Code, Modelle und Grafikdaten kommerzieller Spiele sind nicht enthalten. DAISUKE OBA stellt den Quellcode unter der MIT-Lizenz bereit.

Wählen Sie vor dem Einbinden von wire3d.c einen Darstellungsbereich von 64×48, 96×64 oder 128×96 Pixeln. Definieren Sie beide Makros, WIRE3D_FC_WIDTH und WIRE3D_FC_HEIGHT; die Standardgröße ist 64×48. Der Bereich liegt mittig auf dem 256×240 Pixel großen Hintergrund. Ein größerer Bereich benötigt mehr Kacheln und längere Linien. Wählen Sie die Größe daher anhand von Messungen Ihrer Szene.

c
#define WIRE3D_FC_WIDTH 96
#define WIRE3D_FC_HEIGHT 64
#include "wire3d.c"

void main(void) {
    Wire3DFC_Init();
    Wire3DFC_BeginFrame();
    Wire3DFC_DrawLine2D(4,4,91,59);
    Wire3DFC_DrawLine2D(91,4,4,59);
    Wire3DFC_EndFrame();
    while(1) {}
}

Dieses Beispiel zeichnet zwei sich kreuzende Diagonalen, um den gewählten Darstellungsbereich und die von den Linien belegten Pixel zu prüfen. Kompilieren Sie diese Datei nur einmal; sie bindet die Implementierung bereits ein.

powershell
.\kitaqfc\kitaqfc.exe .\cross.c -I .\kitaqfc\lib --mapper=nrom --nes-chr-ram -o .\cross.nes

Das ROM benötigt 8 KiB beschreibbares CHR-RAM sowie PRG-RAM auf dem Modul, das den Bereich $6800–$70BF abdeckt. Der Renderer beansprucht beide Mustertabellen, Namenstabelle null, Scroll-Einstellungen und Hintergrundpalette sowie die Zero-Page-Adressen $00–$0A. Verwenden Sie diese Bereiche nicht anderweitig und ändern Sie während des Zeichnens ihre Mapper-Zuordnung nicht. --nes-chr-ram wählt RAM anstelle von CHR-ROM. Diese Option lässt sich nicht mit einer über --nes-chr oder --chr-rom angegebenen Grafikdatei kombinieren und wird beim CNROM-Profil nicht akzeptiert.

Der Renderer ist nicht reentrant. Die Initialisierung deaktiviert NMI und schaltet nach der Einrichtung den Hintergrund ein. Zeichnen und Übertragen laufen im aufrufenden Ablauf. Führen Sie dabei keine weiteren PPU-Schreibzugriffe und keine Interrupt-Handler aus, die seinen Arbeitsspeicher verändern. Eine Übertragung kann mehrere Bildschirmframes beanspruchen. Diese Implementierung enthält weder eine asynchrone Spielschleife noch einen Scheduler für Audioaktualisierungen.

FunktionAufgabe und Aufrufbedingungen
Wire3DFC_Init()Löscht beide CHR-Tabellen und die CPU-Zeichenpuffer, erstellt die zentrierte Kachelkarte, wählt Cyan auf dunklem Hintergrund und aktiviert den Hintergrund bei deaktiviertem NMI. Vor jeder anderen Frame-Operation aufrufen.
Wire3DFC_BeginFrame()Löscht die beim vorherigen Zeichnen verwendeten CPU-Kacheln. Das angezeigte Bild bleibt unverändert, bis EndFrame die Puffer tauscht. Vor dem Aufbau jedes vollständigen Bildes einmal aufrufen.
Wire3DFC_DrawLine2D(ax,ay,bx,by)Zeichnet eine Strecke einschließlich beider Endpunkte in den CPU-Puffer. Die Endpunktkoordinaten sind vorzeichenbehaftet und liegen im Bereich −512…511. Pixel außerhalb des Darstellungsbereichs werden abgeschnitten; Strecken mit vollständig außerhalb liegendem Begrenzungsrechteck werden verworfen. Linien innerhalb des Bereichs verwenden eine registerbasierte Bresenham-Schleife für den 6502.
Wire3DFC_RotatePoint(x,y,z,rx,ry,rz)Aktualisiert drei getrennte, beschreibbare s16-Komponenten durch Rotation um Y, X und Z in dieser Reihenfolge. Winkel laufen zyklisch über 32 Schritte pro Umdrehung. Jede Komponente muss anfangs im Bereich −63…63 liegen. Q6-Reduktionen schneiden Nachkommastellen in Richtung null ab. Ist einer der Komponentenpointer NULL, bewirkt der Aufruf nichts.
Wire3DFC_ProjectPoint(x,y,z,sx,sy)Wandelt einen Punkt im Kameraraum in Bildschirmkoordinaten um. X/Y müssen im Bereich −127…127 und die Tiefe im Bereich 32…255 liegen. Bei Erfolg wird 1 zurückgegeben und es werden vorzeichenbehaftete, noch nicht beschnittene Koordinaten geschrieben. Bei ungültigen Koordinaten oder einem NULL-Ausgabepointer wird 0 zurückgegeben, ohne die Ausgaben zu ändern. Positives X zeigt nach rechts, positives Y nach oben.
Wire3DFC_DrawLine3D(ax,ay,az,bx,by,bz)Projiziert beide Endpunkte und zeichnet die Strecke auf dem Bildschirm. Liegt auch nur ein Endpunkt außerhalb des Projektionsbereichs, entfällt die gesamte Kante. Schnittpunkte mit der nahen oder fernen Begrenzungsebene werden nicht berechnet.
Wire3DFC_DrawModel(vertices,count,edges,edge_count,x,y,z,rx,ry,rz)Transformiert und projiziert bis zu 24 der ersten Eckpunkte jeweils einmal, speichert die Ergebnisse zwischen und zeichnet anschließend die indizierten Kanten. Ein Eckpunkt besteht aus drei s8-Komponenten, eine Kante aus zwei u8-Indizes. NULL-Arrays, ungültige Indizes und verworfene Endpunkte werden übersprungen. Die Summen nach der Verschiebung müssen im Wertebereich von s16 bleiben. Alle gültigen Kanten werden gezeichnet; diese API entfernt keine verdeckten Flächen.
Wire3DFC_EndFrame()Überträgt die vom vorbereiteten Bild oder vom bisherigen Inhalt des unsichtbaren CHR-Puffers verwendeten Kacheln, einschließlich der zu löschenden Kacheln. Pro VBlank werden höchstens 16 Kacheln übertragen. Anschließend werden die Scroll-Einstellungen wiederhergestellt und das fertige Bild in einem neuen VBlank angezeigt. Der Aufruf wartet bis zum Abschluss.

Nach EndFrame enthält wire3d_uploaded_tiles die Zahl der übertragenen Kacheln. wire3d_transfer_frames enthält die Zahl der Übertragungsblöcke zuzüglich der abschließenden Wartezeit auf den Puffertausch. Dieser Wert ist nicht die gesamte Renderdauer: Transformationen, Rasterung und Zustandsverwaltung auf CPU-Seite benötigen ebenfalls Zeit. Die Perspektive verwendet eine quantisierte Kehrwerttabelle; bei 128 Pixeln Breite wird der Faktor für die geringste Tiefe von 256 auf 255 begrenzt.

Das Würfelbeispiel im HTML-Handbuch zeigt gemeinsam verwendete Eckpunkte, Rotation, Projektion, zwölf indizierte Kanten und die Ausgabe eines vollständigen Bildes. Die Prüfbilder zeigen einen um die Y-Achse gedrehten Würfel. Alle zwölf Kanten müssen verbunden bleiben; Linien des vorherigen Bildes dürfen nicht zurückbleiben.

Beispiel eines rotierenden Würfels

powershell
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\wire3d_cube.c -I .\kitaqfc\lib --mapper=nrom --nes-chr-ram -o .\wire_cube.nes
64×48: ein um 3/32 Umdrehung um Y gedrehter Würfel. Alle zwölf Kanten sollen verbunden sein; im Hintergrund dürfen keine alten Linien bleiben.
64×48: ein um 3/32 Umdrehung um Y gedrehter Würfel. Alle zwölf Kanten sollen verbunden sein; im Hintergrund dürfen keine alten Linien bleiben.
96×64: ein um 3/32 Umdrehung um Y gedrehter Würfel. Alle zwölf Kanten sollen verbunden sein; im Hintergrund dürfen keine alten Linien bleiben.
96×64: ein um 3/32 Umdrehung um Y gedrehter Würfel. Alle zwölf Kanten sollen verbunden sein; im Hintergrund dürfen keine alten Linien bleiben.
128×96: ein um 3/32 Umdrehung um Y gedrehter Würfel. Alle zwölf Kanten sollen verbunden sein; im Hintergrund dürfen keine alten Linien bleiben.
128×96: ein um 3/32 Umdrehung um Y gedrehter Würfel. Alle zwölf Kanten sollen verbunden sein; im Hintergrund dürfen keine alten Linien bleiben.

KUROSAKI hat Linien, Würfel und Löschen für jede Größe geprüft, insgesamt neun Bildprüfungen. Weitere Prüfungen decken Projektionsgrenzen, NULL-Pointer, alle 32 Rotationsschritte jeder Achse, kombinierte Rotationen und verworfene Kanten ab, jeweils für drei Darstellungsgrößen und vier Compilerkonfigurationen. Die Zeichenbeispiele verwenden NROM; das größere ROM für Grenzwerttests verwendet MMC3. Dies sind Emulatorprüfungen, keine Messungen an echter Hardware.

zx0

Decodiert ZX0-kompatible Assets in RAM oder VRAM. Bereiten Sie Assets am PC mit kitaqfc-zx0.exe vor und decodieren Sie zur Laufzeit nur benötigte Daten. --format=auto vergleicht unkomprimierte, RLE- und ZX0-Nutzdaten und wählt die kleinsten; bei Gleichstand gilt die Reihenfolge unkomprimiert, RLE, ZX0. Der gesamte Container einschließlich Neun-Byte-Header darf 65535 Bytes nicht überschreiten. Teilen Sie Assets passend zu tatsächlichen CPU-Bänken und RAM auf.

Einar Saukas entwickelte das ZX0-Format und den ursprünglichen Kompressionsalgorithmus. Der hier bereitgestellte Kompressor und Dekompressor sind unabhängige KITAQ-Implementierungen, Copyright DAISUKE OBA, veröffentlicht unter der MIT-Lizenz.

Führen Sie diese Hostbefehle im Stammverzeichnis des Repositorys aus. Bauen Sie das Werkzeug mit tools/zx0/build.ps1.

.\kitaqfc-zx0.exe tiles.bin tiles.zx0
.\kitaqfc-zx0.exe tiles.bin tiles.h --header=tiles
.\kitaqfc-zx0.exe map.bin map.kqa --format=auto
.\kitaqfc-zx0.exe tiles.zx0 restored.bin --decompress
zx0_decompress

Decodiert einen ZX0-v2-Strom in einen begrenzten RAM-Bereich. Übereinstimmungen verweisen auf zuvor decodierte Bytes; das Ziel muss daher les- und beschreibbar sein. Geeignet für Tilemaps oder Leveltabellen, die die CPU vor ihrer Verwendung verarbeitet.

Syntax

c
u16 zx0_decompress(void* dst, u16 capacity, const void* src, u16 packed_size);

Parameter

dst

Beginn des beschreibbaren Ziel-RAM; darf nicht null sein. Geben Sie die Kapazität in Bytes an, nicht in Arrayelementen.

capacity

Anzahl beschreibbarer Zielbytes. Ein gewöhnlicher ZX0-Strom benötigt mindestens ein Byte. Ein leeres unkomprimiertes KQA1-Asset kann mit Kapazität null erfolgreich sein.

src

Beginn der über die aktuelle Bankeinblendung lesbaren komprimierten Daten. Darf nicht null sein.

packed_size

Byteanzahl der vollständigen Eingabe. Ein ZX0-Strom enthält seine Endmarkierung und keine nachfolgenden Bytes. Ein KQA1-Container enthält seinen Neun-Byte-Header. Maximum: 65535 Bytes.

Rückgabewert

Liefert bei Erfolg die Anzahl decodierter Bytes, bei Fehler null. Prüfen Sie stets auch zx0_error.

Bedingungen und Grenzen

Binden Sie zx0.h ein und kompilieren Sie lib/zx0.c. Diese Routinen teilen sich Arbeitsspeicher und sind aus Interrupts nicht reentrant. Ein- und Ausgabe dürfen weder überlappen noch im CPU-Adressraum umbrechen oder aktuell eingeblendete Bankfenster überschreiten. Die Bibliothek schaltet keine Asset-Bänke um.

Jeder Aufruf aktualisiert zx0_error: 0 Erfolg, 1 ungültiges Argument, 2 abgeschnittene Eingabe, 3 fehlerhafter Datenstrom, 4 zu wenig Ausgabespeicher, 5 aktive Anzeige. Ein Fehler kann Teilausgabe hinterlassen; verwenden Sie diese nicht. Bei mehreren ungültigen Bedingungen bestimmt die zuerst erkannte den Code.

Akzeptiert vorwärtsgerichtete ZX0-v2-Ströme. ZX0 v1, Rückwärtsströme und externe Wörterbücher gehören nicht zu dieser Schnittstelle. Kennen Sie die decodierte Größe des am Host erzeugten Assets und stellen Sie ausreichend Speicher bereit.

ZX0-Format — Einar Saukas

Anwendungsbeispiel

c
count=zx0_decompress(decoded_map,16,packed_map,packed_map_SIZE);
    if(count!=16||zx0_error!=ZX0_OK)failures++;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Die Zeile RAM MAP wiederholt Quadrat-, Rauten- und Schachbrett-Tiles. AUTO RLE MAP bildet aus sechzehn Quadraten einen waagerechten Balken. VRAM TILES wiederholt dieselben drei Tiles nach Decodierung ihrer Pixel ins VRAM. Auf CGB und FC ist das Quadrat weiß, die Raute rot und das Schachbrett blau; DMG verwendet Graustufen. CHECKS OK bestätigt die erwarteten decodierten Größen ohne Fehler bei allen drei Aufrufen.

zx0_decompress: NTSC — Die Zeile RAM MAP wiederholt Quadrat-, Rauten- und Schachbrett-Tiles. AUTO RLE MAP bildet aus sechzehn Quadraten einen waagerechten Balken. VRAM TILES wiederholt dieselben drei Tiles nach Decodierung ihrer Pixel ins VRAM. Auf CGB und FC ist das Quadrat weiß, die Raute rot und das Schachbrett blau; DMG verwendet Graustufen. CHECKS OK bestätigt die erwarteten decodierten Größen ohne Fehler bei allen drei Aufrufen.
NTSC — Die Zeile RAM MAP wiederholt Quadrat-, Rauten- und Schachbrett-Tiles. AUTO RLE MAP bildet aus sechzehn Quadraten einen waagerechten Balken. VRAM TILES wiederholt dieselben drei Tiles nach Decodierung ihrer Pixel ins VRAM. Auf CGB und FC ist das Quadrat weiß, die Raute rot und das Schachbrett blau; DMG verwendet Graustufen. CHECKS OK bestätigt die erwarteten decodierten Größen ohne Fehler bei allen drei Aufrufen.

Vollständiges Beispielprogramm

Build-Befehl

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\zx0_decode.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\zx0_decode.nes --mapper=nrom --nes-chr-ram --no-cache --no-disasm
Implementierung und Quelltext

kitaqfc/lib/zx0.h:16

Deklarationshinweise im Original
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.

kitaqfc/lib/zx0.c:52

c
u16 zx0_decompress(void* dst,u16 capacity,const void* src,u16 packed_size) {
    u8 phase; u8 low; u8* out; u8* match;
    u16 count; u16 distance; u16 used; u16 upper;
    zx0_error=ZX0_OK;
    if(!kq_zx_arguments(dst,capacity,src,packed_size)) { zx0_error=ZX0_BAD_ARGUMENT; return 0; }
    kq_zx_input=(const u8*)src; kq_zx_left=packed_size;
    kq_zx_mask=0; kq_zx_borrowed=0;
    out=(u8*)dst; used=0; distance=1; phase=0;
    // Phase 0 is literal, 1 reuses the last distance, 2 carries a new distance.
    while(1) {
        if(phase==2) {
            upper=kq_zx_number(1);
            if(zx0_error) return 0;
            if(upper==256) {
                if(kq_zx_left!=0) { zx0_error=ZX0_BAD_STREAM; return 0; }
                return used;
            }
            if(upper>255) { zx0_error=ZX0_BAD_STREAM; return 0; }
            low=kq_zx_byte();
            distance=(u16)((upper<<7)-(low>>1));
            kq_zx_borrowed=1; kq_zx_borrow_value=(u8)(low&1);
            count=kq_zx_number(0);
            if(count==65535) { zx0_error=ZX0_BAD_STREAM; return 0; }
            count++;
        } else count=kq_zx_number(0);
        if(zx0_error) return 0;
        if(count>capacity-used) { zx0_error=ZX0_OUTPUT_FULL; return 0; }
        if(phase==0) {
            if(count>kq_zx_left) { zx0_error=ZX0_TRUNCATED; return 0; }
            kq_zx_left-=count; used+=count;
            while(count!=0) { *out++=*kq_zx_input++; count--; }
            phase=kq_zx_bit()?2:1;
        } else {
            if(distance>used) { zx0_error=ZX0_BAD_STREAM; return 0; }
            match=out-distance; used+=count;
            // Forward byte copying deliberately supports overlapping matches.
            while(count!=0) { *out++=*match++; count--; }
            phase=kq_zx_bit()?2:0;
        }
        if(zx0_error) return 0;
    }
}
asset_decompress

Liest Codec und Größen aus einem mit --format=auto erzeugten KQA1-Header und kopiert dann rohe Bytes oder decodiert RLE/ZX0 ins RAM. Der Aufrufer benötigt keine separate Verzweigung je Codec.

Syntax

c
u16 asset_decompress(void* dst, u16 capacity, const void* src, u16 packed_size);

Parameter

dst

Beginn des beschreibbaren Ziel-RAM; darf nicht null sein. Geben Sie die Kapazität in Bytes an, nicht in Arrayelementen.

capacity

Anzahl beschreibbarer Zielbytes. Ein gewöhnlicher ZX0-Strom benötigt mindestens ein Byte. Ein leeres unkomprimiertes KQA1-Asset kann mit Kapazität null erfolgreich sein.

src

Beginn der über die aktuelle Bankeinblendung lesbaren komprimierten Daten. Darf nicht null sein.

packed_size

Byteanzahl der vollständigen Eingabe. Ein ZX0-Strom enthält seine Endmarkierung und keine nachfolgenden Bytes. Ein KQA1-Container enthält seinen Neun-Byte-Header. Maximum: 65535 Bytes.

Rückgabewert

Liefert bei Erfolg die Anzahl decodierter Bytes, bei Fehler null. Prüfen Sie stets auch zx0_error.

Bedingungen und Grenzen

Binden Sie zx0.h ein und kompilieren Sie lib/zx0.c. Diese Routinen teilen sich Arbeitsspeicher und sind aus Interrupts nicht reentrant. Ein- und Ausgabe dürfen weder überlappen noch im CPU-Adressraum umbrechen oder aktuell eingeblendete Bankfenster überschreiten. Die Bibliothek schaltet keine Asset-Bänke um.

Jeder Aufruf aktualisiert zx0_error: 0 Erfolg, 1 ungültiges Argument, 2 abgeschnittene Eingabe, 3 fehlerhafter Datenstrom, 4 zu wenig Ausgabespeicher, 5 aktive Anzeige. Ein Fehler kann Teilausgabe hinterlassen; verwenden Sie diese nicht. Bei mehreren ungültigen Bedingungen bestimmt die zuerst erkannte den Code.

KQA1 ist der KITAQ-Asset-Container: Vier-Byte-Kennung, Ein-Byte-Codec (0 unkomprimiert, 1 RLE, 2 ZX0), decodierte Größe u16, Nutzdatengröße u16, danach Nutzdaten. Die u16-Felder sind Little-Endian. RLE wiederholt Anzahl/Wert-Paare mit Anzahlen 1..255 und einem Abschluss mit Anzahl null. Ein leeres unkomprimiertes Asset ist mit Rückgabewert null und Fehler null erfolgreich.

ZX0-Format — Einar Saukas

Anwendungsbeispiel

c
count=asset_decompress(decoded_auto,16,packed_auto,packed_auto_SIZE);
    if(count!=16||zx0_error!=ZX0_OK)failures++;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Die Zeile RAM MAP wiederholt Quadrat-, Rauten- und Schachbrett-Tiles. AUTO RLE MAP bildet aus sechzehn Quadraten einen waagerechten Balken. VRAM TILES wiederholt dieselben drei Tiles nach Decodierung ihrer Pixel ins VRAM. Auf CGB und FC ist das Quadrat weiß, die Raute rot und das Schachbrett blau; DMG verwendet Graustufen. CHECKS OK bestätigt die erwarteten decodierten Größen ohne Fehler bei allen drei Aufrufen.

asset_decompress: NTSC — Die Zeile RAM MAP wiederholt Quadrat-, Rauten- und Schachbrett-Tiles. AUTO RLE MAP bildet aus sechzehn Quadraten einen waagerechten Balken. VRAM TILES wiederholt dieselben drei Tiles nach Decodierung ihrer Pixel ins VRAM. Auf CGB und FC ist das Quadrat weiß, die Raute rot und das Schachbrett blau; DMG verwendet Graustufen. CHECKS OK bestätigt die erwarteten decodierten Größen ohne Fehler bei allen drei Aufrufen.
NTSC — Die Zeile RAM MAP wiederholt Quadrat-, Rauten- und Schachbrett-Tiles. AUTO RLE MAP bildet aus sechzehn Quadraten einen waagerechten Balken. VRAM TILES wiederholt dieselben drei Tiles nach Decodierung ihrer Pixel ins VRAM. Auf CGB und FC ist das Quadrat weiß, die Raute rot und das Schachbrett blau; DMG verwendet Graustufen. CHECKS OK bestätigt die erwarteten decodierten Größen ohne Fehler bei allen drei Aufrufen.

Vollständiges Beispielprogramm

Build-Befehl

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\zx0_decode.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\zx0_decode.nes --mapper=nrom --nes-chr-ram --no-cache --no-disasm
Implementierung und Quelltext

kitaqfc/lib/zx0.h:19

Deklarationshinweise im Original
Decode a KQA1 raw/RLE/ZX0 asset produced with --format=auto.
Empty raw assets return zero with zx0_error==ZX0_OK.

kitaqfc/lib/zx0.c:95

c
u16 asset_decompress(void* dst,u16 capacity,const void* src,u16 packed_size) {
    const u8* in; u8* out; u16 raw; u16 packed; u16 used;
    u8 codec; u8 count; u8 value;
    zx0_error=ZX0_OK;
    if(packed_size<9||!kq_zx_arguments(dst,capacity,src,packed_size)) { zx0_error=ZX0_BAD_ARGUMENT; return 0; }
    in=(const u8*)src; out=(u8*)dst;
    if(in[0]!=75||in[1]!=81||in[2]!=65||in[3]!=49) { zx0_error=ZX0_BAD_STREAM; return 0; }
    codec=in[4]; raw=(u16)((u16)in[5]|((u16)in[6]<<8));
    packed=(u16)((u16)in[7]|((u16)in[8]<<8));
    if(packed!=packed_size-9||codec>2) { zx0_error=ZX0_BAD_STREAM; return 0; }
    if(raw>capacity) { zx0_error=ZX0_OUTPUT_FULL; return 0; }
    in+=9;
    if(codec==2) {
        used=zx0_decompress(dst,raw,in,packed);
        if(zx0_error==0&&used!=raw) zx0_error=ZX0_BAD_STREAM;
        return zx0_error?0:used;
    }
    if(codec==0) {
        if(raw!=packed) { zx0_error=ZX0_BAD_STREAM; return 0; }
        used=raw; while(raw!=0) { *out++=*in++; raw--; } return used;
    }
    used=0;
    while(packed!=0) {
        count=*in++; packed--;
        if(count==0) {
            if(packed!=0||used!=raw) { zx0_error=ZX0_BAD_STREAM; return 0; }
            return used;
        }
        if(packed==0) { zx0_error=ZX0_TRUNCATED; return 0; }
        value=*in++; packed--;
        if((u16)count>raw-used) { zx0_error=ZX0_OUTPUT_FULL; return 0; }
        used+=count; while(count!=0) { *out++=value; count--; }
    }
    zx0_error=ZX0_TRUNCATED; return 0;
}
zx0_decompress_vram

Decodiert das gesamte ZX0-Asset in RAM des Aufrufers und überträgt es dann in Blöcken von höchstens 128 Bytes zur PPU. Der Rückverweisverlauf bleibt im RAM, da PPU-Speicher nicht direkt über gewöhnliche CPU-Zeiger lesbar ist.

Syntax

c
u16 zx0_decompress_vram(u16 ppu_addr,void* workspace,u16 capacity,const void* src,u16 packed_size);

Parameter

ppu_addr

PPU-Ziel, 0x0000..0x2FFF. Der gesamte decodierte Bereich muss vor 0x3000 enden. Ziele in Mustertabellen benötigen eine Cartridge-Konfiguration mit CHR-RAM.

workspace

Beginn des beschreibbaren Ziel-RAM; darf nicht null sein. Geben Sie die Kapazität in Bytes an, nicht in Arrayelementen.

capacity

RAM-Arbeitsbereichskapazität. Sie muss das gesamte decodierte Asset aufnehmen; die PPU-Übertragungsblockgröße von 128 Bytes verringert diesen Bedarf nicht.

src

Beginn der über die aktuelle Bankeinblendung lesbaren komprimierten Daten. Darf nicht null sein.

packed_size

Byteanzahl der vollständigen Eingabe. Ein ZX0-Strom enthält seine Endmarkierung und keine nachfolgenden Bytes. Ein KQA1-Container enthält seinen Neun-Byte-Header. Maximum: 65535 Bytes.

Rückgabewert

Liefert bei Erfolg die Anzahl decodierter Bytes, bei Fehler null. Prüfen Sie stets auch zx0_error.

Bedingungen und Grenzen

Binden Sie zx0.h ein und kompilieren Sie lib/zx0.c. Diese Routinen teilen sich Arbeitsspeicher und sind aus Interrupts nicht reentrant. Ein- und Ausgabe dürfen weder überlappen noch im CPU-Adressraum umbrechen oder aktuell eingeblendete Bankfenster überschreiten. Die Bibliothek schaltet keine Asset-Bänke um.

Jeder Aufruf aktualisiert zx0_error: 0 Erfolg, 1 ungültiges Argument, 2 abgeschnittene Eingabe, 3 fehlerhafter Datenstrom, 4 zu wenig Ausgabespeicher, 5 aktive Anzeige. Ein Fehler kann Teilausgabe hinterlassen; verwenden Sie diese nicht. Bei mehreren ungültigen Bedingungen bestimmt die zuerst erkannte den Code.

Akzeptiert vorwärtsgerichtete ZX0-v2-Ströme. ZX0 v1, Rückwärtsströme und externe Wörterbücher gehören nicht zu dieser Schnittstelle. Kennen Sie die decodierte Größe des am Host erzeugten Assets und stellen Sie ausreichend Speicher bereit.

Deaktivieren Sie vor dem Aufruf Rendering mit __ppu_mask_set(0). Die Routine wählt vorübergehend PPU-Inkrement 1 und stellt PPUCTRL danach wieder her. PPUADDR/PPUDATA-Zugriffe ändern PPU-Adresse und Latch-Zustand; setzen Sie Scrolling vor Wiederaufnahme des Renderings. Auch Interrupt-Handler müssen während des Aufrufs PPU-Zugriffe vermeiden. Nicht für CHR-ROM oder Palettenübertragungen verwenden. Der Zielbereich wird erst nach RAM-Decodierung geprüft; ein Bereichsfehler kann den Arbeitsbereich daher trotzdem verändern.

ZX0-Format — Einar Saukas

Anwendungsbeispiel

c
count=zx0_decompress_vram(0x0800,tile_workspace,48,packed_tiles,packed_tiles_SIZE);
    if(count!=48||zx0_error!=ZX0_OK)failures++;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Die Zeile RAM MAP wiederholt Quadrat-, Rauten- und Schachbrett-Tiles. AUTO RLE MAP bildet aus sechzehn Quadraten einen waagerechten Balken. VRAM TILES wiederholt dieselben drei Tiles nach Decodierung ihrer Pixel ins VRAM. Auf CGB und FC ist das Quadrat weiß, die Raute rot und das Schachbrett blau; DMG verwendet Graustufen. CHECKS OK bestätigt die erwarteten decodierten Größen ohne Fehler bei allen drei Aufrufen.

zx0_decompress_vram: NTSC — Die Zeile RAM MAP wiederholt Quadrat-, Rauten- und Schachbrett-Tiles. AUTO RLE MAP bildet aus sechzehn Quadraten einen waagerechten Balken. VRAM TILES wiederholt dieselben drei Tiles nach Decodierung ihrer Pixel ins VRAM. Auf CGB und FC ist das Quadrat weiß, die Raute rot und das Schachbrett blau; DMG verwendet Graustufen. CHECKS OK bestätigt die erwarteten decodierten Größen ohne Fehler bei allen drei Aufrufen.
NTSC — Die Zeile RAM MAP wiederholt Quadrat-, Rauten- und Schachbrett-Tiles. AUTO RLE MAP bildet aus sechzehn Quadraten einen waagerechten Balken. VRAM TILES wiederholt dieselben drei Tiles nach Decodierung ihrer Pixel ins VRAM. Auf CGB und FC ist das Quadrat weiß, die Raute rot und das Schachbrett blau; DMG verwendet Graustufen. CHECKS OK bestätigt die erwarteten decodierten Größen ohne Fehler bei allen drei Aufrufen.

Vollständiges Beispielprogramm

Build-Befehl

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\zx0_decode.c -I .\kitaqfc\lib -I .\kitaq-docs\samples -o .\out\zx0_decode.nes --mapper=nrom --nes-chr-ram --no-cache --no-disasm
Implementierung und Quelltext

kitaqfc/lib/zx0.h:23

Deklarationshinweise im Original
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.

kitaqfc/lib/zx0.c:134

c
u16 zx0_decompress_vram(u16 ppu_addr,void* workspace,u16 capacity,const void* src,u16 packed_size) {
    u16 size; u16 left; const u8* data; u8 chunk; u8 saved_ctrl;
    zx0_error=ZX0_OK;
    if(ppu_addr>=0x3000) { zx0_error=ZX0_BAD_ARGUMENT; return 0; }
    if(__ppu_mask_get()&0x18) { zx0_error=ZX0_DISPLAY_ACTIVE; return 0; }
    size=zx0_decompress(workspace,capacity,src,packed_size);
    if(zx0_error) return 0;
    if(size>0x3000-ppu_addr) { zx0_error=ZX0_OUTPUT_FULL; return 0; }
    saved_ctrl=__ppu_ctrl_get(); __ppu_ctrl_set((u8)(saved_ctrl&0xFB));
    left=size; data=(const u8*)workspace;
    while(left!=0) {
        chunk=left>128?128:(u8)left;
        __vram_write(ppu_addr,data,chunk);
        ppu_addr+=chunk; data+=chunk; left-=chunk;
    }
    __ppu_ctrl_set(saved_ctrl); return size;
}

wire3d — Referenz der einzelnen Funktionen

Wire3DFC_Init

Initialisiert CHR-RAM, Hintergrundkarte, vorbereitete Pixel und die Historie geänderter Kacheln. Anschließend wird die Hintergrunddarstellung mit cyanfarbenen Linien aktiviert. Der bisherige Bildschirminhalt wird gelöscht.

Syntax

c
void Wire3DFC_Init(void);

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Benötigt 8 KiB CHR-RAM, beschreibbares Cartridge-PRG-RAM bei $6800–$70BF und Zero-Page-Zwischenspeicher bei $00–$0A. Bauen Sie mit --nes-chr-ram. Aufgrund des gemeinsam genutzten Arbeitsspeichers ist der Renderer nicht reentrant.

Rufen Sie Init, BeginFrame, Zeichenfunktionen und EndFrame in dieser Reihenfolge auf. Die Bibliothek übernimmt beide Hintergrund-Mustertabellen, Nametable null, Hintergrundpalette und Scrollposition und deaktiviert NMI. Führen Sie keine anderen PPU-Schreibzugriffe gleichzeitig aus.

Wählen Sie 64×48 (Standard), 96×64 oder 128×96, indem Sie vor dem Einbinden von wire3d.c sowohl WIRE3D_FC_WIDTH als auch WIRE3D_FC_HEIGHT definieren. Der Ansichtsbereich liegt mittig auf dem Bildschirm. Kleinere Ansichten verringern Zeichen- und Übertragungsaufwand, reservieren aber dieselbe RAM-Kapazität.

Die Bilder wurden in KUROSAKI in allen drei Größen aufgenommen. Die Prüfungen vergleichen jedes Pixel des 256×240-Bildes einschließlich Farbe sowie die numerischen Ergebnisse im RAM. Es handelt sich nicht um Leistungsmessungen auf echter Hardware.

Anwendungsbeispiel

c
Wire3DFC_Init();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.

Wire3DFC_Init: 64X48 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
64X48 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
Wire3DFC_Init: 96X64 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
96X64 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
Wire3DFC_Init: 128X96 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
128X96 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.

Vollständiges Beispielprogramm

Build-Befehl

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\wire3d_projection.c -I .\kitaqfc\lib --mapper=nrom --nes-chr-ram -o .\out\wire3d_projection.nes --no-cache --no-disasm
.\kurosaki\kurosaki.exe run .\out\wire3d_projection.nes --headless --frames 180 --png .\out\wire3d_projection.png
Implementierung und Quelltext

kitaqfc/lib/wire3d.h:34

Deklarationshinweise im Original
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.

kitaqfc/lib/wire3d.c:40

c
void Wire3DFC_Init(void) {
    u16 address;u8 x,y,tile;
    __ppu_mask_set(0);__ppu_ctrl_set(0);
    // Both pattern tables have a zero high bitplane; all subsequent transfers
    // update only low bitplanes in the currently hidden table.
    for(address=0;address<8192;address+=128)__vram_fill(address,0,128);
    for(address=0x2000;address<0x2400;address+=128)__vram_fill(address,255,128);
    __vram_fill(0x23C0,0,64);__palette_bg_load(w3dfc_palette);
    tile=0;
    for(y=0;y<WIRE3D_FC_HEIGHT/8;y++) {
        for(x=0;x<WIRE3D_FC_WIDTH/8;x++) {
            address=(u16)(0x2000+(u16)(y+(30-WIRE3D_FC_HEIGHT/8)/2)*32+x+(32-WIRE3D_FC_WIDTH/8)/2);
            __ppu_addr(address);__ppu_data(tile);tile++;
        }
    }
    __memset(w3dfc_pixels,0,1536);
    __memset(w3dfc_dirty,0,192);
    __memset(w3dfc_bank0_dirty,0,192);
    __memset(w3dfc_bank1_dirty,0,192);
    w3dfc_front=0;w3dfc_batch_count=0;
    wire3d_transfer_frames=0;wire3d_uploaded_tiles=0;
    __scroll_set(0,0);__ppu_ctrl_set(0);__ppu_mask_set(0x0A);
}
Wire3DFC_BeginFrame

Löscht die vorbereiteten Pixel in den beim vorherigen Zeichnen berührten Kacheln und bereitet so einen leeren Frame vor. Die angezeigte CHR-Tabelle und das sichtbare Bild bleiben unverändert.

Syntax

c
void Wire3DFC_BeginFrame(void);

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Rufen Sie die Funktion zu Beginn jedes Zeichenvorgangs einmal auf. Ein erneuter Aufruf vor EndFrame löscht die bisher vorbereiteten Linien.

Benötigt 8 KiB CHR-RAM, beschreibbares Cartridge-PRG-RAM bei $6800–$70BF und Zero-Page-Zwischenspeicher bei $00–$0A. Bauen Sie mit --nes-chr-ram. Aufgrund des gemeinsam genutzten Arbeitsspeichers ist der Renderer nicht reentrant.

Rufen Sie Init, BeginFrame, Zeichenfunktionen und EndFrame in dieser Reihenfolge auf. Die Bibliothek übernimmt beide Hintergrund-Mustertabellen, Nametable null, Hintergrundpalette und Scrollposition und deaktiviert NMI. Führen Sie keine anderen PPU-Schreibzugriffe gleichzeitig aus.

Wählen Sie 64×48 (Standard), 96×64 oder 128×96, indem Sie vor dem Einbinden von wire3d.c sowohl WIRE3D_FC_WIDTH als auch WIRE3D_FC_HEIGHT definieren. Der Ansichtsbereich liegt mittig auf dem Bildschirm. Kleinere Ansichten verringern Zeichen- und Übertragungsaufwand, reservieren aber dieselbe RAM-Kapazität.

Die Bilder wurden in KUROSAKI in allen drei Größen aufgenommen. Die Prüfungen vergleichen jedes Pixel des 256×240-Bildes einschließlich Farbe sowie die numerischen Ergebnisse im RAM. Es handelt sich nicht um Leistungsmessungen auf echter Hardware.

Anwendungsbeispiel

c
Wire3DFC_BeginFrame();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.

Wire3DFC_BeginFrame: 64X48 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
64X48 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
Wire3DFC_BeginFrame: 96X64 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
96X64 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
Wire3DFC_BeginFrame: 128X96 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
128X96 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.

Vollständiges Beispielprogramm

Build-Befehl

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\wire3d_projection.c -I .\kitaqfc\lib --mapper=nrom --nes-chr-ram -o .\out\wire3d_projection.nes --no-cache --no-disasm
.\kurosaki\kurosaki.exe run .\out\wire3d_projection.nes --headless --frames 180 --png .\out\wire3d_projection.png
Implementierung und Quelltext

kitaqfc/lib/wire3d.h:36

Deklarationshinweise im Original
Clear the previous staged drawing. The displayed front image remains intact.

kitaqfc/lib/wire3d.c:63

c
void Wire3DFC_BeginFrame(void) {
    w3dfc_tile_count=WIRE3D_FC_TILES;
    // Clear exactly eight bytes per previously touched tile, using the same
    // zero-page pointer as upload. No nested C indexing runs in the inner loop.
    __asm {
        PHA
        TXA
        PHA
        TYA
        PHA
        LDX #0
w3dfc_clear_next:
        LDA w3dfc_dirty,X
        BEQ w3dfc_clear_skip
        TXA
        ASL A
        ASL A
        ASL A
        STA w3dfc_upload_ptr
        TXA
        LSR A
        LSR A
        LSR A
        LSR A
        LSR A
        CLC
        ADC #104
        STA w3dfc_upload_ptr+1
        LDA #0
        STA w3dfc_dirty,X
        LDY #7
w3dfc_clear_byte:
        STA (w3dfc_upload_ptr),Y
        DEY
        BPL w3dfc_clear_byte
w3dfc_clear_skip:
        INX
        CPX w3dfc_tile_count
        BNE w3dfc_clear_next
        PLA
        TAY
        PLA
        TAX
        PLA
    }
}
Wire3DFC_DrawLine2D

Rastert eine Linie einschließlich beider Endpunkte in den Vorbereitungsspeicher und markiert betroffene Kacheln zur Übertragung. Es erfolgt keine Kameraprojektion.

Syntax

c
void Wire3DFC_DrawLine2D(s16 ax,s16 ay,s16 bx,s16 by);

Parameter

ax

Horizontale Startkoordinate in Pixeln des Ansichtsbereichs von −512 bis 511. Dessen linke obere Ecke ist (0,0).

ay

Vertikale Startkoordinate in Pixeln des Ansichtsbereichs von −512 bis 511. Dessen linke obere Ecke ist (0,0).

bx

Horizontale Endkoordinate in Pixeln des Ansichtsbereichs von −512 bis 511. Dessen linke obere Ecke ist (0,0).

by

Vertikale Endkoordinate in Pixeln des Ansichtsbereichs von −512 bis 511. Dessen linke obere Ecke ist (0,0).

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Verwirft die gesamte Linie, sobald eine Endpunktkoordinate außerhalb von −512 bis 511 liegt. Andernfalls werden nur Pixel außerhalb des Ansichtsbereichs verworfen. Neue Pixel werden per OR mit vorbereiteten Linien verknüpft und durch EndFrame sichtbar.

Benötigt 8 KiB CHR-RAM, beschreibbares Cartridge-PRG-RAM bei $6800–$70BF und Zero-Page-Zwischenspeicher bei $00–$0A. Bauen Sie mit --nes-chr-ram. Aufgrund des gemeinsam genutzten Arbeitsspeichers ist der Renderer nicht reentrant.

Rufen Sie Init, BeginFrame, Zeichenfunktionen und EndFrame in dieser Reihenfolge auf. Die Bibliothek übernimmt beide Hintergrund-Mustertabellen, Nametable null, Hintergrundpalette und Scrollposition und deaktiviert NMI. Führen Sie keine anderen PPU-Schreibzugriffe gleichzeitig aus.

Wählen Sie 64×48 (Standard), 96×64 oder 128×96, indem Sie vor dem Einbinden von wire3d.c sowohl WIRE3D_FC_WIDTH als auch WIRE3D_FC_HEIGHT definieren. Der Ansichtsbereich liegt mittig auf dem Bildschirm. Kleinere Ansichten verringern Zeichen- und Übertragungsaufwand, reservieren aber dieselbe RAM-Kapazität.

Die Bilder wurden in KUROSAKI in allen drei Größen aufgenommen. Die Prüfungen vergleichen jedes Pixel des 256×240-Bildes einschließlich Farbe sowie die numerischen Ergebnisse im RAM. Es handelt sich nicht um Leistungsmessungen auf echter Hardware.

Anwendungsbeispiel

c
Wire3DFC_DrawLine2D(0,0,WIRE3D_FC_WIDTH-1,0);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.

Wire3DFC_DrawLine2D: 64X48 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
64X48 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
Wire3DFC_DrawLine2D: 96X64 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
96X64 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
Wire3DFC_DrawLine2D: 128X96 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
128X96 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.

Vollständiges Beispielprogramm

Build-Befehl

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\wire3d_projection.c -I .\kitaqfc\lib --mapper=nrom --nes-chr-ram -o .\out\wire3d_projection.nes --no-cache --no-disasm
.\kurosaki\kurosaki.exe run .\out\wire3d_projection.nes --headless --frames 180 --png .\out\wire3d_projection.png
Implementierung und Quelltext

kitaqfc/lib/wire3d.h:39

Deklarationshinweise im Original
Draw a connected, inclusive segment. Endpoints must be -512..511. Pixels
outside the viewport are clipped; completely outside bounding boxes return.

kitaqfc/lib/wire3d.c:193

c
void Wire3DFC_DrawLine2D(s16 ax,s16 ay,s16 bx,s16 by) {
    s16 dx,dy,sx,sy,error,twice;u16 address;u8 tile;
    if(ax < -512 || ax>511 || ay < -512 || ay>511 || bx < -512 || bx>511 || by < -512 || by>511)return;
    if((ax<0 && bx<0)||(ay<0 && by<0)||(ax>=WIRE3D_FC_WIDTH && bx>=WIRE3D_FC_WIDTH)||(ay>=WIRE3D_FC_HEIGHT && by>=WIRE3D_FC_HEIGHT))return;
    dx=bx-ax;if(dx<0)dx=0-dx;
    dy=by-ay;if(dy<0)dy=0-dy;
    if(ax>=0 && ay>=0 && bx>=0 && by>=0 && ax<WIRE3D_FC_WIDTH && bx<WIRE3D_FC_WIDTH && ay<WIRE3D_FC_HEIGHT && by<WIRE3D_FC_HEIGHT) {
        w3dfc_lx=(u8)ax;w3dfc_ly=(u8)ay;
        w3dfc_sx=ax<bx?1:255;w3dfc_sy=ay<by?1:255;
        if(dx>=dy){w3dfc_major=(u8)dx;w3dfc_minor=(u8)dy;w3dfc_y_major=0;}
        else{w3dfc_major=(u8)dy;w3dfc_minor=(u8)dx;w3dfc_y_major=1;}
        w3dfc_error=(u8)(w3dfc_major>>1);w3dfc_remaining=(u8)(w3dfc_major+1);
        w3dfc_line_inside();return;
    }
    sx=ax<bx?1:-1;sy=ay<by?1:-1;error=dx-dy;
    while(1) {
        if(ax>=0 && ax<WIRE3D_FC_WIDTH && ay>=0 && ay<WIRE3D_FC_HEIGHT) {
            tile=(u8)(((u8)ay>>3)*(WIRE3D_FC_WIDTH/8)+((u8)ax>>3));
            address=(u16)tile*8+((u8)ay&7);
            w3dfc_pixels[address]=(u8)(w3dfc_pixels[address]|w3dfc_bits[(u8)ax&7]);
            w3dfc_dirty[tile]=1;
        }
        if(ax==bx && ay==by)return;
        twice=error*2;
        if(twice > (0-dy)){error-=dy;ax+=sx;}
        if(twice < dx){error+=dx;ay+=sy;}
    }
}
Wire3DFC_RotatePoint

Dreht einen Punkt im Modellraum direkt an dessen Speicherstelle, ohne Verschiebung oder perspektivische Projektion.

Syntax

c
void Wire3DFC_RotatePoint(s16* x,s16* y,s16* z,u8 rx,u8 ry,u8 rz);

Parameter

x

Zeiger auf die beschreibbare s16-x-Komponente. Verwenden Sie drei unterschiedliche Speicherstellen und halten Sie jede Eingabekomponente im Bereich −63 bis 63.

y

Zeiger auf die beschreibbare s16-y-Komponente. Verwenden Sie drei unterschiedliche Speicherstellen und halten Sie jede Eingabekomponente im Bereich −63 bis 63.

z

Zeiger auf die beschreibbare s16-z-Komponente. Verwenden Sie drei unterschiedliche Speicherstellen und halten Sie jede Eingabekomponente im Bereich −63 bis 63.

rx

Drehwinkel um die X-Achse in 32 Schritten pro Umdrehung.

ry

Drehwinkel um die Y-Achse in 32 Schritten pro Umdrehung.

rz

Drehwinkel um die Z-Achse in 32 Schritten pro Umdrehung.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Winkel verwenden 32 Schritte pro Umdrehung: 0 bedeutet keine Drehung, 8 entspricht 90 Grad und 16 entspricht 180 Grad. Nur die unteren fünf Bits werden verwendet. Drehungen erfolgen in der Reihenfolge Y, X, Z.

Ist einer der Zeiger null, erfolgt die Rückkehr ohne Koordinatenänderung. Q6-Ganzzahlprodukte werden gegen null abgeschnitten. Eingabekomponenten werden nicht automatisch begrenzt.

Benötigt 8 KiB CHR-RAM, beschreibbares Cartridge-PRG-RAM bei $6800–$70BF und Zero-Page-Zwischenspeicher bei $00–$0A. Bauen Sie mit --nes-chr-ram. Aufgrund des gemeinsam genutzten Arbeitsspeichers ist der Renderer nicht reentrant.

Rufen Sie Init, BeginFrame, Zeichenfunktionen und EndFrame in dieser Reihenfolge auf. Die Bibliothek übernimmt beide Hintergrund-Mustertabellen, Nametable null, Hintergrundpalette und Scrollposition und deaktiviert NMI. Führen Sie keine anderen PPU-Schreibzugriffe gleichzeitig aus.

Wählen Sie 64×48 (Standard), 96×64 oder 128×96, indem Sie vor dem Einbinden von wire3d.c sowohl WIRE3D_FC_WIDTH als auch WIRE3D_FC_HEIGHT definieren. Der Ansichtsbereich liegt mittig auf dem Bildschirm. Kleinere Ansichten verringern Zeichen- und Übertragungsaufwand, reservieren aber dieselbe RAM-Kapazität.

Die Bilder wurden in KUROSAKI in allen drei Größen aufgenommen. Die Prüfungen vergleichen jedes Pixel des 256×240-Bildes einschließlich Farbe sowie die numerischen Ergebnisse im RAM. Es handelt sich nicht um Leistungsmessungen auf echter Hardware.

Anwendungsbeispiel

c
Wire3DFC_RotatePoint(&px,&py,&pz,0,0,8);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.

Im Beispiel verwandelt eine Z-Drehung um 90 Grad (24,0,0) in (0,24,0); das projizierte Kreuz erscheint oberhalb des Würfels.

Wire3DFC_RotatePoint: 64X48 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen. Im Beispiel verwandelt eine Z-Drehung um 90 Grad (24,0,0) in (0,24,0); das projizierte Kreuz erscheint oberhalb des Würfels.
64X48 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen. Im Beispiel verwandelt eine Z-Drehung um 90 Grad (24,0,0) in (0,24,0); das projizierte Kreuz erscheint oberhalb des Würfels.
Wire3DFC_RotatePoint: 96X64 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen. Im Beispiel verwandelt eine Z-Drehung um 90 Grad (24,0,0) in (0,24,0); das projizierte Kreuz erscheint oberhalb des Würfels.
96X64 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen. Im Beispiel verwandelt eine Z-Drehung um 90 Grad (24,0,0) in (0,24,0); das projizierte Kreuz erscheint oberhalb des Würfels.
Wire3DFC_RotatePoint: 128X96 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen. Im Beispiel verwandelt eine Z-Drehung um 90 Grad (24,0,0) in (0,24,0); das projizierte Kreuz erscheint oberhalb des Würfels.
128X96 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen. Im Beispiel verwandelt eine Z-Drehung um 90 Grad (24,0,0) in (0,24,0); das projizierte Kreuz erscheint oberhalb des Würfels.

Vollständiges Beispielprogramm

Build-Befehl

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\wire3d_projection.c -I .\kitaqfc\lib --mapper=nrom --nes-chr-ram -o .\out\wire3d_projection.nes --no-cache --no-disasm
.\kurosaki\kurosaki.exe run .\out\wire3d_projection.nes --headless --frames 180 --png .\out\wire3d_projection.png
Implementierung und Quelltext

kitaqfc/lib/wire3d.h:42

Deklarationshinweise im Original
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.

kitaqfc/lib/wire3d.c:227

c
void Wire3DFC_RotatePoint(s16* x,s16* y,s16* z,u8 rx,u8 ry,u8 rz) {
    s16 a,b,s,c;
    if(x==0 || y==0 || z==0)return;
    ry=(u8)(ry&31);rx=(u8)(rx&31);rz=(u8)(rz&31);
    if(ry!=0){a=*x;b=*z;s=w3dfc_sin[ry];c=w3dfc_sin[(u8)((ry+8)&31)];*x=w3dfc_q6(a*c+b*s);*z=w3dfc_q6(b*c-a*s);}
    if(rx!=0){a=*y;b=*z;s=w3dfc_sin[rx];c=w3dfc_sin[(u8)((rx+8)&31)];*y=w3dfc_q6(a*c-b*s);*z=w3dfc_q6(a*s+b*c);}
    if(rz!=0){a=*x;b=*y;s=w3dfc_sin[rz];c=w3dfc_sin[(u8)((rz+8)&31)];*x=w3dfc_q6(a*c-b*s);*y=w3dfc_q6(a*s+b*c);}
}
Wire3DFC_ProjectPoint

Projiziert einen Punkt im Kameraraum auf Pixel des Ansichtsbereichs, dessen Mitte als Projektionszentrum dient. Dabei wird weder gezeichnet noch eine Maske verändert.

Syntax

c
u8 Wire3DFC_ProjectPoint(s16 x,s16 y,s16 z,s16* sx,s16* sy);

Parameter

x

X-Koordinate im Kameraraum. Verwenden Sie −127 bis 127. Positives X zeigt nach rechts, positives Y nach oben.

y

Y-Koordinate im Kameraraum. Verwenden Sie −127 bis 127. Positives X zeigt nach rechts, positives Y nach oben.

z

Z-Koordinate im Kameraraum. Die Tiefe muss zwischen 32 und 255 liegen; größere Werte liegen weiter entfernt.

sx

Beschreibbarer s16-Zeiger für die projizierte horizontale Pixelkoordinate. Verwenden Sie unterschiedliche Ausgabestellen.

sy

Beschreibbarer s16-Zeiger für die projizierte vertikale Pixelkoordinate. Verwenden Sie unterschiedliche Ausgabestellen.

Rückgabewert

Gibt bei Erfolg 1 zurück, bei Koordinaten außerhalb des Bereichs oder Null-Ausgabezeigern dagegen 0. Fehlgeschlagene Aufrufe lassen die Ausgaben unverändert.

Bedingungen und Grenzen

Eine gültige Tiefe garantiert kein Ergebnis innerhalb des Bildschirms. Ausgabekoordinaten werden nicht auf den Ansichtsbereich begrenzt. Die ganzzahlige Kehrwertnäherung kann um einige Pixel von einer idealen Gleitkommaprojektion abweichen.

Benötigt 8 KiB CHR-RAM, beschreibbares Cartridge-PRG-RAM bei $6800–$70BF und Zero-Page-Zwischenspeicher bei $00–$0A. Bauen Sie mit --nes-chr-ram. Aufgrund des gemeinsam genutzten Arbeitsspeichers ist der Renderer nicht reentrant.

Rufen Sie Init, BeginFrame, Zeichenfunktionen und EndFrame in dieser Reihenfolge auf. Die Bibliothek übernimmt beide Hintergrund-Mustertabellen, Nametable null, Hintergrundpalette und Scrollposition und deaktiviert NMI. Führen Sie keine anderen PPU-Schreibzugriffe gleichzeitig aus.

Wählen Sie 64×48 (Standard), 96×64 oder 128×96, indem Sie vor dem Einbinden von wire3d.c sowohl WIRE3D_FC_WIDTH als auch WIRE3D_FC_HEIGHT definieren. Der Ansichtsbereich liegt mittig auf dem Bildschirm. Kleinere Ansichten verringern Zeichen- und Übertragungsaufwand, reservieren aber dieselbe RAM-Kapazität.

Die Bilder wurden in KUROSAKI in allen drei Größen aufgenommen. Die Prüfungen vergleichen jedes Pixel des 256×240-Bildes einschließlich Farbe sowie die numerischen Ergebnisse im RAM. Es handelt sich nicht um Leistungsmessungen auf echter Hardware.

Anwendungsbeispiel

c
projected=Wire3DFC_ProjectPoint(px,py,pz+96,&sx,&sy);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.

Von der linken oberen Ecke des Ansichtsbereichs aus liegt der Kreuzmittelpunkt bei 64×48 auf (32,16), bei 96×64 auf (48,20) und bei 128×96 auf (64,33).

Wire3DFC_ProjectPoint: 64X48 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen. Von der linken oberen Ecke des Ansichtsbereichs aus liegt der Kreuzmittelpunkt bei 64×48 auf (32,16), bei 96×64 auf (48,20) und bei 128×96 auf (64,33).
64X48 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen. Von der linken oberen Ecke des Ansichtsbereichs aus liegt der Kreuzmittelpunkt bei 64×48 auf (32,16), bei 96×64 auf (48,20) und bei 128×96 auf (64,33).
Wire3DFC_ProjectPoint: 96X64 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen. Von der linken oberen Ecke des Ansichtsbereichs aus liegt der Kreuzmittelpunkt bei 64×48 auf (32,16), bei 96×64 auf (48,20) und bei 128×96 auf (64,33).
96X64 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen. Von der linken oberen Ecke des Ansichtsbereichs aus liegt der Kreuzmittelpunkt bei 64×48 auf (32,16), bei 96×64 auf (48,20) und bei 128×96 auf (64,33).
Wire3DFC_ProjectPoint: 128X96 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen. Von der linken oberen Ecke des Ansichtsbereichs aus liegt der Kreuzmittelpunkt bei 64×48 auf (32,16), bei 96×64 auf (48,20) und bei 128×96 auf (64,33).
128X96 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen. Von der linken oberen Ecke des Ansichtsbereichs aus liegt der Kreuzmittelpunkt bei 64×48 auf (32,16), bei 96×64 auf (48,20) und bei 128×96 auf (64,33).

Vollständiges Beispielprogramm

Build-Befehl

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\wire3d_projection.c -I .\kitaqfc\lib --mapper=nrom --nes-chr-ram -o .\out\wire3d_projection.nes --no-cache --no-disasm
.\kurosaki\kurosaki.exe run .\out\wire3d_projection.nes --headless --frames 180 --png .\out\wire3d_projection.png
Implementierung und Quelltext

kitaqfc/lib/wire3d.h:46

Deklarationshinweise im Original
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.

kitaqfc/lib/wire3d.c:235

c
u8 Wire3DFC_ProjectPoint(s16 x,s16 y,s16 z,s16* sx,s16* sy) {
    u8 scale;u16 magnitude;
    if(sx==0 || sy==0 || x < -127 || x>127 || y < -127 || y>127 || z<32 || z>255)return 0;
    // Focal length follows half the selected width. Use unsigned magnitude
    // products and shifts so negative coordinates mirror positive ones exactly.
    scale=w3dfc_recip[(u8)z];
    if(x<0){magnitude=__mul16x8((u16)(0-x),scale);*sx=WIRE3D_FC_WIDTH/2-(s16)(magnitude>>7);}
    else{magnitude=__mul16x8((u16)x,scale);*sx=WIRE3D_FC_WIDTH/2+(s16)(magnitude>>7);}
    if(y<0){magnitude=__mul16x8((u16)(0-y),scale);*sy=WIRE3D_FC_HEIGHT/2+(s16)(magnitude>>7);}
    else{magnitude=__mul16x8((u16)y,scale);*sy=WIRE3D_FC_HEIGHT/2-(s16)(magnitude>>7);}
    return 1;
}
Wire3DFC_DrawLine3D

Projiziert zwei Endpunkte im Kameraraum und zeichnet die Linie, wenn beide gültig sind. Führen Sie Modellrotationen oder -verschiebungen vor dem Aufruf aus.

Syntax

c
void Wire3DFC_DrawLine3D(s16 ax,s16 ay,s16 az,s16 bx,s16 by,s16 bz);

Parameter

ax

Start-X-Koordinate im Kameraraum; verwenden Sie −127 bis 127.

ay

Start-Y-Koordinate im Kameraraum; verwenden Sie −127 bis 127.

az

Start-Z-Koordinate im Kameraraum; verwenden Sie eine Tiefe von 32 bis 255.

bx

End-X-Koordinate im Kameraraum; verwenden Sie −127 bis 127.

by

End-Y-Koordinate im Kameraraum; verwenden Sie −127 bis 127.

bz

End-Z-Koordinate im Kameraraum; verwenden Sie eine Tiefe von 32 bis 255.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Schlägt die Projektion eines Endpunkts fehl, wird das gesamte Segment verworfen. Es findet kein Abschneiden am Schnittpunkt mit der Nah-Ebene statt. DrawLine2D verwirft bei angenommenen Segmenten die Pixel außerhalb des Ansichtsbereichs.

Benötigt 8 KiB CHR-RAM, beschreibbares Cartridge-PRG-RAM bei $6800–$70BF und Zero-Page-Zwischenspeicher bei $00–$0A. Bauen Sie mit --nes-chr-ram. Aufgrund des gemeinsam genutzten Arbeitsspeichers ist der Renderer nicht reentrant.

Rufen Sie Init, BeginFrame, Zeichenfunktionen und EndFrame in dieser Reihenfolge auf. Die Bibliothek übernimmt beide Hintergrund-Mustertabellen, Nametable null, Hintergrundpalette und Scrollposition und deaktiviert NMI. Führen Sie keine anderen PPU-Schreibzugriffe gleichzeitig aus.

Wählen Sie 64×48 (Standard), 96×64 oder 128×96, indem Sie vor dem Einbinden von wire3d.c sowohl WIRE3D_FC_WIDTH als auch WIRE3D_FC_HEIGHT definieren. Der Ansichtsbereich liegt mittig auf dem Bildschirm. Kleinere Ansichten verringern Zeichen- und Übertragungsaufwand, reservieren aber dieselbe RAM-Kapazität.

Die Bilder wurden in KUROSAKI in allen drei Größen aufgenommen. Die Prüfungen vergleichen jedes Pixel des 256×240-Bildes einschließlich Farbe sowie die numerischen Ergebnisse im RAM. Es handelt sich nicht um Leistungsmessungen auf echter Hardware.

Anwendungsbeispiel

c
Wire3DFC_DrawLine3D(-24,-24,96,24,-24,96);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.

Wire3DFC_DrawLine3D: 64X48 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
64X48 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
Wire3DFC_DrawLine3D: 96X64 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
96X64 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
Wire3DFC_DrawLine3D: 128X96 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
128X96 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.

Vollständiges Beispielprogramm

Build-Befehl

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\wire3d_projection.c -I .\kitaqfc\lib --mapper=nrom --nes-chr-ram -o .\out\wire3d_projection.nes --no-cache --no-disasm
.\kurosaki\kurosaki.exe run .\out\wire3d_projection.nes --headless --frames 180 --png .\out\wire3d_projection.png
Implementierung und Quelltext

kitaqfc/lib/wire3d.h:49

Deklarationshinweise im Original
Draw when both endpoints pass the projection range. Near-plane crossings
are rejected, not intersected with the near plane; screen pixels are clipped.

kitaqfc/lib/wire3d.c:247

c
void Wire3DFC_DrawLine3D(s16 ax,s16 ay,s16 az,s16 bx,s16 by,s16 bz) {
    s16 x0,y0,x1,y1;
    if(Wire3DFC_ProjectPoint(ax,ay,az,&x0,&y0)==0)return;
    if(Wire3DFC_ProjectPoint(bx,by,bz,&x1,&y1)==0)return;
    Wire3DFC_DrawLine2D(x0,y0,x1,y1);
}
Wire3DFC_DrawModel

Dreht, verschiebt und projiziert die Vertices einmal und verwendet deren Bildschirmkoordinaten beim Zeichnen der indizierten Kanten erneut.

Syntax

c
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);

Parameter

vertices

Array aus Wire3DFC_Vec3-Datensätzen mit s8-Komponenten x/y/z. Halten Sie die Komponenten im Bereich −63 bis 63 und stellen Sie die angegebene Vertexanzahl bereit.

vertex_count

Anzahl der Vertices; bei Werten über 24 werden nur die ersten 24 verwendet.

edges

Array aus Wire3DFC_Edge-Datensätzen mit den Vertexindizes a/b. Stellen Sie edge_count Elemente bereit.

edge_count

Anzahl zu verarbeitender Kanten (0 bis 255). Kanten mit Verweisen auf Vertices außerhalb der tatsächlich genutzten Anzahl werden übersprungen.

x

Nach der Drehung addierte X-Verschiebung. Transformierte Punkte müssen innerhalb der Eingabebereiche von ProjectPoint liegen.

y

Nach der Drehung addierte Y-Verschiebung. Transformierte Punkte müssen innerhalb der Eingabebereiche von ProjectPoint liegen.

z

Nach der Drehung addierte Z-Verschiebung. Transformierte Punkte müssen innerhalb der Eingabebereiche von ProjectPoint liegen.

rx

Drehwinkel um die X-Achse in 32 Schritten pro Umdrehung.

ry

Drehwinkel um die Y-Achse in 32 Schritten pro Umdrehung.

rz

Drehwinkel um die Z-Achse in 32 Schritten pro Umdrehung.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Winkel verwenden 32 Schritte pro Umdrehung: 0 bedeutet keine Drehung, 8 entspricht 90 Grad und 16 entspricht 180 Grad. Nur die unteren fünf Bits werden verwendet. Drehungen erfolgen in der Reihenfolge Y, X, Z.

Bei null für vertices oder edges wird nichts gezeichnet. Die Tabellen müssen in der aktuellen PRG-Einblendung lesbar bleiben. Diese API verwendet weder Flächendaten noch eine Tiefenmaske und zeichnet jede gültige Kante. Daher bleiben auch die hinteren Würfelkanten sichtbar.

Benötigt 8 KiB CHR-RAM, beschreibbares Cartridge-PRG-RAM bei $6800–$70BF und Zero-Page-Zwischenspeicher bei $00–$0A. Bauen Sie mit --nes-chr-ram. Aufgrund des gemeinsam genutzten Arbeitsspeichers ist der Renderer nicht reentrant.

Rufen Sie Init, BeginFrame, Zeichenfunktionen und EndFrame in dieser Reihenfolge auf. Die Bibliothek übernimmt beide Hintergrund-Mustertabellen, Nametable null, Hintergrundpalette und Scrollposition und deaktiviert NMI. Führen Sie keine anderen PPU-Schreibzugriffe gleichzeitig aus.

Wählen Sie 64×48 (Standard), 96×64 oder 128×96, indem Sie vor dem Einbinden von wire3d.c sowohl WIRE3D_FC_WIDTH als auch WIRE3D_FC_HEIGHT definieren. Der Ansichtsbereich liegt mittig auf dem Bildschirm. Kleinere Ansichten verringern Zeichen- und Übertragungsaufwand, reservieren aber dieselbe RAM-Kapazität.

Die Bilder wurden in KUROSAKI in allen drei Größen aufgenommen. Die Prüfungen vergleichen jedes Pixel des 256×240-Bildes einschließlich Farbe sowie die numerischen Ergebnisse im RAM. Es handelt sich nicht um Leistungsmessungen auf echter Hardware.

Anwendungsbeispiel

c
Wire3DFC_DrawModel(example_vertices,8,example_edges,12,0,0,96,0,3,0);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.

Wire3DFC_DrawModel: 64X48 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
64X48 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
Wire3DFC_DrawModel: 96X64 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
96X64 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
Wire3DFC_DrawModel: 128X96 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
128X96 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.

Vollständiges Beispielprogramm

Build-Befehl

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\wire3d_projection.c -I .\kitaqfc\lib --mapper=nrom --nes-chr-ram -o .\out\wire3d_projection.nes --no-cache --no-disasm
.\kurosaki\kurosaki.exe run .\out\wire3d_projection.nes --headless --frames 180 --png .\out\wire3d_projection.png
Implementierung und Quelltext

kitaqfc/lib/wire3d.h:53

Deklarationshinweise im Original
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.

kitaqfc/lib/wire3d.c:253

c
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) {
    u8 i,a,b;s16 px,py,pz;
    if(vertices==0 || edges==0)return;
    if(vertex_count>24)vertex_count=24;
    for(i=0;i<vertex_count;i++) {
        px=vertices[i].x;py=vertices[i].y;pz=vertices[i].z;
        Wire3DFC_RotatePoint(&px,&py,&pz,rx,ry,rz);
        w3dfc_valid[i]=Wire3DFC_ProjectPoint(px+x,py+y,pz+z,&w3dfc_projected_x[i],&w3dfc_projected_y[i]);
    }
    for(i=0;i<edge_count;i++) {
        a=edges[i].a;b=edges[i].b;
        if(a<vertex_count && b<vertex_count && w3dfc_valid[a]!=0 && w3dfc_valid[b]!=0)
            Wire3DFC_DrawLine2D(w3dfc_projected_x[a],w3dfc_projected_y[a],w3dfc_projected_x[b],w3dfc_projected_y[b]);
    }
}
Wire3DFC_EndFrame

Überträgt berührte sowie zu löschende Kacheln in die verborgene CHR-Tabelle und wechselt nach Abschluss bei einem neuen VBlank die angezeigte Tabelle.

Syntax

c
void Wire3DFC_EndFrame(void);

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Jeder VBlank-Block überträgt höchstens 16 Kacheln bzw. 128 Bytes der niedrigen Bitebene. Dieser synchrone Aufruf wartet auf alle benötigten Blöcke. wire3d_uploaded_tiles meldet die übertragenen Kacheln. wire3d_transfer_frames zählt die Übertragungsblöcke plus eine Wartezeit für den Wechsel, nicht alle tatsächlich vergangenen Spielframes.

Die Historie der verborgenen Tabelle ermöglicht das Löschen alter Linien nach einer Objektbewegung. Verfolgt werden beim Zeichnen berührte Kacheln; es werden nicht alle Kachelbytes zwischen Frames verglichen.

Benötigt 8 KiB CHR-RAM, beschreibbares Cartridge-PRG-RAM bei $6800–$70BF und Zero-Page-Zwischenspeicher bei $00–$0A. Bauen Sie mit --nes-chr-ram. Aufgrund des gemeinsam genutzten Arbeitsspeichers ist der Renderer nicht reentrant.

Rufen Sie Init, BeginFrame, Zeichenfunktionen und EndFrame in dieser Reihenfolge auf. Die Bibliothek übernimmt beide Hintergrund-Mustertabellen, Nametable null, Hintergrundpalette und Scrollposition und deaktiviert NMI. Führen Sie keine anderen PPU-Schreibzugriffe gleichzeitig aus.

Wählen Sie 64×48 (Standard), 96×64 oder 128×96, indem Sie vor dem Einbinden von wire3d.c sowohl WIRE3D_FC_WIDTH als auch WIRE3D_FC_HEIGHT definieren. Der Ansichtsbereich liegt mittig auf dem Bildschirm. Kleinere Ansichten verringern Zeichen- und Übertragungsaufwand, reservieren aber dieselbe RAM-Kapazität.

Die Bilder wurden in KUROSAKI in allen drei Größen aufgenommen. Die Prüfungen vergleichen jedes Pixel des 256×240-Bildes einschließlich Farbe sowie die numerischen Ergebnisse im RAM. Es handelt sich nicht um Leistungsmessungen auf echter Hardware.

Anwendungsbeispiel

c
Wire3DFC_EndFrame();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.

Wire3DFC_EndFrame: 64X48 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
64X48 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
Wire3DFC_EndFrame: 96X64 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
96X64 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
Wire3DFC_EndFrame: 128X96 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.
128X96 — Das fertige Bild zeigt auf Schwarz einen cyanfarbenen Rand, einen Würfel in der Mitte, ein Kreuz darüber und eine waagerechte Linie darunter. Der Rand verwendet 2D-Koordinaten, das Kreuz Punktrotation und Projektion, die untere Linie Endpunkte im Kameraraum und der Würfel Vertex- und Kantenarrays. An diesen Formen lassen sich die Aufgaben der APIs auf einem Bildschirm vergleichen.

Vollständiges Beispielprogramm

Build-Befehl

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqfc\kitaqfc.exe .\kitaq-docs\samples\api-examples\fc\wire3d_projection.c -I .\kitaqfc\lib --mapper=nrom --nes-chr-ram -o .\out\wire3d_projection.nes --no-cache --no-disasm
.\kurosaki\kurosaki.exe run .\out\wire3d_projection.nes --headless --frames 180 --png .\out\wire3d_projection.png
Implementierung und Quelltext

kitaqfc/lib/wire3d.h:57

Deklarationshinweise im Original
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.

kitaqfc/lib/wire3d.c:336

c
void Wire3DFC_EndFrame(void) {
    u8 tile,back,old;u16 source,destination;
    back=(u8)(w3dfc_front^16);wire3d_transfer_frames=0;wire3d_uploaded_tiles=0;w3dfc_batch_count=0;
    for(tile=0;tile<WIRE3D_FC_TILES;tile++) {
        if(back==0)old=w3dfc_bank0_dirty[tile];else old=w3dfc_bank1_dirty[tile];
        if(old!=0 || w3dfc_dirty[tile]!=0) {
            source=(u16)(0x6800+(u16)tile*8);
            destination=(u16)((u16)back*256+(u16)tile*16);
            w3dfc_src_lo[w3dfc_batch_count]=(u8)source;w3dfc_src_hi[w3dfc_batch_count]=(u8)(source>>8);
            w3dfc_dst_lo[w3dfc_batch_count]=(u8)destination;w3dfc_dst_hi[w3dfc_batch_count]=(u8)(destination>>8);
            w3dfc_batch_count++;wire3d_uploaded_tiles++;
            if(back==0)w3dfc_bank0_dirty[tile]=w3dfc_dirty[tile];else w3dfc_bank1_dirty[tile]=w3dfc_dirty[tile];
            if(w3dfc_batch_count==16)w3dfc_upload_batch();
        }
    }
    if(w3dfc_batch_count!=0)w3dfc_upload_batch();
    // Switch pattern tables only at a fresh VBlank, after every transfer finishes.
    while((w3dfc_status&128)!=0){}
    while((w3dfc_status&128)==0){}
    w3dfc_front=back;__ppu_ctrl_set(back);__scroll_set(0,0);
    wire3d_transfer_frames++;
}

9. Ressourcen, Mapper und FDS

bank und asset beschreiben PRG-Banken und Ressourcen. Ob eine Operation aus mapper.h wirksam ist, hängt vom beim Build gewählten Mapper ab. Planen Sie Konfiguration, Aktivierung, Quittierung und Deaktivierung von Scroll-IRQs als zusammenhängenden Ablauf.

FDS-Dienste verteilen sich auf fds_file, fds_overlay, fds_save und fds_sound. Ein geladenes Overlay ersetzt Code an einer bestehenden Adresse. Beachten Sie deshalb Rücksprungziele und die Gültigkeitsdauer von Daten. Gehen Sie nicht vom gewöhnlichen Far-Call-Verhalten eines Moduls aus.

10. Referenzeinträge und Beispiele

Das folgende Verzeichnis orientiert sich an den öffentlichen Headern und unterscheidet Funktionen, funktionsartige Makros und Aliase. Die vollständigen Header enthalten auch Strukturen und Konstanten. Nur deklarierte APIs, lediglich gespeicherte Callbacks und spezielle Geräteschnittstellen werden von gewöhnlichen geprüften Operationen unterschieden. Quellkommentare bleiben zum genauen Vergleich mit der Implementierung unverändert.

vram_get_queue_capacity() liefert die Gesamtkapazität des Befehlspuffers von 128 Bytes. vram_get_queue_free() liefert die freien Bytes: Gesamtkapazität minus vram_get_queue_used(). Gemeint sind codierte Befehle einschließlich Verwaltungsdaten, kein freier Hardware-VRAM. Ein einzelner Kachelschreibzugriff benötigt 4 Bytes, Füllen 5 und eine zeigerbasierte Kopie 6 Bytes. Prüfen Sie den Platz vor der Freigabe; NMI kann eine freigegebene Warteschlange asynchron abarbeiten.

Vollständige Beispielprogramme

Enthalten sind alle Programme, die gemeinsamen Header, die bereitgestellte ascii.c und die daraus konvertierten Ressourcen. Namen mit m_ am Anfang bezeichnen Hilfsfunktionen für diese Handbücher. Lesen Sie jeden Build-Befehl zusammen mit dem erwarteten Ergebnis und dem Prüfprotokoll. Führen Sie die Befehle im übergeordneten Ordner der nebeneinanderliegenden Repositories aus.

Skript zur Stapelkompilierung / Ergebnisse und Bildschirmaufnahmen

Den mitgelieferten Zeichensatz anzeigen fc_font.c

Zweck: Zeigt, welche Buchstaben, Ziffern und Satzzeichen die mitgelieferte eigens erstellte Schrift enthält und wie sie gezeichnet werden.

Funktionsweise: m_init bereitet Anzeige und Schrift vor. m_text zeichnet jede Zeile; m_put zeichnet das doppelte Anführungszeichen mit Zeichencode 34.

Bedienung und erwartetes Ergebnis: Prüfen Sie, ob 26 Großbuchstaben, 26 Kleinbuchstaben, 10 Ziffern und 30 Satzzeichen erscheinen und alle Zeichen gut lesbar sind. Es ist keine Eingabe erforderlich.

Den mitgelieferten Zeichensatz anzeigen: Prüfen Sie, ob 26 Großbuchstaben, 26 Kleinbuchstaben, 10 Ziffern und 30 Satzzeichen erscheinen und alle Zeichen gut lesbar sind. Es ist keine Eingabe erforderlich.
Anzeigebeispiel: Prüfen Sie, ob 26 Großbuchstaben, 26 Kleinbuchstaben, 10 Ziffern und 30 Satzzeichen erscheinen und alle Zeichen gut lesbar sind. Es ist keine Eingabe erforderlich.

Quelltext herunterladen / Prüfstatus

powershell
.\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
c
// 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();  }
}
Die erste Textausgabe fc_hello.c

Zweck: Zeigt den grundlegenden Ablauf zum Starten einer ROM und zum Zeichnen von Text und einer Zahl im Hintergrund.

Funktionsweise: Nach m_init zeichnet m_text die Begrüßung und m_number formatiert 42. Die abschließende Schleife wartet auf Frames und lässt das Bild sichtbar.

Bedienung und erwartetes Ergebnis: Der Bildschirm zeigt HELLO WORLD und 042. Die führende Null entsteht durch die Dezimaldarstellung mit drei Stellen.

Die erste Textausgabe: Der Bildschirm zeigt HELLO WORLD und 042. Die führende Null entsteht durch die Dezimaldarstellung mit drei Stellen.
Anzeigebeispiel: Der Bildschirm zeigt HELLO WORLD und 042. Die führende Null entsteht durch die Dezimaldarstellung mit drei Stellen.

Quelltext herunterladen / Prüfstatus

powershell
.\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
c
// 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();  }
}
Mit breiterem Zwischentyp rechnen fc_arithmetic.c

Zweck: Zeigt, wie ein Zwischenergebnis gespeichert wird, das nicht in acht Bit passt.

Funktionsweise: (u16)200 + 100 ergibt 300. Das Programm teilt das Ergebnis durch 10 und wandelt es anschließend zur Anzeige in u8 um. Beachten Sie, dass die Typverbreiterung vor der Addition erfolgt.

Bedienung und erwartetes Ergebnis: 030 steht für das berechnete Ergebnis 30.

Mit breiterem Zwischentyp rechnen: 030 steht für das berechnete Ergebnis 30.
Anzeigebeispiel: 030 steht für das berechnete Ergebnis 30.

Quelltext herunterladen / Prüfstatus

powershell
.\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
c
// 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();  }
}
Verzweigungen und Schleifen fc_control.c

Zweck: Erprobt for, continue, while und if/else in einer kleinen Berechnung.

Funktionsweise: Die for-Schleife addiert 0 bis 7, überspringt dabei 3 und erhält 25. Die while-Schleife zählt bis 32 weiter; das folgende if weist bei Übereinstimmung den Wert 42 zu.

Bedienung und erwartetes Ergebnis: 042 ist das Endergebnis. Das Programm verwendet eine if/else-Verzweigung.

Verzweigungen und Schleifen: Das Endergebnis ist 042. Dieses Programm verwendet eine if/else-Verzweigung.
Anzeigebeispiel: 042 ist das Endergebnis. Das Programm verwendet eine if/else-Verzweigung.

Quelltext herunterladen / Prüfstatus

powershell
.\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
c
// 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();  }
}
Funktionen, Arrays, Strukturen und Zeiger fc_aggregate.c

Zweck: Zeigt, wie Werte gruppiert und über Funktionen und Zeiger angesprochen werden.

Funktionsweise: Das Programm kopiert einen Point mit (10,20) und schreibt dann über einen Zeiger 1 bis 4 in ein Array. Es addiert das Funktionsergebnis 30, die Arraywerte 1, 2 und 4 sowie die Konstante 5.

Bedienung und erwartetes Ergebnis: Die Summe wird als 042 angezeigt. Verfolgen Sie die Strukturkopie, die Schreibzugriffe auf ptr[i] und den Rückgabewert der Funktion.

Funktionen, Arrays, Strukturen und Zeiger: Die Summe wird als 042 angezeigt. Verfolgen Sie die Strukturkopie, die Schreibzugriffe auf ptr[i] und den Rückgabewert der Funktion.
Anzeigebeispiel: Die Summe wird als 042 angezeigt. Verfolgen Sie die Strukturkopie, die Schreibzugriffe auf ptr[i] und den Rückgabewert der Funktion.

Quelltext herunterladen / Prüfstatus

powershell
.\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
c
// 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();  }
}
Bitflags und Pufferkopie fc_bits_memory.c

Zweck: Packt Flags in ein Byte und kopiert einen Puffer in einen getrennten Speicherbereich.

Funktionsweise: __memset löscht vier Bytes. Das Programm setzt Bit 3, invertiert Bit 1 und kopiert anschließend alle vier Bytes mit __memcpy.

Bedienung und erwartetes Ergebnis: Das erste Zielbyte wird als 010 angezeigt; Bit 3 trägt 8 und Bit 1 trägt 2 bei.

Bitflags und Pufferkopie: Das erste Zielbyte wird als 010 angezeigt; Bit 3 trägt 8 und Bit 1 trägt 2 bei.
Anzeigebeispiel: Das erste Zielbyte wird als 010 angezeigt; Bit 3 trägt 8 und Bit 1 trägt 2 bei.

Quelltext herunterladen / Prüfstatus

powershell
.\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
c
// 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();  }
}
Neue Tastendrücke zählen fc_input.c

Zweck: Unterscheidet einen neuen Tastendruck von einer weiterhin gedrückten Taste.

Funktionsweise: In jedem Frame wird input_update aufgerufen. Der Zähler steigt nur, wenn input_pressed(BTN_A) wahr ist.

Bedienung und erwartetes Ergebnis: Der Anfangswert ist 000. Drücken Sie A, um 001 zu erhalten; Gedrückthalten erhöht den Zähler nicht weiter. Loslassen und erneut drücken ergibt 002. Der Bytezähler springt nach 255 auf 000 zurück.

Neue Tastendrücke zählen: Der Anfangswert ist 000. Drücken Sie A, um 001 zu erhalten; Gedrückthalten erhöht den Zähler nicht weiter. Loslassen und erneut drücken ergibt 002. Der Bytezähler springt nach 255 auf 000 zurück.
Anzeigebeispiel: Der Anfangswert ist 000. Drücken Sie A, um 001 zu erhalten; Gedrückthalten erhöht den Zähler nicht weiter. Loslassen und erneut drücken ergibt 002. Der Bytezähler springt nach 255 auf 000 zurück.

Quelltext herunterladen / Prüfstatus

powershell
.\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
c
// 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); } }
}
Q8.8-Festkommawerte multiplizieren fc_fixed.c

Zweck: Zeigt die Umwandlung von Ganzzahlen in Q8.8, die Multiplikation und die Rückwandlung in eine Ganzzahl.

Funktionsweise: fix_from_int wandelt 3 und 4 in Q8.8 um. fix_mul multipliziert sie, und fix_to_int wandelt das Produkt wieder in eine Ganzzahl um.

Bedienung und erwartetes Ergebnis: 012 bedeutet 3 × 4 = 12. Es ist die umgewandelte Ganzzahl, nicht der intern mit 256 skalierte Wert.

Q8.8-Festkommawerte multiplizieren: 012 bedeutet 3 × 4 = 12. Es ist die umgewandelte Ganzzahl, nicht der intern mit 256 skalierte Wert.
Anzeigebeispiel: 012 bedeutet 3 × 4 = 12. Es ist die umgewandelte Ganzzahl, nicht der intern mit 256 skalierte Wert.

Quelltext herunterladen / Prüfstatus

powershell
.\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
c
// 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();  }
}
Aus einem festen Objektpool zuweisen fc_entity.c

Zweck: Erzeugt ein Objekt aus einer festen Menge von Speicherplätzen, ohne dynamische Speicherzuweisung.

Funktionsweise: entity_init setzt den Pool zurück. entity_create erzeugt Typ 1 bei (20,30); das Programm prüft auf die Fehler-ID 0xFF, bevor es vx auf 2 setzt.

Bedienung und erwartetes Ergebnis: 001 ist die Anzahl aktiver Objekte, keine ID oder Koordinate. Das Beispiel aktualisiert und zeichnet das Objekt nicht; daher erscheint keine bewegte Figur.

Aus einem festen Objektpool zuweisen: 001 ist die Anzahl aktiver Objekte, keine ID oder Koordinate. Das Beispiel aktualisiert und zeichnet das Objekt nicht; daher erscheint keine bewegte Figur.
Anzeigebeispiel: 001 ist die Anzahl aktiver Objekte, keine ID oder Koordinate. Das Beispiel aktualisiert und zeichnet das Objekt nicht; daher erscheint keine bewegte Figur.

Quelltext herunterladen / Prüfstatus

powershell
.\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
c
// 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();  }
}
Einen Diagnosewert im RAM aufzeichnen fc_debug.c

Zweck: Speichert einen benannten Spielwert getrennt von der Bildschirmanzeige in einem Diagnosepuffer.

Funktionsweise: Das Programm initialisiert die Diagnose, setzt die Framekennung auf 1 und zeichnet den Wert 42 unter dem Namen HP auf.

Bedienung und erwartetes Ergebnis: 001 ist die Anzahl der Trace-Einträge. HP=42 liegt im Diagnosepuffer; der Bildschirm allein zeigt oder bestätigt diesen Inhalt nicht.

Einen Diagnosewert im RAM aufzeichnen: 001 ist die Anzahl der Trace-Einträge. HP=42 liegt im Diagnosepuffer; der Bildschirm allein zeigt oder bestätigt diesen Inhalt nicht.
Anzeigebeispiel: 001 ist die Anzahl der Trace-Einträge. HP=42 liegt im Diagnosepuffer; der Bildschirm allein zeigt oder bestätigt diesen Inhalt nicht.

Quelltext herunterladen / Prüfstatus

powershell
.\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
c
// 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();  }
}
Einen Positionsverlauf speichern fc_chain.c

Zweck: Zeigt, wie ein Positionsverlauf in einem Ringpuffer gespeichert wird.

Funktionsweise: chain_init bindet ein Array mit Platz für vier Punkte ein. Anschließend zeichnet chain_push_head (20,30) auf.

Bedienung und erwartetes Ergebnis: 042 ist eine feste Abschlussmarkierung, keine Koordinate oder Anzahl. Prüfen Sie trail und points für den gespeicherten Verlauf. Dieses Programm zeichnet keinen nachfolgenden Körper.

Einen Positionsverlauf speichern: 042 ist eine feste Abschlussmarkierung, keine Koordinate oder Anzahl. Prüfen Sie trail und points für den gespeicherten Verlauf. Dieses Programm zeichnet keinen nachfolgenden Körper.
Anzeigebeispiel: 042 ist eine feste Abschlussmarkierung, keine Koordinate oder Anzahl. Prüfen Sie trail und points für den gespeicherten Verlauf. Dieses Programm zeichnet keinen nachfolgenden Körper.

Quelltext herunterladen / Prüfstatus

powershell
.\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
c
// 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();  }
}
Den Framezähler der Bibliothek lesen fc_system.c

Zweck: Zeigt, wie Wartezeiten in Frames den Framezähler der Bibliothek beeinflussen.

Funktionsweise: Nach system_init ruft das Programm system_wait_vblank zweimal auf und zeigt system_get_frame8 an.

Bedienung und erwartetes Ergebnis: Das Ergebnis ist 002. Die Warteschleife verwendet die Handbuch-Hilfsfunktion m_wait; der angezeigte Wert steigt daher nicht weiter.

Den Framezähler der Bibliothek lesen: Das Ergebnis ist 002. Die Warteschleife verwendet die Handbuch-Hilfsfunktion m_wait; der angezeigte Wert steigt daher nicht weiter.
Anzeigebeispiel: Das Ergebnis ist 002. Die Warteschleife verwendet die Handbuch-Hilfsfunktion m_wait; der angezeigte Wert steigt daher nicht weiter.

Quelltext herunterladen / Prüfstatus

powershell
.\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
c
// 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();  }
}
Die aktuelle Szenen-ID wählen fc_scene.c

Zweck: Zeigt, wie eine ID zur Unterscheidung von Szenen wie Titelbildschirm und Spiel gewählt wird.

Funktionsweise: Das Programm registriert zwei mit null initialisierte SceneDef-Einträge und wählt mit scene_change die ID 1.

Bedienung und erwartetes Ergebnis: 001 ist die aktuelle von scene_get_current gelieferte ID. In diesem Beispiel sind weder Szenen-Callbacks noch Übergangszeichnungen registriert.

Die aktuelle Szenen-ID wählen: 001 ist die aktuelle von scene_get_current gelieferte ID. In diesem Beispiel sind weder Szenen-Callbacks noch Übergangszeichnungen registriert.
Anzeigebeispiel: 001 ist die aktuelle von scene_get_current gelieferte ID. In diesem Beispiel sind weder Szenen-Callbacks noch Übergangszeichnungen registriert.

Quelltext herunterladen / Prüfstatus

powershell
.\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
c
// 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();  }
}
Gebrochene Q5.3-Bewegung aufsummieren fc_subpixel.c

Zweck: Behält Subpixelbewegungen als Rest bei und überträgt ganze Pixel auf die Position.

Funktionsweise: Ausgehend von X=40 addiert die Schleife achtmal 2/8 Pixel. Eine Rechtsverschiebung liefert die ganzen Pixel; eine Maske behält den Rest bei.

Bedienung und erwartetes Ergebnis: Die Gesamtbewegung beträgt zwei Pixel; deshalb erscheint X=42 als 042. Dieses Beispiel manueller Integration behandelt positive Bewegung; negative Bewegung benötigt einen entsprechenden Übertrag beim Subtrahieren.

Gebrochene Q5.3-Bewegung aufsummieren: Die Gesamtbewegung beträgt zwei Pixel; deshalb erscheint X=42 als 042. Dieses Beispiel manueller Integration behandelt positive Bewegung; negative Bewegung benötigt einen entsprechenden Übertrag beim Subtrahieren.
Anzeigebeispiel: Die Gesamtbewegung beträgt zwei Pixel; deshalb erscheint X=42 als 042. Dieses Beispiel manueller Integration behandelt positive Bewegung; negative Bewegung benötigt einen entsprechenden Übertrag beim Subtrahieren.

Quelltext herunterladen / Prüfstatus

powershell
.\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
c
// 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();  }
}
Den NES-Hintergrund scrollen fc_scroll.c

Zweck: Verschiebt den Hintergrund durch Aktualisieren der PPU-Scrollposition.

Funktionsweise: Nach __scroll_set(0,0) erhöht das Programm phase einmal pro Frame und verwendet den Wert als horizontale Position.

Bedienung und erwartetes Ergebnis: Das Wort SCROLL ändert seine horizontale Position. phase springt von 255 auf 0 zurück. Dies ist kein Beispiel für eine breite Karte über mehrere Nametables.

Den NES-Hintergrund scrollen: Das Wort SCROLL ändert seine horizontale Position. phase springt von 255 auf 0 zurück. Dies ist kein Beispiel für eine breite Karte über mehrere Nametables.
Anzeigebeispiel: Das Wort SCROLL ändert seine horizontale Position. phase springt von 255 auf 0 zurück. Dies ist kein Beispiel für eine breite Karte über mehrere Nametables.

Quelltext herunterladen / Prüfstatus

powershell
.\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
c
// 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); }
}
Eine Tile-Aktualisierung über NMI anwenden fc_vram_queue.c

Zweck: Reicht aus dem Hauptprogramm eine PPU-Aktualisierung ein, die anschließend im NMI-Ablauf angewendet wird.

Funktionsweise: __vramq_put reiht Tile 52 für Nametable-Adresse 0x2103 ein; __vramq_commit reicht die Aktualisierung ein. Diese Adresse entspricht Tile-Koordinate (3,8).

Bedienung und erwartetes Ergebnis: Bei Hintergrundkoordinate (3,8) erscheint eine einzelne 4. Tile 52 ist in der mitgelieferten Schrift die Ziffer 4.

Eine Tile-Aktualisierung über NMI anwenden: Bei Hintergrundkoordinate (3,8) erscheint eine einzelne 4. Tile 52 ist in der mitgelieferten Schrift die Ziffer 4.
Anzeigebeispiel: Bei Hintergrundkoordinate (3,8) erscheint eine einzelne 4. Tile 52 ist in der mitgelieferten Schrift die Ziffer 4.

Quelltext herunterladen / Prüfstatus

powershell
.\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
c
// 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();  }
}
Ein NES-OAM-Sprite anzeigen fc_sprite.c

Zweck: Bereitet Spritefarben und OAM-Daten vor, um ein Bild unabhängig vom Hintergrund zu zeichnen.

Funktionsweise: Das Programm lädt die Spritepalette, setzt Eintrag 0 auf Position (70,80), Tile 65 und Attribute 0, aktiviert die Darstellung und wiederholt den OAM-DMA.

Bedienung und erwartetes Ergebnis: Ein unbewegtes A erscheint als Sprite. Das Beispiel zeigt OAM-Einrichtung und -Übertragung, keine Animation.

Ein NES-OAM-Sprite anzeigen: Ein unbewegliches A erscheint als Sprite. Das Beispiel zeigt Einrichtung und Übertragung des OAM, keine Animation.
Anzeigebeispiel: Ein unbewegtes A erscheint als Sprite. Das Beispiel zeigt OAM-Einrichtung und -Übertragung, keine Animation.

Quelltext herunterladen / Prüfstatus

powershell
.\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
c
// 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(); }
}
Einen APU-Pulston abspielen fc_sound.c

Zweck: Stellt Steuer-, Timer- und Längenwerte des eingebauten NES-Pulskanals ein.

Funktionsweise: Nach nes_apu_init ruft das Programm nes_sfx_square1(0xBF,400,20) auf. Steuerwert 0xBF wählt konstante Lautstärke und hält den Längenzähler an, sodass der Ton anhält. 20 ist ein Index der Längentabelle, keine Dauer von 20 Frames.

Bedienung und erwartetes Ergebnis: Während 042 angezeigt wird, erklingt ein anhaltender Pulston. Beenden Sie ihn mit nes_apu_silence_all. Die Bildschirmanzeige allein bestätigt keine Tonausgabe.

Einen APU-Pulston abspielen: Während 042 angezeigt wird, erklingt ein anhaltender Pulston. Beenden Sie ihn mit nes_apu_silence_all. Die Bildschirmanzeige allein bestätigt keine Tonausgabe.
Anzeigebeispiel: Während 042 angezeigt wird, erklingt ein anhaltender Pulston. Beenden Sie ihn mit nes_apu_silence_all. Die Bildschirmanzeige allein bestätigt keine Tonausgabe.

Quelltext herunterladen / Prüfstatus

powershell
.\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
c
// 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();  }
}

API-Referenz der Bibliothek

294 Einträge. Öffnen Sie einen Eintrag, um Syntax, Argumente, Quellhinweise und ein Anwendungsbeispiel zu sehen. Aufruffragmente benötigen zusätzliche Initialisierung und sind keine eigenständigen ROMs. Die Beispiele zeigen, wie vorbereitete Werte an die API übergeben werden; sie belegen keine Prüfung am Gerät.

actor.h — Arrays für Spielakteure

NesActor bündelt Weltposition, Bildschirmposition und Rechteckgröße. Hilfsfunktionen projizieren durch die Kamera, schreiben Metasprite-OAM und prüfen Überlappungen in Weltkoordinaten. Geschwindigkeit, Aussortieren außerhalb des Bildschirms und OAM-DMA verwaltet das Spiel.

nes_actor_collide

Prüft die Überlappung achsenparalleler Akteursrechtecke in Weltkoordinaten.

Syntax

c
unsigned char nes_actor_collide(struct NesActor* a, struct NesActor* b);

Parameter

a

Erster Akteur.

b

Zweiter Akteur.

Rückgabewert

Gibt bei Überlappung 1 zurück, bei Trennung oder bloßer Kantenberührung 0.

Bedingungen und Grenzen

Verwenden Sie positive Breiten und Höhen und halten Sie Position+Größe≤65535. Bildschirmkoordinaten, attr und flags werden ignoriert.

Anwendungsbeispiel

c
result[3]=nes_actor_collide(&a,&b);nes_actor_set_world(&b,315,95);result[4]=nes_actor_collide(&a,&b);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Projizieren Sie Weltposition (300,95) durch Kamera (268,32): Rote und blaue 8×8-Teile erscheinen bei (32,64) und (40,64). Dies zeigt den rohen OAM-Y-Wert 63 als sichtbares Y=64 sowie den Wechsel des Kollisionsergebnisses von null bei Kantenberührung zu eins bei einem Pixel Überlappung.

nes_actor_collide: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/actor.h:29

Deklarationshinweise im Original
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

c
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

Schreibt mit den zwischengespeicherten Bildschirmkoordinaten des Akteurs ein Metasprite in das Schatten-OAM.

Syntax

c
unsigned char nes_actor_draw_metasprite(struct NesActor* actor, unsigned char oam_index, unsigned char* metasprite);

Parameter

actor

Zeiger auf einen beschreibbaren NesActor.

oam_index

Erster Slot, 0..63; reservieren Sie Platz für alle Teile.

metasprite

Vier-Byte-Datensätze dx,dy,tile,attr; dx=255 beendet die Liste.

Rückgabewert

Gibt den nächsten OAM-Slotindex zurück, mit Umlauf am Ende der 64 Slots.

Bedingungen und Grenzen

Binden Sie runtime.c ein. Die Warteschlange kopiert Nutzdaten für eine spätere NMI oder eine sichere Übertragung bei ausgeschalteter Darstellung. Serialisieren Sie Erzeugung und Verbrauch. Geht bei mehreren Zeilen die Kapazität aus, bleiben zuvor aufgenommene Zeilen eingereiht.

Wendet die attr/flags-Felder des Akteurs nicht an. Y ist ein rohes OAM-Byte, daher liegt die sichtbare Oberkante ein Pixel tiefer. Zum Anzeigen des Schattenpuffers ist ein OAM-DMA erforderlich.

Anwendungsbeispiel

c
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);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Projizieren Sie Weltposition (300,95) durch Kamera (268,32): Rote und blaue 8×8-Teile erscheinen bei (32,64) und (40,64). Dies zeigt den rohen OAM-Y-Wert 63 als sichtbares Y=64 sowie den Wechsel des Kollisionsergebnisses von null bei Kantenberührung zu eins bei einem Pixel Überlappung.

nes_actor_draw_metasprite: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/actor.h:25

Deklarationshinweise im Original
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

c
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

Setzt Welt-X/Y eines Akteurs.

Syntax

c
void nes_actor_set_world(struct NesActor* actor, unsigned short x, unsigned short y);

Parameter

actor

Zeiger auf einen beschreibbaren NesActor.

x

Welt-X, 0..65535 Pixel.

y

Welt-Y, 0..65535 Pixel.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Aktualisiert screen_x/screen_y nicht. Rufen Sie update_screen zur Projektion durch die Kamera auf.

Anwendungsbeispiel

c
nes_actor_set_world(&a,300,95);nes_actor_set_world(&b,316,95);result[0]=a.world_x;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Projizieren Sie Weltposition (300,95) durch Kamera (268,32): Rote und blaue 8×8-Teile erscheinen bei (32,64) und (40,64). Dies zeigt den rohen OAM-Y-Wert 63 als sichtbares Y=64 sowie den Wechsel des Kollisionsergebnisses von null bei Kantenberührung zu eins bei einem Pixel Überlappung.

nes_actor_set_world: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/actor.h:19

Deklarationshinweise im Original
Set the actor's 16-bit world position without updating cached screen coordinates.

kitaqfc/lib/actor.c:19

c
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

Zieht Kamerakoordinaten von Weltkoordinaten ab und speichert die unteren Bytes als Bildschirmkoordinaten zwischen.

Syntax

c
void nes_actor_update_screen(struct NesActor* actor, unsigned short camera_x, unsigned short camera_y);

Parameter

actor

Zeiger auf einen beschreibbaren NesActor.

camera_x

Welt-X der Kamera.

camera_y

Welt-Y der Kamera.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Negative Ergebnisse oder Werte ≥256 laufen um. Akteure außerhalb des Bildschirms werden nicht ausgeblendet; das Spiel muss sie vor dem Zeichnen aussortieren.

Anwendungsbeispiel

c
nes_actor_update_screen(&a,268,32);result[1]=a.screen_x;result[2]=a.screen_y;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Projizieren Sie Weltposition (300,95) durch Kamera (268,32): Rote und blaue 8×8-Teile erscheinen bei (32,64) und (40,64). Dies zeigt den rohen OAM-Y-Wert 63 als sichtbares Y=64 sowie den Wechsel des Kollisionsergebnisses von null bei Kantenberührung zu eins bei einem Pixel Überlappung.

nes_actor_update_screen: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/actor.h:22

Deklarationshinweise im Original
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

c
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 — Ressourcen-IDs und Datenbeschreibungen

Die Ressourcenbibliothek findet Daten in ROM-Bänken über eine 8-Bit-ID. Binden Sie asset.c ein; auf dem FC zusätzlich bank.c. Ein gepackter AssetDesc belegt 6 Byte: Typ, Banknummer der Nutzdaten, 16-Bit-Adresse und Länge in Byte. Deskriptortabelle und Nutzdaten dürfen in verschiedenen ROM-Bänken liegen.

Registrieren Sie die Tabelle vor der ersten Suche. Die Registrierung ist ein gemeinsamer globaler Zustand und darf nicht gleichzeitig mit einer Suche geändert werden. Geprüft werden IDs und der Ausgabezeiger von asset_get, nicht jedoch Tabelle, Nutzdatenadressen oder Cartridge-Inhalt.

Sucht eine RAW- oder TILES-Ressource, wählt deren ROM-Bank und überträgt sämtliche Daten mit __vram_write in Blöcken von höchstens 128 Byte. Anschließend wird die von bank_get_current() gespeicherte Bank wiederhergestellt. Zwischen den Blöcken wird nicht auf das nächste Bild gewartet.

Verwenden Sie beschreibbaren CHR RAM für Muster und schalten Sie die Darstellung bei langen Transfers ab. Innerhalb von VBlank muss der gesamte Vorgang in die verfügbare Zeit passen; 128-Byte-Blöcke gewährleisten das nicht. Das Beispiel nutzt --mapper=mmc1 --board=surom512. Bei generischen Boards erzeugt das Weglassen von --nes-chr leeren CHR ROM, keinen CHR RAM.

asset_get

Kopiert einen AssetDesc aus der ROM-Bank der registrierten Tabelle in den bereitgestellten Speicher. Damit werden die Metadaten der Ressource gelesen, nicht ihre Nutzdaten.

Syntax

c
u8 asset_get(u8 asset_id, AssetDesc* out_desc);

Parameter

asset_id

Ressourcenindex ab null. In der registrierten Tabelle gilt für eine gültige ID asset_id < count.

out_desc

Beschreibbarer Speicher für einen 6-Byte-Deskriptor. Ein Nullzeiger wird vor dem Tabellenzugriff zurückgewiesen.

Rückgabewert

1 nach dem Kopieren des Deskriptors; 0 bei Nullzeiger oder ungültiger ID. Bei diesen Fehlern bleibt der Zielspeicher unverändert.

Bedingungen und Grenzen

Registrieren Sie die Tabelle vor der ersten Suche. Die Registrierung ist ein gemeinsamer globaler Zustand und darf nicht gleichzeitig mit einer Suche geändert werden. Geprüft werden IDs und der Ausgabezeiger von asset_get, nicht jedoch Tabelle, Nutzdatenadressen oder Cartridge-Inhalt.

Die Beispiele legen den aufrufenden Code in die feste Bank 0, damit ein Wechsel der Quellbank den laufenden Code nicht ausblendet. Die Übertragungen sind synchron. Unterbrechen Sie sie nicht durch eine weitere bankwechselnde Kopie. Die Hilfsfunktion allein macht nicht die gesamte Anwendung interruptsicher.

Anwendungsbeispiel

c
loaded=asset_get(0,&descriptor);
expect(loaded==1,1);
expect(descriptor.type==ASSET_TYPE_TILES && descriptor.bank==2,2);
expect(descriptor.ptr==asset_shapes && descriptor.len==144,3);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel liest Deskriptor 0 und prüft Typ TILES, Bank 2, Zeiger und Länge 144 Byte. Ungültige IDs und Nullzeiger müssen scheitern; bei einer fehlgeschlagenen Suche bleibt der vorherige Ausgabewert erhalten.

Erwartetes Bild: Eine rote Reihe beginnt bei (16,32) und belegt 72×8 Pixel. Dreimal folgen ein 8×8-Dreieck, ein 8×8-Quadrat mit einem Pixel Rand und eine Kachel mit vier gefüllten linken Spalten. Das Dreieck wächst von einem Pixel oben links auf acht Pixel in der untersten Zeile.

Auf dem FC zeigt das blaue Paar bei (16,64) __far_memcpy, das grüne bei (16,96) asset_load_raw mit anschließender CHR-Übertragung. Jedes Paar belegt 16×8 Pixel auf schwarzem Hintergrund. So werden die kopierten Bilddaten sichtbar, nicht nur numerische Statuswerte.

Erwartet werden FAILED CHECKS 000 und FIRST FAILURE 00. Die Prüfung führt 300 Bilder aus und vergleicht Text, Formmasken und Farben mit den Sollwerten. Dies ist ein Emulatornachweis, kein Test auf physischer Hardware.

asset_get: SUROM512
SUROM512

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/asset.h:25

Deklarationshinweise im Original
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

c
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

Liest die Banknummer der Nutzdaten aus dem Deskriptor. Dies ist nicht die Banknummer der Tabelle. Nach dem Aufruf bleibt diese ROM-Bank auch nicht ausgewählt.

Syntax

c
u8 asset_get_bank(u8 asset_id);

Parameter

asset_id

Ressourcenindex ab null. In der registrierten Tabelle gilt für eine gültige ID asset_id < count.

Rückgabewert

Das 8-Bit-Feld bank oder 0, wenn die Suche scheitert. Bank null kann ebenfalls gültig sein. Nutzen Sie asset_get(), um den Erfolg unabhängig vom Wert zu erkennen.

Bedingungen und Grenzen

Registrieren Sie die Tabelle vor der ersten Suche. Die Registrierung ist ein gemeinsamer globaler Zustand und darf nicht gleichzeitig mit einer Suche geändert werden. Geprüft werden IDs und der Ausgabezeiger von asset_get, nicht jedoch Tabelle, Nutzdatenadressen oder Cartridge-Inhalt.

Jede Abfrage ruft erneut asset_get auf und kopiert einen Deskriptor. Wenn Bank, Zeiger und Länge gemeinsam benötigt werden, genügt ein Aufruf von asset_get mit anschließendem Lesen der Felder.

Die Beispiele legen den aufrufenden Code in die feste Bank 0, damit ein Wechsel der Quellbank den laufenden Code nicht ausblendet. Die Übertragungen sind synchron. Unterbrechen Sie sie nicht durch eine weitere bankwechselnde Kopie. Die Hilfsfunktion allein macht nicht die gesamte Anwendung interruptsicher.

Anwendungsbeispiel

c
payload_bank=asset_get_bank(0);
expect(payload_bank==2,17); // Payload bank, not descriptor-table bank 3.
expect(asset_get_bank(4)==0,18); // Failure sentinel; a valid descriptor may also use bank 0.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Erwartet wird ROM-Bank 2 der Nutzdaten, obwohl die Tabelle in Bank 3 liegt. Zusätzlich muss eine ungültige ID null zurückgeben.

Erwartetes Bild: Eine rote Reihe beginnt bei (16,32) und belegt 72×8 Pixel. Dreimal folgen ein 8×8-Dreieck, ein 8×8-Quadrat mit einem Pixel Rand und eine Kachel mit vier gefüllten linken Spalten. Das Dreieck wächst von einem Pixel oben links auf acht Pixel in der untersten Zeile.

Auf dem FC zeigt das blaue Paar bei (16,64) __far_memcpy, das grüne bei (16,96) asset_load_raw mit anschließender CHR-Übertragung. Jedes Paar belegt 16×8 Pixel auf schwarzem Hintergrund. So werden die kopierten Bilddaten sichtbar, nicht nur numerische Statuswerte.

Erwartet werden FAILED CHECKS 000 und FIRST FAILURE 00. Die Prüfung führt 300 Bilder aus und vergleicht Text, Formmasken und Farben mit den Sollwerten. Dies ist ein Emulatornachweis, kein Test auf physischer Hardware.

asset_get_bank: SUROM512
SUROM512

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/asset.h:33

Deklarationshinweise im Original
Return the asset bank or zero on lookup failure; bank zero may also be valid.

kitaqfc/lib/asset.c:74

c
u8 asset_get_bank(u8 asset_id)
{
    AssetDesc desc;
    if (asset_get(asset_id, &desc) == 0) return 0;
    return desc.bank;
}
asset_get_len

Liest die Länge der Ressource in Byte aus dem Deskriptor. Der Wert ist eine Metadatenangabe. Die Funktion untersucht keine Nutzdaten und rechnet die Länge nicht in Kacheln, Elemente oder Bilder um.

Syntax

c
u16 asset_get_len(u8 asset_id);

Parameter

asset_id

Ressourcenindex ab null. In der registrierten Tabelle gilt für eine gültige ID asset_id < count.

Rückgabewert

Das 16-Bit-Feld len in Byte oder 0 bei erfolgloser Suche. Auch eine leere Ressource hat Länge null. Unterscheiden Sie diese Fälle mit asset_get().

Bedingungen und Grenzen

Registrieren Sie die Tabelle vor der ersten Suche. Die Registrierung ist ein gemeinsamer globaler Zustand und darf nicht gleichzeitig mit einer Suche geändert werden. Geprüft werden IDs und der Ausgabezeiger von asset_get, nicht jedoch Tabelle, Nutzdatenadressen oder Cartridge-Inhalt.

Jede Abfrage ruft erneut asset_get auf und kopiert einen Deskriptor. Wenn Bank, Zeiger und Länge gemeinsam benötigt werden, genügt ein Aufruf von asset_get mit anschließendem Lesen der Felder.

Die Beispiele legen den aufrufenden Code in die feste Bank 0, damit ein Wechsel der Quellbank den laufenden Code nicht ausblendet. Die Übertragungen sind synchron. Unterbrechen Sie sie nicht durch eine weitere bankwechselnde Kopie. Die Hilfsfunktion allein macht nicht die gesamte Anwendung interruptsicher.

Anwendungsbeispiel

c
expect(asset_get_len(0)==144,21); // Bytes, not tiles.
expect(asset_get_len(3)==0 && asset_get_len(4)==0,22); // Empty asset and invalid ID both yield zero.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Die Ressource mit neun Kacheln muss 144 Byte melden, nicht neun Kacheln. Eine leere Ressource und eine ungültige ID müssen beide null liefern.

Erwartetes Bild: Eine rote Reihe beginnt bei (16,32) und belegt 72×8 Pixel. Dreimal folgen ein 8×8-Dreieck, ein 8×8-Quadrat mit einem Pixel Rand und eine Kachel mit vier gefüllten linken Spalten. Das Dreieck wächst von einem Pixel oben links auf acht Pixel in der untersten Zeile.

Auf dem FC zeigt das blaue Paar bei (16,64) __far_memcpy, das grüne bei (16,96) asset_load_raw mit anschließender CHR-Übertragung. Jedes Paar belegt 16×8 Pixel auf schwarzem Hintergrund. So werden die kopierten Bilddaten sichtbar, nicht nur numerische Statuswerte.

Erwartet werden FAILED CHECKS 000 und FIRST FAILURE 00. Die Prüfung führt 300 Bilder aus und vergleicht Text, Formmasken und Farben mit den Sollwerten. Dies ist ein Emulatornachweis, kein Test auf physischer Hardware.

asset_get_len: SUROM512
SUROM512

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/asset.h:38

Deklarationshinweise im Original
Return the descriptor byte length, or zero for an invalid ID.

kitaqfc/lib/asset.c:91

c
u16 asset_get_len(u8 asset_id)
{
    AssetDesc desc;
    if (asset_get(asset_id, &desc) == 0) return 0;
    return desc.len;
}
asset_get_ptr

Liest die im Deskriptor gespeicherte 16-Bit-Adresse der Nutzdaten. Der zurückgegebene Nahzeiger enthält keine Banknummer. Verwenden Sie ihn zusammen mit asset_get_bank() und einer bankübergreifenden Kopierfunktion, um Daten aus einer anderen ROM-Bank zu lesen.

Syntax

c
const u8* asset_get_ptr(u8 asset_id);

Parameter

asset_id

Ressourcenindex ab null. In der registrierten Tabelle gilt für eine gültige ID asset_id < count.

Rückgabewert

Der gespeicherte const u8* oder ein Nullzeiger bei erfolgloser Suche. Der Nutzdatenzeiger im Deskriptor wird nicht auf null geprüft. Mit asset_get() lässt sich ein Suchfehler eindeutig erkennen.

Bedingungen und Grenzen

Registrieren Sie die Tabelle vor der ersten Suche. Die Registrierung ist ein gemeinsamer globaler Zustand und darf nicht gleichzeitig mit einer Suche geändert werden. Geprüft werden IDs und der Ausgabezeiger von asset_get, nicht jedoch Tabelle, Nutzdatenadressen oder Cartridge-Inhalt.

Jede Abfrage ruft erneut asset_get auf und kopiert einen Deskriptor. Wenn Bank, Zeiger und Länge gemeinsam benötigt werden, genügt ein Aufruf von asset_get mit anschließendem Lesen der Felder.

Die Beispiele legen den aufrufenden Code in die feste Bank 0, damit ein Wechsel der Quellbank den laufenden Code nicht ausblendet. Die Übertragungen sind synchron. Unterbrechen Sie sie nicht durch eine weitere bankwechselnde Kopie. Die Hilfsfunktion allein macht nicht die gesamte Anwendung interruptsicher.

Anwendungsbeispiel

c
payload_pointer=asset_get_ptr(0);
expect(payload_pointer==asset_shapes,19);
expect(*asset_bank_marker==0xA1,20); // Getting the pointer leaves bank 1 selected.
// Use payload_bank together with payload_pointer for a far copy; do not dereference it here.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Der Zeiger muss der nach dem Linken feststehenden ROM-Adresse entsprechen, während ein Marker in Bank 1 weiterhin lesbar ist. Danach werden Zeiger und ROM-Bank 2 an die bankübergreifende Kopie übergeben.

Erwartetes Bild: Eine rote Reihe beginnt bei (16,32) und belegt 72×8 Pixel. Dreimal folgen ein 8×8-Dreieck, ein 8×8-Quadrat mit einem Pixel Rand und eine Kachel mit vier gefüllten linken Spalten. Das Dreieck wächst von einem Pixel oben links auf acht Pixel in der untersten Zeile.

Auf dem FC zeigt das blaue Paar bei (16,64) __far_memcpy, das grüne bei (16,96) asset_load_raw mit anschließender CHR-Übertragung. Jedes Paar belegt 16×8 Pixel auf schwarzem Hintergrund. So werden die kopierten Bilddaten sichtbar, nicht nur numerische Statuswerte.

Erwartet werden FAILED CHECKS 000 und FIRST FAILURE 00. Die Prüfung führt 300 Bilder aus und vergleicht Text, Formmasken und Farben mit den Sollwerten. Dies ist ein Emulatornachweis, kein Test auf physischer Hardware.

asset_get_ptr: SUROM512
SUROM512

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/asset.h:36

Deklarationshinweise im Original
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

c
const u8* asset_get_ptr(u8 asset_id)
{
    AssetDesc desc;
    if (asset_get(asset_id, &desc) == 0) return 0;
    return desc.ptr;
}
asset_load_raw

Sucht die Ressource und kopiert min(desc.len, max_len) Byte aus ihrer ROM-Bank in beschreibbaren Speicher. Der Typ wird nicht geprüft: Grafik-, Karten- und Musikdaten werden unverändert kopiert, ohne Dekodierung oder Dekomprimierung.

Syntax

c
u8 asset_load_raw(u8 asset_id, void* dst, u16 max_len);

Parameter

asset_id

Ressourcenindex ab null. In der registrierten Tabelle gilt für eine gültige ID asset_id < count.

dst

Ziel in beschreibbarem Speicher mit genügend Platz für alle kopierten Byte. Abgesehen von einem Transfer mit Länge null erfolgt keine Prüfung auf Nullzeiger oder ungültige Zieladressen.

max_len

Höchstens zu kopierende Byte, 0–65535. Eine kleinere Grenze kürzt die Kopie; bei null werden keine Nutzdaten kopiert.

Rückgabewert

0, wenn die Suche scheitert, sonst 1 – auch bei gekürzter Kopie, Grenze null oder leerer Ressource. Der Rückgabewert ist keine Byteanzahl und bestätigt nicht, dass die gesamte Ressource in den Puffer passte.

Bedingungen und Grenzen

Registrieren Sie die Tabelle vor der ersten Suche. Die Registrierung ist ein gemeinsamer globaler Zustand und darf nicht gleichzeitig mit einer Suche geändert werden. Geprüft werden IDs und der Ausgabezeiger von asset_get, nicht jedoch Tabelle, Nutzdatenadressen oder Cartridge-Inhalt.

Der gesamte Quellbereich muss in der vorgesehenen ROM-Zuordnung lesbar und der gesamte Zielbereich beschreibbar sein. Die Kopie schaltet am Fensterende nicht automatisch zur nächsten Bank, behandelt Überlappungen nicht wie memmove und steuert keine sicheren VRAM-Schreibzeitpunkte. Verwenden Sie für VRAM die Grafikübertragungs-APIs.

Die Beispiele legen den aufrufenden Code in die feste Bank 0, damit ein Wechsel der Quellbank den laufenden Code nicht ausblendet. Die Übertragungen sind synchron. Unterbrechen Sie sie nicht durch eine weitere bankwechselnde Kopie. Die Hilfsfunktion allein macht nicht die gesamte Anwendung interruptsicher.

Anwendungsbeispiel

c
loaded=asset_load_raw(0,buffer,7); // Success with truncation: copy seven of 144 bytes.
expect(loaded==1 && buffer[7]==0x55,7);
for(i=0;i<7;i++) expect(buffer[(__safe_index u8)i]==expected_shape_byte(i),8);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Eine Grenze von sieben kopiert nur sieben Byte einer 144-Byte-Ressource und lässt das nächste Byte auf 0x55, meldet aber Erfolg. Außerdem werden vollständige Kopie, Grenze null, leere Ressource und das Kopieren von MAP-Daten geprüft.

Erwartetes Bild: Eine rote Reihe beginnt bei (16,32) und belegt 72×8 Pixel. Dreimal folgen ein 8×8-Dreieck, ein 8×8-Quadrat mit einem Pixel Rand und eine Kachel mit vier gefüllten linken Spalten. Das Dreieck wächst von einem Pixel oben links auf acht Pixel in der untersten Zeile.

Auf dem FC zeigt das blaue Paar bei (16,64) __far_memcpy, das grüne bei (16,96) asset_load_raw mit anschließender CHR-Übertragung. Jedes Paar belegt 16×8 Pixel auf schwarzem Hintergrund. So werden die kopierten Bilddaten sichtbar, nicht nur numerische Statuswerte.

Erwartet werden FAILED CHECKS 000 und FIRST FAILURE 00. Die Prüfung führt 300 Bilder aus und vergleicht Text, Formmasken und Farben mit den Sollwerten. Dies ist ein Emulatornachweis, kein Test auf physischer Hardware.

asset_load_raw: SUROM512
SUROM512

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/asset.h:28

Deklarationshinweise im Original
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

c
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

Sucht eine RAW- oder TILES-Ressource, wählt deren ROM-Bank und überträgt sämtliche Daten mit __vram_write in Blöcken von höchstens 128 Byte. Anschließend wird die von bank_get_current() gespeicherte Bank wiederhergestellt. Zwischen den Blöcken wird nicht auf das nächste Bild gewartet.

Syntax

c
u8 asset_load_tiles(u8 asset_id, u16 vram_dst);

Parameter

asset_id

Ressourcenindex ab null. In der registrierten Tabelle gilt für eine gültige ID asset_id < count.

vram_dst

Byteadresse des PPU, keine CPU-Adresse oder Kachelnummer. Kachelmuster werden in beschreibbaren CHR RAM bei $0000–$1FFF geladen, mit 16 Byte je Kachel. Der gesamte Transfer muss im vorgesehenen PPU-Bereich bleiben.

Rückgabewert

0 bei ungültiger ID oder einem anderen Typ als RAW/TILES; 1 nach einem akzeptierten Transfer, auch bei Länge null. Erfolg bestätigt weder das Kachelformat noch die korrekte Darstellung im VRAM.

Bedingungen und Grenzen

Registrieren Sie die Tabelle vor der ersten Suche. Die Registrierung ist ein gemeinsamer globaler Zustand und darf nicht gleichzeitig mit einer Suche geändert werden. Geprüft werden IDs und der Ausgabezeiger von asset_get, nicht jedoch Tabelle, Nutzdatenadressen oder Cartridge-Inhalt.

Die Beispiele legen den aufrufenden Code in die feste Bank 0, damit ein Wechsel der Quellbank den laufenden Code nicht ausblendet. Die Übertragungen sind synchron. Unterbrechen Sie sie nicht durch eine weitere bankwechselnde Kopie. Die Hilfsfunktion allein macht nicht die gesamte Anwendung interruptsicher.

Der Transfer schreibt nur Bytes. Er platziert keine Kacheln auf der Karte, weist keine Farben zu und reserviert keinen VRAM. Kachelkarte und Paletten werden separat eingerichtet. Die Beispiele übertragen bei abgeschalteter Darstellung und schalten sie erst nach dem Bildaufbau ein.

asset_load_tiles stellt die von bank.c vermerkte Bank wieder her, keinen vom Mapper zurückgelesenen Wert. Initialisieren und pflegen Sie diesen Zustand mit bank_switch. Direkte Mapper-Zugriffe oder alleinige Aufrufe von __bankswitch aktualisieren den Bibliothekszustand nicht. Die Kopier-Intrinsic stellt separat den Compilerzustand wieder her.

Verwenden Sie beschreibbaren CHR RAM für Muster und schalten Sie die Darstellung bei langen Transfers ab. Innerhalb von VBlank muss der gesamte Vorgang in die verfügbare Zeit passen; 128-Byte-Blöcke gewährleisten das nicht. Das Beispiel nutzt --mapper=mmc1 --board=surom512. Bei generischen Boards erzeugt das Weglassen von --nes-chr leeren CHR ROM, keinen CHR RAM.

Anwendungsbeispiel

c
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.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel lädt neun eigene Muster mit je 8×8 Pixeln, insgesamt 144 Byte, und prüft die Ablehnung von MAP und ungültigen IDs. Auf dem FC werden damit sowohl der 128-Byte-Block als auch die verbleibenden 16 Byte geprüft.

Erwartetes Bild: Eine rote Reihe beginnt bei (16,32) und belegt 72×8 Pixel. Dreimal folgen ein 8×8-Dreieck, ein 8×8-Quadrat mit einem Pixel Rand und eine Kachel mit vier gefüllten linken Spalten. Das Dreieck wächst von einem Pixel oben links auf acht Pixel in der untersten Zeile.

Auf dem FC zeigt das blaue Paar bei (16,64) __far_memcpy, das grüne bei (16,96) asset_load_raw mit anschließender CHR-Übertragung. Jedes Paar belegt 16×8 Pixel auf schwarzem Hintergrund. So werden die kopierten Bilddaten sichtbar, nicht nur numerische Statuswerte.

Erwartet werden FAILED CHECKS 000 und FIRST FAILURE 00. Die Prüfung führt 300 Bilder aus und vergleicht Text, Formmasken und Farben mit den Sollwerten. Dies ist ein Emulatornachweis, kein Test auf physischer Hardware.

asset_load_tiles: SUROM512
SUROM512

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/asset.h:31

Deklarationshinweise im Original
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

c
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

Registriert Banknummer, Adresse und Eintragszahl der einzigen aktiven Deskriptortabelle. Die Funktion speichert nur diese drei Werte. Sie kopiert weder die Tabelle noch Nutzdaten und reserviert keinen Speicher.

Syntax

c
void asset_set_table(u8 bank, const AssetDesc* table, u8 count);

Parameter

bank

8-Bit-Nummer der ROM-Bank mit der Deskriptortabelle, nicht mit den Nutzdaten.

table

Nahzeiger auf count aufeinanderfolgende AssetDesc-Einträge. Solange die Tabelle registriert ist, müssen alle count * 6 Byte in ihrer ROM-Bank lesbar bleiben.

count

Anzahl der Einträge, 0–255. Bei null ist keine ID gültig. Mit asset_set_table(0, 0, 0) lässt sich sicher eine leere Tabelle registrieren.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Registrieren Sie die Tabelle vor der ersten Suche. Die Registrierung ist ein gemeinsamer globaler Zustand und darf nicht gleichzeitig mit einer Suche geändert werden. Geprüft werden IDs und der Ausgabezeiger von asset_get, nicht jedoch Tabelle, Nutzdatenadressen oder Cartridge-Inhalt.

Anwendungsbeispiel

c
asset_set_table(3,asset_descriptors,4); // Four descriptors in bank 3, payloads in bank 2.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel registriert vier Deskriptoren in Bank 3; ihre nicht leeren Nutzdaten liegen in Bank 2. Zusätzlich wird geprüft, dass die Suche in einer leeren Tabelle ohne Lesen von Adresse null scheitert.

Erwartetes Bild: Eine rote Reihe beginnt bei (16,32) und belegt 72×8 Pixel. Dreimal folgen ein 8×8-Dreieck, ein 8×8-Quadrat mit einem Pixel Rand und eine Kachel mit vier gefüllten linken Spalten. Das Dreieck wächst von einem Pixel oben links auf acht Pixel in der untersten Zeile.

Auf dem FC zeigt das blaue Paar bei (16,64) __far_memcpy, das grüne bei (16,96) asset_load_raw mit anschließender CHR-Übertragung. Jedes Paar belegt 16×8 Pixel auf schwarzem Hintergrund. So werden die kopierten Bilddaten sichtbar, nicht nur numerische Statuswerte.

Erwartet werden FAILED CHECKS 000 und FIRST FAILURE 00. Die Prüfung führt 300 Bilder aus und vergleicht Text, Formmasken und Farben mit den Sollwerten. Dies ist ein Emulatornachweis, kein Test auf physischer Hardware.

asset_set_table: SUROM512
SUROM512

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/asset.h:22

Deklarationshinweise im Original
Retain a bank-qualified descriptor table; the caller keeps its storage valid.

kitaqfc/lib/asset.c:9

c
void asset_set_table(u8 bank, const AssetDesc* table, u8 count)
{
    asset_table_bank = bank;
    asset_table = table;
    asset_table_count = count;
}

attribute.h — Nametable-Attribute

Der gemeinsame 64-Byte-Attributschattenpuffer belegt CPU-RAM $03E0..$041F. Reservieren Sie diesen Bereich. Ein Attributbyte deckt 4×4 Kacheln ab; jedes Zwei-Bit-Feld wählt die Palette für einen 2×2-Kachelquadranten.

Bearbeitet Palettenquadranten rechteckweise und reiht nur betroffene Attributbytes ein, mit Prüfung der 32×30-Kachelgrenzen. Die Eingabe palette_map ist eine fertige 64-Byte-Attributtabelle, kein einzelner Farbwert pro Kachel.

nes_attr_queue_rect

Kopiert die ein Kachelrechteck abdeckenden Attributbytezeilen in die Warteschlange.

Syntax

c
unsigned char nes_attr_queue_rect(unsigned short nt_base, unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height);

Parameter

nt_base

Logische Nametable-Basis $2000/$2400/$2800/$2C00; die Spiegelung bestimmt die physische Unabhängigkeit.

tile_x

Linke Kachelspalte, sichtbarer Bereich 0..31.

tile_y

Obere Kachelzeile, sichtbarer Bereich 0..29.

width

Breite in Kacheln.

height

Höhe in Kacheln.

Rückgabewert

Gibt bei vollständiger Aufnahme oder leerem Rechteck 1 zurück, bei ungültigen Grenzen oder unzureichender Kapazität 0. Ungültige Grenzen reihen nichts ein.

Bedingungen und Grenzen

Der gemeinsame 64-Byte-Attributschattenpuffer belegt CPU-RAM $03E0..$041F. Reservieren Sie diesen Bereich. Ein Attributbyte deckt 4×4 Kacheln ab; jedes Zwei-Bit-Feld wählt die Palette für einen 2×2-Kachelquadranten.

Binden Sie runtime.c ein. Die Warteschlange kopiert Nutzdaten für eine spätere NMI oder eine sichere Übertragung bei ausgeschalteter Darstellung. Serialisieren Sie Erzeugung und Verbrauch. Geht bei mehreren Zeilen die Kapazität aus, bleiben zuvor aufgenommene Zeilen eingereiht.

Ein Attributbyte deckt 4×4 Kacheln ab. Betroffene Bytes werden vollständig übertragen; erhalten Sie daher im Schattenpuffer die richtigen Werte benachbarter Quadranten.

Anwendungsbeispiel

c
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();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Lernen Sie rechteckige Attributübertragungen: Rot 32×32 bei (16,32), Blau 32×32 bei (80,32), Grün 16×16 rechts unten bei (240,224). Das Beispiel erhält benachbarte Quadranten und erreicht korrekt das letzte Attributbyte.

nes_attr_queue_rect: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/attribute.h:15

Deklarationshinweise im Original
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

c
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

Kopiert 64 bereits gepackte Attributbytes in den gemeinsamen Schattenpuffer.

Syntax

c
void nes_attr_shadow_build_from_palette_map(unsigned char* src64);

Parameter

src64

Lesbare, gepackte 64-Byte-Attributtabelle, kein Array einzelner Paletten-IDs je Kachel.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Der gemeinsame 64-Byte-Attributschattenpuffer belegt CPU-RAM $03E0..$041F. Reservieren Sie diesen Bereich. Ein Attributbyte deckt 4×4 Kacheln ab; jedes Zwei-Bit-Feld wählt die Palette für einen 2×2-Kachelquadranten.

Anwendungsbeispiel

c
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];

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Lernen Sie rechteckige Attributübertragungen: Rot 32×32 bei (16,32), Blau 32×32 bei (80,32), Grün 16×16 rechts unten bei (240,224). Das Beispiel erhält benachbarte Quadranten und erreicht korrekt das letzte Attributbyte.

nes_attr_shadow_build_from_palette_map: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/attribute.h:8

Deklarationshinweise im Original
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

c
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

Ersetzt die Palettenfelder aller 2×2-Kachelquadranten, die ein Rechteck berührt.

Syntax

c
void nes_attr_shadow_fill_rect(unsigned char tile_x, unsigned char tile_y, unsigned char width, unsigned char height, unsigned char pal_index);

Parameter

tile_x

Linke Kachelspalte, sichtbarer Bereich 0..31.

tile_y

Obere Kachelzeile, sichtbarer Bereich 0..29.

width

Breite in Kacheln.

height

Höhe in Kacheln.

pal_index

Palettenindex; nur die unteren zwei Bits werden verwendet.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Der gemeinsame 64-Byte-Attributschattenpuffer belegt CPU-RAM $03E0..$041F. Reservieren Sie diesen Bereich. Ein Attributbyte deckt 4×4 Kacheln ab; jedes Zwei-Bit-Feld wählt die Palette für einen 2×2-Kachelquadranten.

Halten Sie das gesamte Rechteck innerhalb von 32×30 Kacheln. Leere oder ungültige Rechtecke ändern nichts. Ungerade Grenzen werden auf Quadrantengrenzen erweitert, sodass benachbarte Kacheln außerhalb ebenfalls die neue Palette erhalten können.

Anwendungsbeispiel

c
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];

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Lernen Sie rechteckige Attributübertragungen: Rot 32×32 bei (16,32), Blau 32×32 bei (80,32), Grün 16×16 rechts unten bei (240,224). Das Beispiel erhält benachbarte Quadranten und erreicht korrekt das letzte Attributbyte.

nes_attr_shadow_fill_rect: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/attribute.h:11

Deklarationshinweise im Original
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

c
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 — Musik, Soundeffekte und Audiosteuerung

Direktsteuerung der zwei Pulse, des Dreiecks, Rauschens und DMC der Standard-APU. Kein Musiksequenzer oder automatischer Mischer; Timing und Stimmenbelegung verwaltet das Spiel.

Diese Hilfe schreibt eine Einkanal-APU_STATUS-Maske und deaktiviert andere Stimmen; sie ist kein Mehrstimmenmischer. Bei Puls und Dreieck ist period ein Timerwert: Kleinere Werte erzeugen höhere Töne. Beispieltonhöhen und -dauern wurden mit NTSC-Timing geprüft.

DMC liest ROM ab einer 64-Byte-Grenze in $C000..$FFC0. Die Länge beträgt 16*n+1 Bytes in 1..4081. Diese Hilfen prüfen weder Ausrichtung noch Bereiche und wechseln keine Banken. Das Beispiel legt eigene Daten mit __aligned(64) in der festen Bank 0 ab und prüft deren Lage zur Laufzeit.

nes_apu_channel_enable

Ersetzt den Aktivierungszustand aller fünf APU-Kanäle durch die angegebene Maske.

Syntax

c
void nes_apu_channel_enable(u8 mask);

Parameter

mask

Vollständige APU_STATUS-Aktivierungsmaske. Bits 0..4 wählen pulse1, pulse2, triangle, noise und DMC; obere Bits werden verworfen.

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Zu hören sind pulse1, pulse2, triangle, noise, tick und move. Timer 253 ergibt unter NTSC etwa 440-Hz-Pulse und ein 220-Hz-Dreieck. Tick liegt bei etwa 111 Hz, move bei etwa 174 Hz und endet früher. Der letzte Abschnitt ist still.

nes_apu_channel_enable: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio.h:17

Deklarationshinweise im Original
Replace all five channel-enable bits in APU_STATUS; this is not an additive enable.

kitaqfc/lib/audio.c:43

c
void nes_apu_channel_enable(u8 mask)
{
    APU_STATUS = (u8)(mask & 0x1F);
}
nes_apu_init

Deaktiviert Frame-IRQ, aktiviert vier Stimmen und setzt stille Steuerwerte. DMC bleibt deaktiviert.

Syntax

c
void nes_apu_init(void);

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Zu hören sind pulse1, pulse2, triangle, noise, tick und move. Timer 253 ergibt unter NTSC etwa 440-Hz-Pulse und ein 220-Hz-Dreieck. Tick liegt bei etwa 111 Hz, move bei etwa 174 Hz und endet früher. Der letzte Abschnitt ist still.

nes_apu_init: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio.h:15

Deklarationshinweise im Original
Disable frame IRQs, enable the four tonal/noise channels and install quiet
control defaults. DMC remains disabled.

kitaqfc/lib/audio.c:28

c
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

Deaktiviert alle Kanäle und löscht Puls-/Rauschlautstärke sowie DMC-Ausgabe.

Syntax

c
void nes_apu_silence_all(void);

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Zu hören sind pulse1, pulse2, triangle, noise, tick und move. Timer 253 ergibt unter NTSC etwa 440-Hz-Pulse und ein 220-Hz-Dreieck. Tick liegt bei etwa 111 Hz, move bei etwa 174 Hz und endet früher. Der letzte Abschnitt ist still.

nes_apu_silence_all: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio.h:19

Deklarationshinweise im Original
Disable every channel and clear volume/DMC output settings used by this helper.

kitaqfc/lib/audio.c:49

c
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

Konfiguriert DMC-Steuerung/-Ausgabe und wandelt Sampleadresse und -länge in Registereinheiten um.

Syntax

c
void nes_dmc_config(u8 flags_rate, u8 output_level, u16 sample_addr, u16 sample_len);

Parameter

flags_rate

DMC: Bit 7 IRQ, Bit 6 Schleife, unteres Halbbyte Ratenindex. Das Beispiel aktiviert IRQ nicht.

output_level

Anfänglicher DMC-Ausgabezähler 0..127; geschrieben werden nur die unteren sieben Bits.

sample_addr

CPU-Adresse der DMC-Daten: eine 64-Byte-Grenze in $C000..$FFC0.

sample_len

Bytelänge 16*n+1 in 1..4081. Übergeben Sie weder null noch eine nicht darstellbare Länge.

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Bedingungen und Grenzen

DMC liest ROM ab einer 64-Byte-Grenze in $C000..$FFC0. Die Länge beträgt 16*n+1 Bytes in 1..4081. Diese Hilfen prüfen weder Ausrichtung noch Bereiche und wechseln keine Banken. Das Beispiel legt eigene Daten mit __aligned(64) in der festen Bank 0 ab und prüft deren Lage zur Laufzeit.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Ein eigenes Deltamuster spielt mit Rate 10, pausiert und spielt dann schneller mit Rate 12. Der DMC-Stopp erhält den Ausgabezähler, daher kann die Pause einen Transienten enthalten. Der letzte Vorgang schaltet die gesamte APU stumm.

nes_dmc_config: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio.h:38

Deklarationshinweise im Original
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

c
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

Konfiguriert das DMC-Sample und startet sofort die Wiedergabe.

Syntax

c
void nes_dmc_play(u8 flags_rate, u8 output_level, u16 sample_addr, u16 sample_len);

Parameter

flags_rate

DMC: Bit 7 IRQ, Bit 6 Schleife, unteres Halbbyte Ratenindex. Das Beispiel aktiviert IRQ nicht.

output_level

Anfänglicher DMC-Ausgabezähler 0..127; geschrieben werden nur die unteren sieben Bits.

sample_addr

CPU-Adresse der DMC-Daten: eine 64-Byte-Grenze in $C000..$FFC0.

sample_len

Bytelänge 16*n+1 in 1..4081. Übergeben Sie weder null noch eine nicht darstellbare Länge.

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Bedingungen und Grenzen

DMC liest ROM ab einer 64-Byte-Grenze in $C000..$FFC0. Die Länge beträgt 16*n+1 Bytes in 1..4081. Diese Hilfen prüfen weder Ausrichtung noch Bereiche und wechseln keine Banken. Das Beispiel legt eigene Daten mit __aligned(64) in der festen Bank 0 ab und prüft deren Lage zur Laufzeit.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Ein eigenes Deltamuster spielt mit Rate 10, pausiert und spielt dann schneller mit Rate 12. Der DMC-Stopp erhält den Ausgabezähler, daher kann die Pause einen Transienten enthalten. Der letzte Vorgang schaltet die gesamte APU stumm.

nes_dmc_play: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio.h:44

Deklarationshinweise im Original
Install sample parameters, then start DMC using the full-channel enable mask.

kitaqfc/lib/audio.c:137

c
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

Schreibt APU_STATUS=0x1F und aktiviert DMC sowie alle vier anderen Stimmen.

Syntax

c
void nes_dmc_start(void);

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Bedingungen und Grenzen

DMC liest ROM ab einer 64-Byte-Grenze in $C000..$FFC0. Die Länge beträgt 16*n+1 Bytes in 1..4081. Diese Hilfen prüfen weder Ausrichtung noch Bereiche und wechseln keine Banken. Das Beispiel legt eigene Daten mit __aligned(64) in der festen Bank 0 ab und prüft deren Lage zur Laufzeit.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Ein eigenes Deltamuster spielt mit Rate 10, pausiert und spielt dann schneller mit Rate 12. Der DMC-Stopp erhält den Ausgabezähler, daher kann die Pause einen Transienten enthalten. Der letzte Vorgang schaltet die gesamte APU stumm.

nes_dmc_start: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio.h:40

Deklarationshinweise im Original
Enable DMC together with all four other channels by replacing the status mask.

kitaqfc/lib/audio.c:125

c
void nes_dmc_start(void)
{
    APU_STATUS = 0x1F;
}
nes_dmc_stop

Schreibt APU_STATUS=0x0F, stoppt DMC und setzt die Aktivierungsbits aller vier anderen Stimmen.

Syntax

c
void nes_dmc_stop(void);

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Bedingungen und Grenzen

DMC liest ROM ab einer 64-Byte-Grenze in $C000..$FFC0. Die Länge beträgt 16*n+1 Bytes in 1..4081. Diese Hilfen prüfen weder Ausrichtung noch Bereiche und wechseln keine Banken. Das Beispiel legt eigene Daten mit __aligned(64) in der festen Bank 0 ab und prüft deren Lage zur Laufzeit.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Ein eigenes Deltamuster spielt mit Rate 10, pausiert und spielt dann schneller mit Rate 12. Der DMC-Stopp erhält den Ausgabezähler, daher kann die Pause einen Transienten enthalten. Der letzte Vorgang schaltet die gesamte APU stumm.

nes_dmc_stop: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio.h:42

Deklarationshinweise im Original
Disable DMC while leaving all four other channel-enable bits set.

kitaqfc/lib/audio.c:131

c
void nes_dmc_stop(void)
{
    APU_STATUS = 0x0F;
}
nes_sfx_move_blip

Triggert Puls 1 mit Steuerwert 0x5A, Timer 0x0280 und Längenindex 2 für einen höheren, kürzeren Bewegungston.

Syntax

c
void nes_sfx_move_blip(void);

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Bedingungen und Grenzen

Diese Hilfe schreibt eine Einkanal-APU_STATUS-Maske und deaktiviert andere Stimmen; sie ist kein Mehrstimmenmischer. Bei Puls und Dreieck ist period ein Timerwert: Kleinere Werte erzeugen höhere Töne. Beispieltonhöhen und -dauern wurden mit NTSC-Timing geprüft.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Zu hören sind pulse1, pulse2, triangle, noise, tick und move. Timer 253 ergibt unter NTSC etwa 440-Hz-Pulse und ein 220-Hz-Dreieck. Tick liegt bei etwa 111 Hz, move bei etwa 174 Hz und endet früher. Der letzte Abschnitt ist still.

nes_sfx_move_blip: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio.h:33

Deklarationshinweise im Original
Trigger the predefined pulse-1 movement effect.

kitaqfc/lib/audio.c:107

c
void nes_sfx_move_blip(void)
{
    nes_sfx_square1(0x5A, 0x0280, 2);
}
nes_sfx_noise

Aktiviert nur Rauschen und schreibt Hüllkurve, Periode/Modus und Längenindex.

Syntax

c
void nes_sfx_noise(u8 volume, u8 period_mode, u8 length_index);

Parameter

volume

Rohe Rauschsteuerung: Bit 5 Längenzählerstopp, Bit 4 konstante Lautstärke, unteres Halbbyte Lautstärke oder Hüllkurvenperiode.

period_mode

Rauschregister: Bit 7 Kurzmodus, unteres Halbbyte Periodentabellenindex.

length_index

Längentabellenindex 0..31, keine Frameanzahl. Nur die unteren fünf Bits erreichen das Register.

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Bedingungen und Grenzen

Diese Hilfe schreibt eine Einkanal-APU_STATUS-Maske und deaktiviert andere Stimmen; sie ist kein Mehrstimmenmischer. Bei Puls und Dreieck ist period ein Timerwert: Kleinere Werte erzeugen höhere Töne. Beispieltonhöhen und -dauern wurden mit NTSC-Timing geprüft.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Zu hören sind pulse1, pulse2, triangle, noise, tick und move. Timer 253 ergibt unter NTSC etwa 440-Hz-Pulse und ein 220-Hz-Dreieck. Tick liegt bei etwa 111 Hz, move bei etwa 174 Hz und endet früher. Der letzte Abschnitt ist still.

nes_sfx_noise: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio.h:29

Deklarationshinweise im Original
Enable only noise and load envelope/control, period/mode and length fields.

kitaqfc/lib/audio.c:92

c
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

Aktiviert nur Puls 1, deaktiviert Sweep und schreibt Steuerwert, Timer und Längenindex.

Syntax

c
void nes_sfx_square1(u8 duty_volume, u16 period, u8 length_index);

Parameter

duty_volume

Rohe Pulssteuerung: Bits 7..6 Tastgrad, Bit 5 Längenzählerstopp, Bit 4 konstante Lautstärke, unteres Halbbyte Lautstärke oder Hüllkurvenperiode.

period

11-Bit-Timer 0..2047. Pulsfrequenz: CPU-Takt/[16*(period+1)]; Dreieckfrequenz: CPU-Takt/[32*(period+1)].

length_index

Längentabellenindex 0..31, keine Frameanzahl. Nur die unteren fünf Bits erreichen das Register.

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Bedingungen und Grenzen

Diese Hilfe schreibt eine Einkanal-APU_STATUS-Maske und deaktiviert andere Stimmen; sie ist kein Mehrstimmenmischer. Bei Puls und Dreieck ist period ein Timerwert: Kleinere Werte erzeugen höhere Töne. Beispieltonhöhen und -dauern wurden mit NTSC-Timing geprüft.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Zu hören sind pulse1, pulse2, triangle, noise, tick und move. Timer 253 ergibt unter NTSC etwa 440-Hz-Pulse und ein 220-Hz-Dreieck. Tick liegt bei etwa 111 Hz, move bei etwa 174 Hz und endet früher. Der letzte Abschnitt ist still.

nes_sfx_square1: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio.h:23

Deklarationshinweise im Original
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

c
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

Aktiviert nur Puls 2, deaktiviert Sweep und schreibt Steuerwert, Timer und Längenindex.

Syntax

c
void nes_sfx_square2(u8 duty_volume, u16 period, u8 length_index);

Parameter

duty_volume

Rohe Pulssteuerung: Bits 7..6 Tastgrad, Bit 5 Längenzählerstopp, Bit 4 konstante Lautstärke, unteres Halbbyte Lautstärke oder Hüllkurvenperiode.

period

11-Bit-Timer 0..2047. Pulsfrequenz: CPU-Takt/[16*(period+1)]; Dreieckfrequenz: CPU-Takt/[32*(period+1)].

length_index

Längentabellenindex 0..31, keine Frameanzahl. Nur die unteren fünf Bits erreichen das Register.

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Bedingungen und Grenzen

Diese Hilfe schreibt eine Einkanal-APU_STATUS-Maske und deaktiviert andere Stimmen; sie ist kein Mehrstimmenmischer. Bei Puls und Dreieck ist period ein Timerwert: Kleinere Werte erzeugen höhere Töne. Beispieltonhöhen und -dauern wurden mit NTSC-Timing geprüft.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Zu hören sind pulse1, pulse2, triangle, noise, tick und move. Timer 253 ergibt unter NTSC etwa 440-Hz-Pulse und ein 220-Hz-Dreieck. Tick liegt bei etwa 111 Hz, move bei etwa 174 Hz und endet früher. Der letzte Abschnitt ist still.

nes_sfx_square2: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio.h:25

Deklarationshinweise im Original
Enable only pulse 2 and load its control/timer/length fields, disabling other channels.

kitaqfc/lib/audio.c:73

c
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

Triggert Puls 1 mit Steuerwert 0x9A, Timer 0x03F0 und Längenindex 4 für einen kurzen tiefen Tick.

Syntax

c
void nes_sfx_tick_blip(void);

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Bedingungen und Grenzen

Diese Hilfe schreibt eine Einkanal-APU_STATUS-Maske und deaktiviert andere Stimmen; sie ist kein Mehrstimmenmischer. Bei Puls und Dreieck ist period ein Timerwert: Kleinere Werte erzeugen höhere Töne. Beispieltonhöhen und -dauern wurden mit NTSC-Timing geprüft.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Zu hören sind pulse1, pulse2, triangle, noise, tick und move. Timer 253 ergibt unter NTSC etwa 440-Hz-Pulse und ein 220-Hz-Dreieck. Tick liegt bei etwa 111 Hz, move bei etwa 174 Hz und endet früher. Der letzte Abschnitt ist still.

nes_sfx_tick_blip: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio.h:31

Deklarationshinweise im Original
Trigger the predefined pulse-1 tick effect; it inherits the exclusive-channel behavior.

kitaqfc/lib/audio.c:101

c
void nes_sfx_tick_blip(void)
{
    nes_sfx_square1(0x9A, 0x03F0, 4);
}
nes_sfx_triangle

Aktiviert nur Dreieck und schreibt Linearcounter, Timer und Längenindex.

Syntax

c
void nes_sfx_triangle(u8 linear, u16 period, u8 length_index);

Parameter

linear

Dreieck-Linearcounter: Bit 7 Steuerung/Längenstopp, untere sieben Bits Nachladewert.

period

11-Bit-Timer 0..2047. Pulsfrequenz: CPU-Takt/[16*(period+1)]; Dreieckfrequenz: CPU-Takt/[32*(period+1)].

length_index

Längentabellenindex 0..31, keine Frameanzahl. Nur die unteren fünf Bits erreichen das Register.

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Bedingungen und Grenzen

Diese Hilfe schreibt eine Einkanal-APU_STATUS-Maske und deaktiviert andere Stimmen; sie ist kein Mehrstimmenmischer. Bei Puls und Dreieck ist period ein Timerwert: Kleinere Werte erzeugen höhere Töne. Beispieltonhöhen und -dauern wurden mit NTSC-Timing geprüft.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Zu hören sind pulse1, pulse2, triangle, noise, tick und move. Timer 253 ergibt unter NTSC etwa 440-Hz-Pulse und ein 220-Hz-Dreieck. Tick liegt bei etwa 111 Hz, move bei etwa 174 Hz und endet früher. Der letzte Abschnitt ist still.

nes_sfx_triangle: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio.h:27

Deklarationshinweise im Original
Enable only triangle and load linear-counter, timer and length fields.

kitaqfc/lib/audio.c:83

c
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 — NMI-gesteuerte Vierkanalmusik

Die Vierkanalmusik läuft in der NMI weiter. Initialisieren Sie den Treiber, legen Sie ein Musikstück fest und füllen Sie die Warteschlange vor. Aktivieren Sie dann NMI für die Wiedergabe und füllen Sie aus dem Hauptprogramm nach. Die NMI liest eine RAM-Warteschlange. Bei rechtzeitigem Nachfüllen reicht dadurch wenig RAM für einen langen Stream. Jeder Kanal hat unabhängige HOLD/STOP-Befehle.

Ein Datensatz besteht aus fünf Bytes: delay, CH1, CH2, CH3, CH4. Eine Dauer von 1 bis 255 gibt an, wie viele NMI-Ticks der neue Zustand anhält. Null beendet die Wiedergabe; die übrigen vier Bytes werden ignoriert. Tonwerte von 0 bis 71 entsprechen C2 bis B7 (24=C4). Rauschwerte von 0 bis 15 wählen eine Periode im langen Modus, 16 bis 31 im kurzen Modus. Für jeden Kanal gilt: 255=NES_AUDIO_HOLD behält den Zustand bei, 254=NES_AUDIO_STOP schaltet ihn stumm.

Dieser Vierkanaltreiber ist auf NTSC abgestimmt: CH1=Impuls 1, CH2=Impuls 2, CH3=Dreieck und CH4=Rauschen, mit den Indizes 0 bis 3. DMC und Erweiterungsaudio werden nicht wiedergegeben. Verwenden Sie ihn nicht gleichzeitig mit direkten APU-Zugriffen, etwa den Effekten in audio.c. Es gibt weder eine PAL-Tonhöhentabelle noch eine PAL-Tempokorrektur.

Läuft die Dauer ab, ohne dass ein weiterer BGM-Datensatz vorliegt, verstummen die BGM-Noten. Nach Eingang neuer Daten geht es bei einer NMI weiter. Ein unabhängiger SFX läuft weiter. Gezählt werden Eintritte in den Datenmangel, nicht alle leeren Frames. Das Einreihen reiner HOLD-Werte stellt die vorherigen BGM-Noten nicht wieder her. Füllen Sie normalerweise pro Frame nach und halten Sie vor längeren Arbeiten ausreichend Wiedergabezeit in der Warteschlange bereit.

WartezeitCH1: Puls 1CH2: Puls 2CH3: DreieckCH4: Rauschen
2424 (C4)12 (C3)0 (C2)2

Vom Compiler angebundener NMI-Hook

nes_audio_vblank_init

Initialisiert APU und Warteschlange und setzt Wiedergabe, Nachfüllzustand sowie Datenmangelzähler zurück.

Syntax

c
void nes_audio_vblank_init(void);

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Binden Sie audio_vblank.h ein und nehmen Sie audio_vblank.c genau einmal in den Build auf. Der Compiler lässt sowohl den Standard-NMI-Handler als auch einen eigenen NMI-Handler den Musik-Hook einmal aufrufen. Aktivieren Sie PPU-NMI. Die Hauptschleife ruft keine Musikaktualisierung auf.

Dieser Vierkanaltreiber ist auf NTSC abgestimmt: CH1=Impuls 1, CH2=Impuls 2, CH3=Dreieck und CH4=Rauschen, mit den Indizes 0 bis 3. DMC und Erweiterungsaudio werden nicht wiedergegeben. Verwenden Sie ihn nicht gleichzeitig mit direkten APU-Zugriffen, etwa den Effekten in audio.c. Es gibt weder eine PAL-Tonhöhentabelle noch eine PAL-Tempokorrektur.

Deaktiviert APU-Frame-IRQs, DMC und den Sweep der Impulskanäle. Die Vorgaben sind: Impuls 1 mit 50 % Tastgrad und Lautstärke 12, Impuls 2 mit 25 % und Lautstärke 10, für Noten freigegebener Dreieckskanal sowie Rauschlautstärke 8. Die Initialisierung startet weder Musik noch NMI.

Anwendungsbeispiel

c
nes_audio_vblank_init();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel spielt eine eigens komponierte vierkanalige Phrase einmal ab. Während das Hauptprogramm 90 Frames lang Ganzzahlberechnungen ohne Nachfüllen ausführt, läuft die Musik weiter. „PHRASE COMPLETE / SILENT“ und „UNDERRUNS 0 / MATH OK“ bedeuten, dass die Wiedergabe beendet ist, kein Datenmangel auftrat und die Rechenergebnisse stimmen. Prüfen Sie in der Audioaufnahme die Impulsmelodie und ihre Begleitung, den Dreiecksbass und das Rauschen. Am Ende herrscht Stille. Das Bild zeigt die Steuerungsergebnisse; den Klang beurteilen Sie anhand der Audioaufnahme.

nes_audio_vblank_init: NROM
NROM
NROM — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio_vblank.h:19

Deklarationshinweise im Original
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

c
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

Prüft einen Datensatz und kopiert ihn in die RAM-Warteschlange. Damit lässt sich Musik im Spielcode erzeugen, ohne Daten aus dem ROM nachzufüllen.

Syntax

c
u8 nes_audio_vblank_enqueue(const u8* record);

Parameter

record

Adresse von fünf lesbaren Bytes, die bis zur Rückkehr des Aufrufs gültig bleiben muss. Danach darf das Quellarray wiederverwendet werden. Null wird abgewiesen.

Rückgabewert

Gibt bei Annahme 1 zurück. Eine volle Warteschlange, Null oder ungültige Ton- bzw. Rauschwerte führen zu 0, ohne die Warteschlange zu ändern. Die vier Kanalbytes eines Abschlussdatensatzes werden nicht geprüft.

Bedingungen und Grenzen

Binden Sie audio_vblank.h ein und nehmen Sie audio_vblank.c genau einmal in den Build auf. Der Compiler lässt sowohl den Standard-NMI-Handler als auch einen eigenen NMI-Handler den Musik-Hook einmal aufrufen. Aktivieren Sie PPU-NMI. Die Hauptschleife ruft keine Musikaktualisierung auf.

Dieser Vierkanaltreiber ist auf NTSC abgestimmt: CH1=Impuls 1, CH2=Impuls 2, CH3=Dreieck und CH4=Rauschen, mit den Indizes 0 bis 3. DMC und Erweiterungsaudio werden nicht wiedergegeben. Verwenden Sie ihn nicht gleichzeitig mit direkten APU-Zugriffen, etwa den Effekten in audio.c. Es gibt weder eine PAL-Tonhöhentabelle noch eine PAL-Tempokorrektur.

Der 40-Byte-Ringpuffer im RAM hat acht physische Plätze. Einer bleibt frei, damit sich voll und leer unterscheiden lassen. Nutzbar sind somit sieben Datensätze. Verwenden Sie nur einen Produzenten im Hauptprogramm; fügen Sie aus der NMI keine Daten hinzu und führen Sie dort weder Nachfüllen noch Initialisierung aus. Der Produzent veröffentlicht die ein Byte große Schreibposition erst nach dem Kopieren des vollständigen Datensatzes. Dadurch kann die NMI keinen unvollständigen Datensatz lesen.

Ein Datensatz besteht aus fünf Bytes: delay, CH1, CH2, CH3, CH4. Eine Dauer von 1 bis 255 gibt an, wie viele NMI-Ticks der neue Zustand anhält. Null beendet die Wiedergabe; die übrigen vier Bytes werden ignoriert. Tonwerte von 0 bis 71 entsprechen C2 bis B7 (24=C4). Rauschwerte von 0 bis 15 wählen eine Periode im langen Modus, 16 bis 31 im kurzen Modus. Für jeden Kanal gilt: 255=NES_AUDIO_HOLD behält den Zustand bei, 254=NES_AUDIO_STOP schaltet ihn stumm.

Anwendungsbeispiel

c
result[6]=nes_audio_vblank_enqueue(quiet_record); // Copy five bytes into RAM.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel spielt eine eigens komponierte vierkanalige Phrase einmal ab. Während das Hauptprogramm 90 Frames lang Ganzzahlberechnungen ohne Nachfüllen ausführt, läuft die Musik weiter. „PHRASE COMPLETE / SILENT“ und „UNDERRUNS 0 / MATH OK“ bedeuten, dass die Wiedergabe beendet ist, kein Datenmangel auftrat und die Rechenergebnisse stimmen. Prüfen Sie in der Audioaufnahme die Impulsmelodie und ihre Begleitung, den Dreiecksbass und das Rauschen. Am Ende herrscht Stille. Das Bild zeigt die Steuerungsergebnisse; den Klang beurteilen Sie anhand der Audioaufnahme.

nes_audio_vblank_enqueue: NROM
NROM
NROM — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio_vblank.h:22

Deklarationshinweise im Original
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

c
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

Gibt die Anzahl der Datensätze zurück, die von der NMI noch nicht verbraucht wurden.

Syntax

c
u8 nes_audio_vblank_queued(void);

Rückgabewert

Gibt 0 bis 7 wartende BGM-Datensätze zurück. Die laufende Dauer und sämtliche SFX-Datensätze zählen nicht mit. Da die NMI Daten verbraucht, ist das Ergebnis nur eine Momentaufnahme.

Bedingungen und Grenzen

Binden Sie audio_vblank.h ein und nehmen Sie audio_vblank.c genau einmal in den Build auf. Der Compiler lässt sowohl den Standard-NMI-Handler als auch einen eigenen NMI-Handler den Musik-Hook einmal aufrufen. Aktivieren Sie PPU-NMI. Die Hauptschleife ruft keine Musikaktualisierung auf.

Dieser Vierkanaltreiber ist auf NTSC abgestimmt: CH1=Impuls 1, CH2=Impuls 2, CH3=Dreieck und CH4=Rauschen, mit den Indizes 0 bis 3. DMC und Erweiterungsaudio werden nicht wiedergegeben. Verwenden Sie ihn nicht gleichzeitig mit direkten APU-Zugriffen, etwa den Effekten in audio.c. Es gibt weder eine PAL-Tonhöhentabelle noch eine PAL-Tempokorrektur.

Der 40-Byte-Ringpuffer im RAM hat acht physische Plätze. Einer bleibt frei, damit sich voll und leer unterscheiden lassen. Nutzbar sind somit sieben Datensätze. Verwenden Sie nur einen Produzenten im Hauptprogramm; fügen Sie aus der NMI keine Daten hinzu und führen Sie dort weder Nachfüllen noch Initialisierung aus. Der Produzent veröffentlicht die ein Byte große Schreibposition erst nach dem Kopieren des vollständigen Datensatzes. Dadurch kann die NMI keinen unvollständigen Datensatz lesen.

Anwendungsbeispiel

c
result[1]=nes_audio_vblank_queued(); // Seven records after prefill.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel spielt eine eigens komponierte vierkanalige Phrase einmal ab. Während das Hauptprogramm 90 Frames lang Ganzzahlberechnungen ohne Nachfüllen ausführt, läuft die Musik weiter. „PHRASE COMPLETE / SILENT“ und „UNDERRUNS 0 / MATH OK“ bedeuten, dass die Wiedergabe beendet ist, kein Datenmangel auftrat und die Rechenergebnisse stimmen. Prüfen Sie in der Audioaufnahme die Impulsmelodie und ihre Begleitung, den Dreiecksbass und das Rauschen. Am Ende herrscht Stille. Das Bild zeigt die Steuerungsergebnisse; den Klang beurteilen Sie anhand der Audioaufnahme.

nes_audio_vblank_queued: NROM
NROM
NROM — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio_vblank.h:24

Deklarationshinweise im Original
Return queued records (0..7), excluding the record whose delay is in progress.

kitaqfc/lib/audio_vblank.c:94

c
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

Gibt die Anzahl freier Datensatzplätze in der Warteschlange zurück.

Syntax

c
u8 nes_audio_vblank_free(void);

Rückgabewert

Gibt 0 bis 7 freie BGM-Plätze zurück, entsprechend 7−queued(). Das ist eine Platzanzahl; jeder Platz umfasst fünf Bytes. Der separate 35-Byte-SFX-Puffer gehört nicht zu dieser Warteschlange.

Bedingungen und Grenzen

Binden Sie audio_vblank.h ein und nehmen Sie audio_vblank.c genau einmal in den Build auf. Der Compiler lässt sowohl den Standard-NMI-Handler als auch einen eigenen NMI-Handler den Musik-Hook einmal aufrufen. Aktivieren Sie PPU-NMI. Die Hauptschleife ruft keine Musikaktualisierung auf.

Dieser Vierkanaltreiber ist auf NTSC abgestimmt: CH1=Impuls 1, CH2=Impuls 2, CH3=Dreieck und CH4=Rauschen, mit den Indizes 0 bis 3. DMC und Erweiterungsaudio werden nicht wiedergegeben. Verwenden Sie ihn nicht gleichzeitig mit direkten APU-Zugriffen, etwa den Effekten in audio.c. Es gibt weder eine PAL-Tonhöhentabelle noch eine PAL-Tempokorrektur.

Der 40-Byte-Ringpuffer im RAM hat acht physische Plätze. Einer bleibt frei, damit sich voll und leer unterscheiden lassen. Nutzbar sind somit sieben Datensätze. Verwenden Sie nur einen Produzenten im Hauptprogramm; fügen Sie aus der NMI keine Daten hinzu und führen Sie dort weder Nachfüllen noch Initialisierung aus. Der Produzent veröffentlicht die ein Byte große Schreibposition erst nach dem Kopieren des vollständigen Datensatzes. Dadurch kann die NMI keinen unvollständigen Datensatz lesen.

Anwendungsbeispiel

c
result[2]=nes_audio_vblank_free();   // No free slots immediately after prefill.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel spielt eine eigens komponierte vierkanalige Phrase einmal ab. Während das Hauptprogramm 90 Frames lang Ganzzahlberechnungen ohne Nachfüllen ausführt, läuft die Musik weiter. „PHRASE COMPLETE / SILENT“ und „UNDERRUNS 0 / MATH OK“ bedeuten, dass die Wiedergabe beendet ist, kein Datenmangel auftrat und die Rechenergebnisse stimmen. Prüfen Sie in der Audioaufnahme die Impulsmelodie und ihre Begleitung, den Dreiecksbass und das Rauschen. Am Ende herrscht Stille. Das Bild zeigt die Steuerungsergebnisse; den Klang beurteilen Sie anhand der Audioaufnahme.

nes_audio_vblank_free: NROM
NROM
NROM — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio_vblank.h:26

Deklarationshinweise im Original
Return available record slots (0..7), not bytes.

kitaqfc/lib/audio_vblank.c:99

c
u8 nes_audio_vblank_free(void){return 7-nes_audio_vblank_queued();}
nes_audio_vblank_start

Aktiviert das Auslesen der RAM-Warteschlange. Der erste Datensatz wird bei der nächsten NMI entnommen.

Syntax

c
void nes_audio_vblank_start(void);

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Binden Sie audio_vblank.h ein und nehmen Sie audio_vblank.c genau einmal in den Build auf. Der Compiler lässt sowohl den Standard-NMI-Handler als auch einen eigenen NMI-Handler den Musik-Hook einmal aufrufen. Aktivieren Sie PPU-NMI. Die Hauptschleife ruft keine Musikaktualisierung auf.

Dieser Vierkanaltreiber ist auf NTSC abgestimmt: CH1=Impuls 1, CH2=Impuls 2, CH3=Dreieck und CH4=Rauschen, mit den Indizes 0 bis 3. DMC und Erweiterungsaudio werden nicht wiedergegeben. Verwenden Sie ihn nicht gleichzeitig mit direkten APU-Zugriffen, etwa den Effekten in audio.c. Es gibt weder eine PAL-Tonhöhentabelle noch eine PAL-Tempokorrektur.

Initialisieren Sie zuerst den Treiber und fügen Sie Datensätze hinzu. Dieser Aufruf aktiviert keine NMI und ändert weder die laufende Dauer noch die Leseposition. Setzen Sie einen pausierten Treiber mit pause(0) fort; start allein hebt die Pause nicht auf.

Läuft die Dauer ab, ohne dass ein weiterer BGM-Datensatz vorliegt, verstummen die BGM-Noten. Nach Eingang neuer Daten geht es bei einer NMI weiter. Ein unabhängiger SFX läuft weiter. Gezählt werden Eintritte in den Datenmangel, nicht alle leeren Frames. Das Einreihen reiner HOLD-Werte stellt die vorherigen BGM-Noten nicht wieder her. Füllen Sie normalerweise pro Frame nach und halten Sie vor längeren Arbeiten ausreichend Wiedergabezeit in der Warteschlange bereit.

Anwendungsbeispiel

c
nes_audio_vblank_start(); // Consume the copied record on the next NMI.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel spielt eine eigens komponierte vierkanalige Phrase einmal ab. Während das Hauptprogramm 90 Frames lang Ganzzahlberechnungen ohne Nachfüllen ausführt, läuft die Musik weiter. „PHRASE COMPLETE / SILENT“ und „UNDERRUNS 0 / MATH OK“ bedeuten, dass die Wiedergabe beendet ist, kein Datenmangel auftrat und die Rechenergebnisse stimmen. Prüfen Sie in der Audioaufnahme die Impulsmelodie und ihre Begleitung, den Dreiecksbass und das Rauschen. Am Ende herrscht Stille. Das Bild zeigt die Steuerungsergebnisse; den Klang beurteilen Sie anhand der Audioaufnahme.

nes_audio_vblank_start: NROM
NROM
NROM — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio_vblank.h:28

Deklarationshinweise im Original
Enable consumption at the next NMI. Does not enable PPU NMI itself.

kitaqfc/lib/audio_vblank.c:100

c
void nes_audio_vblank_start(void){nav_active=1;}
nes_audio_vblank_stop

Deaktiviert die Wiedergabe, schaltet die vier Kanäle stumm und verwirft Warteschlange sowie ROM-Nachfüllzustand.

Syntax

c
void nes_audio_vblank_stop(void);

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Binden Sie audio_vblank.h ein und nehmen Sie audio_vblank.c genau einmal in den Build auf. Der Compiler lässt sowohl den Standard-NMI-Handler als auch einen eigenen NMI-Handler den Musik-Hook einmal aufrufen. Aktivieren Sie PPU-NMI. Die Hauptschleife ruft keine Musikaktualisierung auf.

Dieser Vierkanaltreiber ist auf NTSC abgestimmt: CH1=Impuls 1, CH2=Impuls 2, CH3=Dreieck und CH4=Rauschen, mit den Indizes 0 bis 3. DMC und Erweiterungsaudio werden nicht wiedergegeben. Verwenden Sie ihn nicht gleichzeitig mit direkten APU-Zugriffen, etwa den Effekten in audio.c. Es gibt weder eine PAL-Tonhöhentabelle noch eine PAL-Tempokorrektur.

Stoppt BGM und SFX und verwirft Warteschlange, Nachfüllzustand, beide Wiedergabepositionen und Pausenzustand. Klangfarben und Datenmangelzähler bleiben erhalten; NMI wird nicht deaktiviert. Mit pause bleibt die Position erhalten. Auch set_music und play_music führen diesen Stopp intern aus und brechen dadurch SFX ab.

Anwendungsbeispiel

c
nes_audio_vblank_stop(); // Clear the feeder and queued records; silence now.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel spielt eine eigens komponierte vierkanalige Phrase einmal ab. Während das Hauptprogramm 90 Frames lang Ganzzahlberechnungen ohne Nachfüllen ausführt, läuft die Musik weiter. „PHRASE COMPLETE / SILENT“ und „UNDERRUNS 0 / MATH OK“ bedeuten, dass die Wiedergabe beendet ist, kein Datenmangel auftrat und die Rechenergebnisse stimmen. Prüfen Sie in der Audioaufnahme die Impulsmelodie und ihre Begleitung, den Dreiecksbass und das Rauschen. Am Ende herrscht Stille. Das Bild zeigt die Steuerungsergebnisse; den Klang beurteilen Sie anhand der Audioaufnahme.

nes_audio_vblank_stop: NROM
NROM
NROM — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio_vblank.h:30

Deklarationshinweise im Original
Disable consumption, silence, discard queued records and clear the feeder.

kitaqfc/lib/audio_vblank.c:29

c
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

Stoppt die Wiedergabe und legt einen Stream als Nachfüllquelle fest. Das Kopieren in die Warteschlange und der Wiedergabestart sind getrennte Vorgänge.

Syntax

c
u8 nes_audio_vblank_set_music(const u8* records,u16 count,u8 loop);

Parameter

records

Anfang des Streams in lesbarem ROM oder RAM. Halten Sie die Daten bis zum Ende des Nachfüllens verfügbar. Es findet kein Bankwechsel statt: Blenden Sie beim Aufruf von refill die passende ROM-Bank ein. Die NMI liest ausschließlich die ins RAM kopierten Datensätze.

count

Anzahl lesbarer Fünf-Byte-Datensätze von 1 bis 13107, keine Byteanzahl. Sämtliche count×5 Bytes müssen in einem zusammenhängenden gültigen CPU-Adressbereich liegen.

loop

Null wählt einmalige Wiedergabe, jeder andere Wert wiederholt ab dem Anfang. Fügen Sie in einen sich wiederholenden Stream keinen Abschlussdatensatz mit Dauer null ein.

Rückgabewert

Gibt bei gültigem Zeiger und gültiger Anzahl 1 zurück; bei Nullzeiger, Anzahl null oder einer Anzahl über 13107 wird 0 zurückgegeben. Auch bei einem Fehlschlag werden die bisherige Wiedergabe gestoppt und wartende Daten verworfen. Der Inhalt der Datensätze wird beim Nachfüllen geprüft.

Bedingungen und Grenzen

Binden Sie audio_vblank.h ein und nehmen Sie audio_vblank.c genau einmal in den Build auf. Der Compiler lässt sowohl den Standard-NMI-Handler als auch einen eigenen NMI-Handler den Musik-Hook einmal aufrufen. Aktivieren Sie PPU-NMI. Die Hauptschleife ruft keine Musikaktualisierung auf.

Dieser Vierkanaltreiber ist auf NTSC abgestimmt: CH1=Impuls 1, CH2=Impuls 2, CH3=Dreieck und CH4=Rauschen, mit den Indizes 0 bis 3. DMC und Erweiterungsaudio werden nicht wiedergegeben. Verwenden Sie ihn nicht gleichzeitig mit direkten APU-Zugriffen, etwa den Effekten in audio.c. Es gibt weder eine PAL-Tonhöhentabelle noch eine PAL-Tempokorrektur.

Ein Datensatz besteht aus fünf Bytes: delay, CH1, CH2, CH3, CH4. Eine Dauer von 1 bis 255 gibt an, wie viele NMI-Ticks der neue Zustand anhält. Null beendet die Wiedergabe; die übrigen vier Bytes werden ignoriert. Tonwerte von 0 bis 71 entsprechen C2 bis B7 (24=C4). Rauschwerte von 0 bis 15 wählen eine Periode im langen Modus, 16 bis 31 im kurzen Modus. Für jeden Kanal gilt: 255=NES_AUDIO_HOLD behält den Zustand bei, 254=NES_AUDIO_STOP schaltet ihn stumm.

Anwendungsbeispiel

c
result[5]=nes_audio_vblank_set_music(song,8,0); // Attach without starting.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel spielt eine eigens komponierte vierkanalige Phrase einmal ab. Während das Hauptprogramm 90 Frames lang Ganzzahlberechnungen ohne Nachfüllen ausführt, läuft die Musik weiter. „PHRASE COMPLETE / SILENT“ und „UNDERRUNS 0 / MATH OK“ bedeuten, dass die Wiedergabe beendet ist, kein Datenmangel auftrat und die Rechenergebnisse stimmen. Prüfen Sie in der Audioaufnahme die Impulsmelodie und ihre Begleitung, den Dreiecksbass und das Rauschen. Am Ende herrscht Stille. Das Bild zeigt die Steuerungsergebnisse; den Klang beurteilen Sie anhand der Audioaufnahme.

nes_audio_vblank_set_music: NROM
NROM
NROM — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio_vblank.h:33

Deklarationshinweise im Original
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

c
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

Füllt bis zu sieben Datensätze aus dem festgelegten Stream in freie Plätze. Dieser Vorgang im Hauptprogramm ermöglicht es einer kleinen RAM-Warteschlange, ein langes Musikstück wiederzugeben.

Syntax

c
u8 nes_audio_vblank_refill(void);

Rückgabewert

Gibt die Anzahl angenommener Datensätze von 0 bis 7 zurück, einschließlich des automatisch angehängten Abschlussdatensatzes bei einmaliger Wiedergabe. Ohne Quelle oder bei voller Warteschlange wird 0 zurückgegeben. Ein ungültiger Datensatz stoppt die Wiedergabe, verwirft Warteschlange und Nachfüllzustand und führt zu 0 als Rückgabewert.

Bedingungen und Grenzen

Binden Sie audio_vblank.h ein und nehmen Sie audio_vblank.c genau einmal in den Build auf. Der Compiler lässt sowohl den Standard-NMI-Handler als auch einen eigenen NMI-Handler den Musik-Hook einmal aufrufen. Aktivieren Sie PPU-NMI. Die Hauptschleife ruft keine Musikaktualisierung auf.

Dieser Vierkanaltreiber ist auf NTSC abgestimmt: CH1=Impuls 1, CH2=Impuls 2, CH3=Dreieck und CH4=Rauschen, mit den Indizes 0 bis 3. DMC und Erweiterungsaudio werden nicht wiedergegeben. Verwenden Sie ihn nicht gleichzeitig mit direkten APU-Zugriffen, etwa den Effekten in audio.c. Es gibt weder eine PAL-Tonhöhentabelle noch eine PAL-Tempokorrektur.

Anfang des Streams in lesbarem ROM oder RAM. Halten Sie die Daten bis zum Ende des Nachfüllens verfügbar. Es findet kein Bankwechsel statt: Blenden Sie beim Aufruf von refill die passende ROM-Bank ein. Die NMI liest ausschließlich die ins RAM kopierten Datensätze.

Null wählt einmalige Wiedergabe, jeder andere Wert wiederholt ab dem Anfang. Fügen Sie in einen sich wiederholenden Stream keinen Abschlussdatensatz mit Dauer null ein.

Läuft die Dauer ab, ohne dass ein weiterer BGM-Datensatz vorliegt, verstummen die BGM-Noten. Nach Eingang neuer Daten geht es bei einer NMI weiter. Ein unabhängiger SFX läuft weiter. Gezählt werden Eintritte in den Datenmangel, nicht alle leeren Frames. Das Einreihen reiner HOLD-Werte stellt die vorherigen BGM-Noten nicht wieder her. Füllen Sie normalerweise pro Frame nach und halten Sie vor längeren Arbeiten ausreichend Wiedergabezeit in der Warteschlange bereit.

ROM-Nachfüllen und direktes Einreihen nutzen dieselbe Warteschlange. Kombinieren Sie beides nur mit bewusst festgelegter Reihenfolge. Nachfüllen spielt keine Datensätze ab und startet den Verbraucher nicht. Ein Stopp wegen ungültiger Daten schaltet die APU allerdings stumm.

Anwendungsbeispiel

c
nes_audio_vblank_refill();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel spielt eine eigens komponierte vierkanalige Phrase einmal ab. Während das Hauptprogramm 90 Frames lang Ganzzahlberechnungen ohne Nachfüllen ausführt, läuft die Musik weiter. „PHRASE COMPLETE / SILENT“ und „UNDERRUNS 0 / MATH OK“ bedeuten, dass die Wiedergabe beendet ist, kein Datenmangel auftrat und die Rechenergebnisse stimmen. Prüfen Sie in der Audioaufnahme die Impulsmelodie und ihre Begleitung, den Dreiecksbass und das Rauschen. Am Ende herrscht Stille. Das Bild zeigt die Steuerungsergebnisse; den Klang beurteilen Sie anhand der Audioaufnahme.

nes_audio_vblank_refill: NROM
NROM
NROM — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio_vblank.h:37

Deklarationshinweise im Original
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

c
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

Legt ein Musikstück fest, füllt die Warteschlange vor und aktiviert die Wiedergabe mit einem Aufruf. Dies ist der übliche Einstieg zum Starten einer Phrase.

Syntax

c
u8 nes_audio_vblank_play_music(const u8* records,u16 count,u8 loop);

Parameter

records

Anfang des Streams in lesbarem ROM oder RAM. Halten Sie die Daten bis zum Ende des Nachfüllens verfügbar. Es findet kein Bankwechsel statt: Blenden Sie beim Aufruf von refill die passende ROM-Bank ein. Die NMI liest ausschließlich die ins RAM kopierten Datensätze.

count

Anzahl lesbarer Fünf-Byte-Datensätze von 1 bis 13107, keine Byteanzahl. Sämtliche count×5 Bytes müssen in einem zusammenhängenden gültigen CPU-Adressbereich liegen.

loop

Null wählt einmalige Wiedergabe, jeder andere Wert wiederholt ab dem Anfang. Fügen Sie in einen sich wiederholenden Stream keinen Abschlussdatensatz mit Dauer null ein.

Rückgabewert

Gibt 1 zurück, wenn Einrichtung und erstes Vorfüllen erfolgreich sind, andernfalls 0 bei ungültiger Einrichtung oder dabei erkannten ungültigen Daten. Ein Erfolg bestätigt nicht das gesamte Musikstück: Fehlerhafte spätere Datensätze werden erst bei späteren refill-Aufrufen entdeckt.

Bedingungen und Grenzen

Binden Sie audio_vblank.h ein und nehmen Sie audio_vblank.c genau einmal in den Build auf. Der Compiler lässt sowohl den Standard-NMI-Handler als auch einen eigenen NMI-Handler den Musik-Hook einmal aufrufen. Aktivieren Sie PPU-NMI. Die Hauptschleife ruft keine Musikaktualisierung auf.

Dieser Vierkanaltreiber ist auf NTSC abgestimmt: CH1=Impuls 1, CH2=Impuls 2, CH3=Dreieck und CH4=Rauschen, mit den Indizes 0 bis 3. DMC und Erweiterungsaudio werden nicht wiedergegeben. Verwenden Sie ihn nicht gleichzeitig mit direkten APU-Zugriffen, etwa den Effekten in audio.c. Es gibt weder eine PAL-Tonhöhentabelle noch eine PAL-Tempokorrektur.

Rufen Sie zuerst einmal init auf. play_music behält Klangfarben und Datenmangelzähler bei. Rufen Sie bei langen oder wiederholten Streams weiterhin regelmäßig refill auf.

Anwendungsbeispiel

c
result[0]=nes_audio_vblank_play_music(song,8,0);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel spielt eine eigens komponierte vierkanalige Phrase einmal ab. Während das Hauptprogramm 90 Frames lang Ganzzahlberechnungen ohne Nachfüllen ausführt, läuft die Musik weiter. „PHRASE COMPLETE / SILENT“ und „UNDERRUNS 0 / MATH OK“ bedeuten, dass die Wiedergabe beendet ist, kein Datenmangel auftrat und die Rechenergebnisse stimmen. Prüfen Sie in der Audioaufnahme die Impulsmelodie und ihre Begleitung, den Dreiecksbass und das Rauschen. Am Ende herrscht Stille. Das Bild zeigt die Steuerungsergebnisse; den Klang beurteilen Sie anhand der Audioaufnahme.

nes_audio_vblank_play_music: NROM
NROM
NROM — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio_vblank.h:39

Deklarationshinweise im Original
Set the stream, prefill the queue and start. Return 0 for invalid setup/data.

kitaqfc/lib/audio_vblank.c:135

c
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

Meldet, ob das Auslesen der Warteschlange durch NMI aktiviert ist.

Syntax

c
u8 nes_audio_vblank_is_playing(void);

Rückgabewert

Gibt 1 zurück, solange der BGM-Verbraucher aktiviert ist, auch während Pause oder Datenmangel; nach Stopp oder Ende wird 0 zurückgegeben. Ein allein laufender SFX ergibt ebenfalls 0. Der Wert sagt weder aus, ob etwas hörbar ist, noch ob ein SFX aktiv ist.

Bedingungen und Grenzen

Binden Sie audio_vblank.h ein und nehmen Sie audio_vblank.c genau einmal in den Build auf. Der Compiler lässt sowohl den Standard-NMI-Handler als auch einen eigenen NMI-Handler den Musik-Hook einmal aufrufen. Aktivieren Sie PPU-NMI. Die Hauptschleife ruft keine Musikaktualisierung auf.

Dieser Vierkanaltreiber ist auf NTSC abgestimmt: CH1=Impuls 1, CH2=Impuls 2, CH3=Dreieck und CH4=Rauschen, mit den Indizes 0 bis 3. DMC und Erweiterungsaudio werden nicht wiedergegeben. Verwenden Sie ihn nicht gleichzeitig mit direkten APU-Zugriffen, etwa den Effekten in audio.c. Es gibt weder eine PAL-Tonhöhentabelle noch eine PAL-Tempokorrektur.

Läuft die Dauer ab, ohne dass ein weiterer BGM-Datensatz vorliegt, verstummen die BGM-Noten. Nach Eingang neuer Daten geht es bei einer NMI weiter. Ein unabhängiger SFX läuft weiter. Gezählt werden Eintritte in den Datenmangel, nicht alle leeren Frames. Das Einreihen reiner HOLD-Werte stellt die vorherigen BGM-Noten nicht wieder her. Füllen Sie normalerweise pro Frame nach und halten Sie vor längeren Arbeiten ausreichend Wiedergabezeit in der Warteschlange bereit.

Anwendungsbeispiel

c
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();
    }

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel spielt eine eigens komponierte vierkanalige Phrase einmal ab. Während das Hauptprogramm 90 Frames lang Ganzzahlberechnungen ohne Nachfüllen ausführt, läuft die Musik weiter. „PHRASE COMPLETE / SILENT“ und „UNDERRUNS 0 / MATH OK“ bedeuten, dass die Wiedergabe beendet ist, kein Datenmangel auftrat und die Rechenergebnisse stimmen. Prüfen Sie in der Audioaufnahme die Impulsmelodie und ihre Begleitung, den Dreiecksbass und das Rauschen. Am Ende herrscht Stille. Das Bild zeigt die Steuerungsergebnisse; den Klang beurteilen Sie anhand der Audioaufnahme.

nes_audio_vblank_is_playing: NROM
NROM
NROM — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio_vblank.h:41

Deklarationshinweise im Original
Return 1 while the BGM consumer is enabled, including a recoverable queue underrun.

kitaqfc/lib/audio_vblank.c:101

c
u8 nes_audio_vblank_is_playing(void){return nav_active;}
nes_audio_vblank_underruns

Gibt die Anzahl der Datenmangelereignisse der Warteschlange zurück und hilft damit, den zeitlichen Spielraum zum Nachfüllen einzuschätzen.

Syntax

c
u8 nes_audio_vblank_underruns(void);

Rückgabewert

Gibt 0 bis 255 zurück und bleibt nach Erreichen von 255 auf diesem Wert. Gezählt werden Datenmangelereignisse, nicht alle wartenden Frames. init setzt den Zähler zurück; stop und ein Musikwechsel behalten ihn bei. Ein regulärer Abschlussdatensatz gilt nicht als Datenmangel.

Bedingungen und Grenzen

Binden Sie audio_vblank.h ein und nehmen Sie audio_vblank.c genau einmal in den Build auf. Der Compiler lässt sowohl den Standard-NMI-Handler als auch einen eigenen NMI-Handler den Musik-Hook einmal aufrufen. Aktivieren Sie PPU-NMI. Die Hauptschleife ruft keine Musikaktualisierung auf.

Dieser Vierkanaltreiber ist auf NTSC abgestimmt: CH1=Impuls 1, CH2=Impuls 2, CH3=Dreieck und CH4=Rauschen, mit den Indizes 0 bis 3. DMC und Erweiterungsaudio werden nicht wiedergegeben. Verwenden Sie ihn nicht gleichzeitig mit direkten APU-Zugriffen, etwa den Effekten in audio.c. Es gibt weder eine PAL-Tonhöhentabelle noch eine PAL-Tempokorrektur.

Läuft die Dauer ab, ohne dass ein weiterer BGM-Datensatz vorliegt, verstummen die BGM-Noten. Nach Eingang neuer Daten geht es bei einer NMI weiter. Ein unabhängiger SFX läuft weiter. Gezählt werden Eintritte in den Datenmangel, nicht alle leeren Frames. Das Einreihen reiner HOLD-Werte stellt die vorherigen BGM-Noten nicht wieder her. Füllen Sie normalerweise pro Frame nach und halten Sie vor längeren Arbeiten ausreichend Wiedergabezeit in der Warteschlange bereit.

Anwendungsbeispiel

c
result[4]=nes_audio_vblank_underruns(); // Zero: queued time covered the busy section.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel spielt eine eigens komponierte vierkanalige Phrase einmal ab. Während das Hauptprogramm 90 Frames lang Ganzzahlberechnungen ohne Nachfüllen ausführt, läuft die Musik weiter. „PHRASE COMPLETE / SILENT“ und „UNDERRUNS 0 / MATH OK“ bedeuten, dass die Wiedergabe beendet ist, kein Datenmangel auftrat und die Rechenergebnisse stimmen. Prüfen Sie in der Audioaufnahme die Impulsmelodie und ihre Begleitung, den Dreiecksbass und das Rauschen. Am Ende herrscht Stille. Das Bild zeigt die Steuerungsergebnisse; den Klang beurteilen Sie anhand der Audioaufnahme.

nes_audio_vblank_underruns: NROM
NROM
NROM — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio_vblank.h:43

Deklarationshinweise im Original
Saturating count of starvation episodes, cleared by init; END is not starvation.

kitaqfc/lib/audio_vblank.c:102

c
u8 nes_audio_vblank_underruns(void){return nav_underruns;}
nes_audio_vblank_set_timbre

Legt Tastgrad oder Pegel für die nächste Note eines Kanals fest, ohne dessen aktuelle Note erneut auszulösen.

Syntax

c
u8 nes_audio_vblank_set_timbre(u8 channel,u8 control);

Parameter

channel

0=CH1 Impuls 1, 1=CH2 Impuls 2, 2=CH3 Dreieck, 3=CH4 Rauschen. Werte ab 4 werden abgewiesen.

control

Bei Impulskanälen wählen die Bits 7..6 den Tastgrad (0=12,5 %, 1=25 %, 2=50 %, 3=75 %); die Bits 3..0 legen die konstante Lautstärke von 0 bis 15 fest. Beim Rauschen dienen die Bits 3..0 normalerweise ebenfalls als konstante Lautstärke. Verknüpfen Sie den Wert per OR mit NES_AUDIO_NOISE_ENVELOPE (128), um diese Bits als Abklingperiode von 0 bis 15 zu verwenden: Die nächste Rauschnote beginnt bei Lautstärke 15 und klingt einmal ab. Größere Perioden sind langsamer; 15 dauert etwa eine Sekunde. Der Längenzähler des Rauschkanals lässt das Abklingen vollständig zu. Beim Dreieckskanal bedeutet null eine stumme nächste Note; jeder andere Wert macht sie hörbar.

Rückgabewert

Gibt für einen gültigen Kanal 1 zurück. Werte ab 4 ergeben 0, ohne Änderungen vorzunehmen.

Bedingungen und Grenzen

Binden Sie audio_vblank.h ein und nehmen Sie audio_vblank.c genau einmal in den Build auf. Der Compiler lässt sowohl den Standard-NMI-Handler als auch einen eigenen NMI-Handler den Musik-Hook einmal aufrufen. Aktivieren Sie PPU-NMI. Die Hauptschleife ruft keine Musikaktualisierung auf.

Dieser Vierkanaltreiber ist auf NTSC abgestimmt: CH1=Impuls 1, CH2=Impuls 2, CH3=Dreieck und CH4=Rauschen, mit den Indizes 0 bis 3. DMC und Erweiterungsaudio werden nicht wiedergegeben. Verwenden Sie ihn nicht gleichzeitig mit direkten APU-Zugriffen, etwa den Effekten in audio.c. Es gibt weder eine PAL-Tonhöhentabelle noch eine PAL-Tempokorrektur.

Anwendungsbeispiel

c
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.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Es ist keine Eingabe erforderlich. CH1 spielt BGM bei etwa 220 Hz, wechselt für 30 Frames zu einem SFX bei etwa 880 Hz und kehrt dann zur aktuellen BGM zurück. Nach einer stummen Pause von 30 Frames läuft die BGM weiter. Ein zweiter Effekt wird nach 15 Frames ausdrücklich abgebrochen. Abschließend klingt das CH4-Rauschen einmal langsam ab. COMPLETE / ALL CHANNELS OFF kennzeichnet das Ende. Prüfen Sie anhand der beigefügten Aufnahme die Tonhöhenwechsel, die stumme Pause und das Abklingen des Rauschens.

nes_audio_vblank_set_timbre: NROM
NROM
NROM — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio_vblank.h:50

Deklarationshinweise im Original
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

c
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

Pausiert BGM und SFX oder setzt beide fort, wobei ihre Wiedergabepositionen erhalten bleiben.

Syntax

c
void nes_audio_vblank_pause(u8 on);

Parameter

on

Ein Wert ungleich null pausiert, null setzt fort. Beim Pausieren werden die vier APU-Kanäle sofort deaktiviert.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Binden Sie audio_vblank.h ein und nehmen Sie audio_vblank.c genau einmal in den Build auf. Der Compiler lässt sowohl den Standard-NMI-Handler als auch einen eigenen NMI-Handler den Musik-Hook einmal aufrufen. Aktivieren Sie PPU-NMI. Die Hauptschleife ruft keine Musikaktualisierung auf.

Dieser Vierkanaltreiber ist auf NTSC abgestimmt: CH1=Impuls 1, CH2=Impuls 2, CH3=Dreieck und CH4=Rauschen, mit den Indizes 0 bis 3. DMC und Erweiterungsaudio werden nicht wiedergegeben. Verwenden Sie ihn nicht gleichzeitig mit direkten APU-Zugriffen, etwa den Effekten in audio.c. Es gibt weder eine PAL-Tonhöhentabelle noch eine PAL-Tempokorrektur.

Rufen Sie die Funktion aus dem Hauptprogramm auf. Die NMI verbraucht die kopierten SFX-Daten. Lassen Sie diese Bibliothek sowohl BGM als auch SFX verwalten und betreiben Sie keinen weiteren APU-Treiber gleichzeitig.

Während der Pause ändern sich weder BGM-Dauer und Warteschlangenposition noch SFX-Dauer und -Position. Das Hauptprogramm kann weiterhin nachfüllen. Die erste NMI nach dem Fortsetzen löst die aktuellen Noten erneut aus und führt den normalen Tick aus. Wellenformphase und ein bereits teilweise abgeklungener Hüllkurvenpegel werden nicht gespeichert. Das von is_playing gemeldete BGM-Aktivierungsflag bleibt unverändert. Null fordert auch bei bereits laufender Wiedergabe eine Wiederherstellung der Noten an; rufen Sie dies daher nicht in jedem Frame auf.

Anwendungsbeispiel

c
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.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Es ist keine Eingabe erforderlich. CH1 spielt BGM bei etwa 220 Hz, wechselt für 30 Frames zu einem SFX bei etwa 880 Hz und kehrt dann zur aktuellen BGM zurück. Nach einer stummen Pause von 30 Frames läuft die BGM weiter. Ein zweiter Effekt wird nach 15 Frames ausdrücklich abgebrochen. Abschließend klingt das CH4-Rauschen einmal langsam ab. COMPLETE / ALL CHANNELS OFF kennzeichnet das Ende. Prüfen Sie anhand der beigefügten Aufnahme die Tonhöhenwechsel, die stumme Pause und das Abklingen des Rauschens.

nes_audio_vblank_pause: NROM
NROM
NROM — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio_vblank.h:54

Deklarationshinweise im Original
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

c
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

Kopiert einen kurzen Effekt ins RAM und übernimmt ab der nächsten NMI vorübergehend die Ausgabe der ausgewählten Kanäle.

Syntax

c
u8 nes_audio_vblank_play_sfx(const u8* records,u8 count,u8 mask);

Parameter

records

Anfang der Fünf-Byte-Datensätze. Halten Sie count×5 Bytes bis zur Rückkehr des Aufrufs lesbar und eingeblendet. Nach dem Kopieren darf die Quelle wiederverwendet werden.

count

1 bis 7 Datensätze mit insgesamt höchstens 35 Bytes. Jede Dauer muss zwischen 1 und 255 liegen. SFX verwenden keine Abschlussdatensätze mit Dauer null, sondern enden nach den angegebenen Datensätzen.

mask

Die unteren vier Bits wählen die Kanäle: 1=CH1, 2=CH2, 4=CH3, 8=CH4. Verknüpfen Sie Bits per OR, um mehrere auszuwählen. Höhere Bits werden ignoriert; sind die unteren vier Bits null, wird die Maske abgewiesen.

Rückgabewert

Gibt nach dem Kopieren und Aktivieren des Effekts 1 zurück. Bei Nullzeiger, ungültiger Anzahl, fehlender Kanalauswahl, Dauer null oder ungültigen Ton- bzw. Rauschwerten wird 0 zurückgegeben. Ungültige Eingaben lassen den aktuellen Effekt unverändert. Werte nicht ausgewählter Kanäle werden ebenfalls geprüft.

Bedingungen und Grenzen

Binden Sie audio_vblank.h ein und nehmen Sie audio_vblank.c genau einmal in den Build auf. Der Compiler lässt sowohl den Standard-NMI-Handler als auch einen eigenen NMI-Handler den Musik-Hook einmal aufrufen. Aktivieren Sie PPU-NMI. Die Hauptschleife ruft keine Musikaktualisierung auf.

Dieser Vierkanaltreiber ist auf NTSC abgestimmt: CH1=Impuls 1, CH2=Impuls 2, CH3=Dreieck und CH4=Rauschen, mit den Indizes 0 bis 3. DMC und Erweiterungsaudio werden nicht wiedergegeben. Verwenden Sie ihn nicht gleichzeitig mit direkten APU-Zugriffen, etwa den Effekten in audio.c. Es gibt weder eine PAL-Tonhöhentabelle noch eine PAL-Tempokorrektur.

Rufen Sie die Funktion aus dem Hauptprogramm auf. Die NMI verbraucht die kopierten SFX-Daten. Lassen Sie diese Bibliothek sowohl BGM als auch SFX verwalten und betreiben Sie keinen weiteren APU-Treiber gleichzeitig.

Die BGM läuft im Hintergrund weiter. Nach dem Effekt geben die Kanäle wieder deren aktuelle Noten aus. Es gibt einen SFX-Stream; ein neuer Aufruf ersetzt ihn. HOLD/STOP entsprechen den BGM-Werten, aber die gehaltenen Noten eines Effekts beginnen im gestoppten Zustand. Ein anfängliches HOLD übernimmt daher keine BGM-Note. SFX können ohne BGM laufen. Ein während der Pause eingereihter Effekt wartet auf das Fortsetzen. Die Klangfarben werden mit der BGM geteilt.

Anwendungsbeispiel

c
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.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Es ist keine Eingabe erforderlich. CH1 spielt BGM bei etwa 220 Hz, wechselt für 30 Frames zu einem SFX bei etwa 880 Hz und kehrt dann zur aktuellen BGM zurück. Nach einer stummen Pause von 30 Frames läuft die BGM weiter. Ein zweiter Effekt wird nach 15 Frames ausdrücklich abgebrochen. Abschließend klingt das CH4-Rauschen einmal langsam ab. COMPLETE / ALL CHANNELS OFF kennzeichnet das Ende. Prüfen Sie anhand der beigefügten Aufnahme die Tonhöhenwechsel, die stumme Pause und das Abklingen des Rauschens.

nes_audio_vblank_play_sfx: NROM
NROM
NROM — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio_vblank.h:62

Deklarationshinweise im Original
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

c
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

Gibt die vom Effekt belegten Kanäle frei, damit die nächste NMI die aktuellen BGM-Noten wiederherstellt.

Syntax

c
void nes_audio_vblank_stop_sfx(void);

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Binden Sie audio_vblank.h ein und nehmen Sie audio_vblank.c genau einmal in den Build auf. Der Compiler lässt sowohl den Standard-NMI-Handler als auch einen eigenen NMI-Handler den Musik-Hook einmal aufrufen. Aktivieren Sie PPU-NMI. Die Hauptschleife ruft keine Musikaktualisierung auf.

Dieser Vierkanaltreiber ist auf NTSC abgestimmt: CH1=Impuls 1, CH2=Impuls 2, CH3=Dreieck und CH4=Rauschen, mit den Indizes 0 bis 3. DMC und Erweiterungsaudio werden nicht wiedergegeben. Verwenden Sie ihn nicht gleichzeitig mit direkten APU-Zugriffen, etwa den Effekten in audio.c. Es gibt weder eine PAL-Tonhöhentabelle noch eine PAL-Tempokorrektur.

Rufen Sie die Funktion aus dem Hauptprogramm auf. Die NMI verbraucht die kopierten SFX-Daten. Lassen Sie diese Bibliothek sowohl BGM als auch SFX verwalten und betreiben Sie keinen weiteren APU-Treiber gleichzeitig.

Dieser Aufruf schreibt keine APU-Register. BGM-Warteschlange, Position und Aktivierungszustand bleiben erhalten. Lief nur ein SFX, setzt die nächste NMI die Kanäle auf gestoppte Noten zurück. Während einer Pause wird die Änderung beim Fortsetzen wirksam. Verwenden Sie stop, um sofort stummzuschalten und beide Wiedergabepositionen zu verwerfen.

Anwendungsbeispiel

c
nes_audio_vblank_stop_sfx(); // Release effect ownership at the next NMI.
    // BGM continues at its current position; this does not restart the song.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Es ist keine Eingabe erforderlich. CH1 spielt BGM bei etwa 220 Hz, wechselt für 30 Frames zu einem SFX bei etwa 880 Hz und kehrt dann zur aktuellen BGM zurück. Nach einer stummen Pause von 30 Frames läuft die BGM weiter. Ein zweiter Effekt wird nach 15 Frames ausdrücklich abgebrochen. Abschließend klingt das CH4-Rauschen einmal langsam ab. COMPLETE / ALL CHANNELS OFF kennzeichnet das Ende. Prüfen Sie anhand der beigefügten Aufnahme die Tonhöhenwechsel, die stumme Pause und das Abklingen des Rauschens.

nes_audio_vblank_stop_sfx: NROM
NROM
NROM — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/audio_vblank.h:65

Deklarationshinweise im Original
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

c
void nes_audio_vblank_stop_sfx(void){nav_sfx_active=0;}

bank.h — Bankabhängiger Zugriff auf Code und Daten

Eine ROM-Bank ist ein Speicherblock des Moduls, der in den CPU-Adressraum eingeblendet wird. Verschiedene Banken können an derselben CPU-Adresse liegen; ein 16-Bit-Zeiger allein identifiziert Bankdaten deshalb nicht eindeutig. BankPtr ist ein gepackter Deskriptor aus drei Bytes: einem Bankbyte und einem Zwei-Byte-Zeiger. Er wird mit farptr_make erstellt und mit farptr_read8, farptr_read16 oder farptr_read gelesen.

Das FC-Beispiel verwendet logische MMC3-Banken: Bank 0 enthält gemeinsamen Code unter $C000–$FFFF, die gewählte 16-KiB-Bank wird unter $8000–$BFFF eingeblendet. Dies sind Banknummern des Compilers, nicht die rohen 8-KiB-Registerwerte des Mappers. Initialisieren Sie den Bibliothekszustand mit bank_switch. Auf FC ist far_call ein Makro für benannte Funktionsaufrufe; übergeben Sie die Funktionsbank, vorzugsweise mit __bankof ermittelt.

bank_get_current

Liefert die zuletzt von bank_switch gespeicherte Banknummer. Gelesen wird der Softwarezustand, nicht ein Register des Moduls.

Syntax

c
u8 bank_get_current(void);

Rückgabewert

Der zuletzt von bank_switch gespeicherte u8-Wert; vor der Initialisierung null.

Bedingungen und Grenzen

Der Bibliothekszustand beginnt bei null und erkennt die Startzuordnung des Moduls nicht. Initialisieren Sie ihn mit bank_switch. Direkte Intrinsics und Mapper-Schreibzugriffe aktualisieren diesen separaten Zustand nicht; bank_get_current kann die tatsächliche Hardwarezuordnung daher nicht prüfen.

Anwendungsbeispiel

c
starting_bank=bank_get_current(); // Last value recorded by bank_switch.
bank_expect(starting_bank==2,1);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Der anfängliche Aufruf bank_switch(2) speichert und wählt Bank 2. Ein späterer direkter Wechsel wählt Bank 1 und liest A1 aus home1, während bank_get_current weiterhin 2 meldet. Nach dem Zurückschalten liefert home2 wieder B2.

Das vollständige Programm zeigt Datenzugriffe über Bank und Nahadresse, bankübergreifende Callbacks und den Unterschied zwischen Bibliothekszustand und tatsächlicher Zuordnung. Alle Zahlen sind hexadezimal. BANK IN und BANK OUT müssen 02 zeigen, BYTE HEX D3, WORD HEX 5C7A sowie FAILED CHECKS und FIRST FAILURE jeweils 00. CGB und FC zeigen blaue Schrift, DMG schwarze.

CALL COUNT zeigt 02: Das Makro far_call und __farcall rufen den Callback jeweils einmal auf.

bank_get_current: MMC3
MMC3

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/bank.h:18

Deklarationshinweise im Original
Read this wrapper's bank shadow; arbitrary mapper writes do not update it.

kitaqfc/lib/bank.c:14

c
u8 bank_get_current(void)
{
    return kq_bank_current;
}
bank_switch

Speichert die angeforderte Bank in der Bibliothek und wählt sie anschließend über die zum Mapper passende PRG-Umschaltung des Compilers.

Syntax

c
void bank_switch(u8 bank);

Parameter

bank

Vorzeichenlose 8-Bit-ROM-Banknummer. Bei Aufrufen muss sie zur Funktionsplatzierung passen, bei Lesezugriffen wählt sie die Quelle. Verwenden Sie den gültigen Bereich des Modultyps.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Ein dauerhafter Bankwechsel darf weder den laufenden Code noch seine Rückkehradresse ausblenden. Legen Sie den Aufruf, gegebenenfalls bank_switch selbst und den anschließend ausgeführten Code wie im Beispiel in die gemeinsame beziehungsweise feste Bank 0.

Der Bibliothekszustand beginnt bei null und erkennt die Startzuordnung des Moduls nicht. Initialisieren Sie ihn mit bank_switch. Direkte Intrinsics und Mapper-Schreibzugriffe aktualisieren diesen separaten Zustand nicht; bank_get_current kann die tatsächliche Hardwarezuordnung daher nicht prüfen.

FC-Banknummern sind logische Nummern des Compilers. Null bezeichnet gemeinsames ROM, kein Umschaltziel; die Hilfsroutine setzt null auf Bank 1 um. Bei SUROM512 sind nur 1–30 gültig: Eine direkt an das Umschalt-Intrinsic übergebene Konstante außerhalb des Bereichs führt zu einem Buildfehler; ein ungültiger Laufzeitwert wählt 1 und setzt den Mapper-Fehlerzustand. Lesen Sie gemeinsames ROM direkt, statt Bank null anzufordern.

Anwendungsbeispiel

c
bank_switch(2); // Select the payload window and update library bookkeeping.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Der anfängliche Aufruf bank_switch(2) speichert und wählt Bank 2. Ein späterer direkter Wechsel wählt Bank 1 und liest A1 aus home1, während bank_get_current weiterhin 2 meldet. Nach dem Zurückschalten liefert home2 wieder B2.

Das vollständige Programm zeigt Datenzugriffe über Bank und Nahadresse, bankübergreifende Callbacks und den Unterschied zwischen Bibliothekszustand und tatsächlicher Zuordnung. Alle Zahlen sind hexadezimal. BANK IN und BANK OUT müssen 02 zeigen, BYTE HEX D3, WORD HEX 5C7A sowie FAILED CHECKS und FIRST FAILURE jeweils 00. CGB und FC zeigen blaue Schrift, DMG schwarze.

CALL COUNT zeigt 02: Das Makro far_call und __farcall rufen den Callback jeweils einmal auf.

bank_switch: MMC3
MMC3

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/bank.h:16

Deklarationshinweise im Original
Record the bank in the library shadow and invoke the mapper-aware compiler intrinsic.

kitaqfc/lib/bank.c:7

c
void bank_switch(u8 bank)
{
    kq_bank_current = bank;
    __bankswitch(bank);
}
far_call

Wird zu __farcall((bank), func) expandiert. Das Makro erhält das Ziel als für den Compiler sichtbaren Funktionsnamen; es ist kein indirekter Aufruf über einen Callback-Zeiger.

Syntax

c
#define far_call(bank, func) __farcall((bank), func)

Parameter

bank

Vorzeichenlose 8-Bit-ROM-Banknummer. Bei Aufrufen muss sie zur Funktionsplatzierung passen, bei Lesezugriffen wählt sie die Quelle. Verwenden Sie den gültigen Bereich des Modultyps.

func

Deklarierter Name einer Funktion ohne Parameter. Dieses Intrinsic für benannte Aufrufe akzeptiert keine Variable mit einer Funktionsadresse. Das Argument bank wird nicht als Callback-Parameter weitergereicht.

Rückgabewert

Der Ergebnistyp richtet sich nach der aufgerufenen Funktion. Ein void-Callback liefert keinen Wert; u8- und u16-Callbacks liefern ihren Skalarwert. Das gezeigte Beispiel verwendet void-Callbacks.

Bedingungen und Grenzen

Diese Aufrufe reichen keine Benutzerargumente weiter und machen den Callback nicht interrupt-reentrant. Verwalten Sie seine Daten, seinen Stack und seine Interruptnutzung korrekt. Die Bankwiederherstellung ist mit verschachtelten und wiederholten Aufrufen geprüft; reale Hardware und beliebige Interruptverschachtelungen deckt dieses Beispiel nicht ab.

FC-Banknummern sind logische Nummern des Compilers. Null bezeichnet gemeinsames ROM, kein Umschaltziel; die Hilfsroutine setzt null auf Bank 1 um. Bei SUROM512 sind nur 1–30 gültig: Eine direkt an das Umschalt-Intrinsic übergebene Konstante außerhalb des Bereichs führt zu einem Buildfehler; ein ungültiger Laufzeitwert wählt 1 und setzt den Mapper-Fehlerzustand. Lesen Sie gemeinsames ROM direkt, statt Bank null anzufordern.

Anwendungsbeispiel

c
far_call(3,callback); // No arguments; callback reads payload[0] in bank 3.
bank_expect(callback_count==1 && callback_byte==0xD3,15);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

An dieser Stelle des vollständigen Programms erhöht far_call den Wert von callback_count auf 1. Der Callback liest D3 aus Bank 3. Ein späterer Nahzugriff auf home2 mit Ergebnis B2 bestätigt die Rückkehr bei eingeblendeter Bank 2.

Das vollständige Programm zeigt Datenzugriffe über Bank und Nahadresse, bankübergreifende Callbacks und den Unterschied zwischen Bibliothekszustand und tatsächlicher Zuordnung. Alle Zahlen sind hexadezimal. BANK IN und BANK OUT müssen 02 zeigen, BYTE HEX D3, WORD HEX 5C7A sowie FAILED CHECKS und FIRST FAILURE jeweils 00. CGB und FC zeigen blaue Schrift, DMG schwarze.

CALL COUNT zeigt 02: Das Makro far_call und __farcall rufen den Callback jeweils einmal auf.

far_call: MMC3
MMC3

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/bank.h:36

far_data_read

Kopiert über das Fernspeicher-Intrinsic len Bytes aus der angegebenen ROM-Bank in den RAM-Puffer des Aufrufers. Vor der Rückkehr wird die vorherige Bank wiederhergestellt.

Syntax

c
void far_data_read(u8 bank, const void* addr, void* dst, u16 len);

Parameter

bank

Vorzeichenlose 8-Bit-ROM-Banknummer. Bei Aufrufen muss sie zur Funktionsplatzierung passen, bei Lesezugriffen wählt sie die Quelle. Verwenden Sie den gültigen Bereich des Modultyps.

addr

Nahzeiger auf lesbare Bytes in der gewählten ROM-Bank. Er enthält keine Banknummer.

dst

Ziel in beschreibbarem Speicher mit genügend Platz für alle kopierten Byte. Abgesehen von einem Transfer mit Länge null erfolgt keine Prüfung auf Nullzeiger oder ungültige Zieladressen.

len

Byteanzahl, 0–65535. Bei null wird kein Speicher kopiert; Bankauswahl und Wiederherstellung werden trotzdem ausgeführt.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Der gesamte Quellbereich muss in der vorgesehenen ROM-Zuordnung lesbar und der gesamte Zielbereich beschreibbar sein. Die Kopie schaltet am Fensterende nicht automatisch zur nächsten Bank, behandelt Überlappungen nicht wie memmove und steuert keine sicheren VRAM-Schreibzeitpunkte. Verwenden Sie für VRAM die Grafikübertragungs-APIs.

Fernlesezugriffe und Kopien arbeiten synchron und nutzen gemeinsamen Arbeitsspeicher des Compilers. Ein Interrupt darf währenddessen keinen weiteren Banktransfer über denselben Speicher ausführen. Auf GB nutzt die Kopierhilfe außerdem einen gemeinsamen HRAM-Platz für die gespeicherte Bank. Das Beispiel führt die Operationen aus festem Code ohne konkurrierenden Transfer-Handler aus.

FC-Banknummern sind logische Nummern des Compilers. Null bezeichnet gemeinsames ROM, kein Umschaltziel; die Hilfsroutine setzt null auf Bank 1 um. Bei SUROM512 sind nur 1–30 gültig: Eine direkt an das Umschalt-Intrinsic übergebene Konstante außerhalb des Bereichs führt zu einem Buildfehler; ein ungültiger Laufzeitwert wählt 1 und setzt den Mapper-Fehlerzustand. Lesen Sie gemeinsames ROM direkt, statt Bank null anzufordern.

Anwendungsbeispiel

c
far_data_read(3,payload,buffer,4); // Copy into four writable RAM bytes.
bank_expect(buffer[0]==0xD3 && buffer[1]==0x7A && buffer[2]==0x5C && buffer[3]==0x96,7);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieser Ausschnitt kopiert mit far_data_read 4 Bytes und prüft den Puffer gegen D3 7A 5C 96. Quelldeskriptor oder Quellzeiger des Aufrufers bleiben erhalten; das vollständige Programm prüft zusätzlich eine Kopie der Länge null und die Bankwiederherstellung.

Das vollständige Programm zeigt Datenzugriffe über Bank und Nahadresse, bankübergreifende Callbacks und den Unterschied zwischen Bibliothekszustand und tatsächlicher Zuordnung. Alle Zahlen sind hexadezimal. BANK IN und BANK OUT müssen 02 zeigen, BYTE HEX D3, WORD HEX 5C7A sowie FAILED CHECKS und FIRST FAILURE jeweils 00. CGB und FC zeigen blaue Schrift, DMG schwarze.

CALL COUNT zeigt 02: Das Makro far_call und __farcall rufen den Callback jeweils einmal auf.

far_data_read: MMC3
MMC3

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/bank.h:24

Deklarationshinweise im Original
Copy len bytes from banked ROM to caller-owned writable storage.

kitaqfc/lib/bank.c:32

c
void far_data_read(u8 bank, const void* addr, void* dst, u16 len)
{
    __far_memcpy((u8*)dst, bank, (u16)addr, len);
}
far_data_read16

Liest mit __farpeek16 zwei aufeinanderfolgende Bytes als Little-Endian-Wort. Das erste Byte bildet die unteren acht Bits.

Syntax

c
u16 far_data_read16(u8 bank, const void* addr);

Parameter

bank

Vorzeichenlose 8-Bit-ROM-Banknummer. Bei Aufrufen muss sie zur Funktionsplatzierung passen, bei Lesezugriffen wählt sie die Quelle. Verwenden Sie den gültigen Bereich des Modultyps.

addr

Nahzeiger auf lesbare Bytes in der gewählten ROM-Bank. Er enthält keine Banknummer.

Rückgabewert

Das gelesene Little-Endian-Wort als u16 (0–65535).

Bedingungen und Grenzen

Das gesamte Byte oder Wort muss in der gewählten CPU-Zuordnung lesbar sein. Zeiger werden nicht geprüft, Adressen nicht begrenzt und Fenstergrenzen lösen keinen automatischen Wechsel zur nächsten ROM-Bank aus. Ein Wort benötigt zwei gültige aufeinanderfolgende Bytes.

Fernlesezugriffe und Kopien arbeiten synchron und nutzen gemeinsamen Arbeitsspeicher des Compilers. Ein Interrupt darf währenddessen keinen weiteren Banktransfer über denselben Speicher ausführen. Auf GB nutzt die Kopierhilfe außerdem einen gemeinsamen HRAM-Platz für die gespeicherte Bank. Das Beispiel führt die Operationen aus festem Code ohne konkurrierenden Transfer-Handler aus.

FC-Banknummern sind logische Nummern des Compilers. Null bezeichnet gemeinsames ROM, kein Umschaltziel; die Hilfsroutine setzt null auf Bank 1 um. Bei SUROM512 sind nur 1–30 gültig: Eine direkt an das Umschalt-Intrinsic übergebene Konstante außerhalb des Bereichs führt zu einem Buildfehler; ein ungültiger Laufzeitwert wählt 1 und setzt den Mapper-Fehlerzustand. Lesen Sie gemeinsames ROM direkt, statt Bank null anzufordern.

Anwendungsbeispiel

c
word_value=far_data_read16(3,payload+1); // Little-endian 7A 5C -> 0x5C7A.
bank_expect(word_value==0x5C7A,6);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieser Ausschnitt liest mit far_data_read16 den Ausdruck payload+1 in Bank 3 und prüft 5C7A. Das vollständige Programm bestätigt durch einen Nahzugriff auf home2 außerdem die Wiederherstellung von Bank 2.

Das vollständige Programm zeigt Datenzugriffe über Bank und Nahadresse, bankübergreifende Callbacks und den Unterschied zwischen Bibliothekszustand und tatsächlicher Zuordnung. Alle Zahlen sind hexadezimal. BANK IN und BANK OUT müssen 02 zeigen, BYTE HEX D3, WORD HEX 5C7A sowie FAILED CHECKS und FIRST FAILURE jeweils 00. CGB und FC zeigen blaue Schrift, DMG schwarze.

CALL COUNT zeigt 02: Das Makro far_call und __farcall rufen den Callback jeweils einmal auf.

far_data_read16: MMC3
MMC3

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/bank.h:22

Deklarationshinweise im Original
Read a 16-bit value through the bank-aware compiler intrinsic.

kitaqfc/lib/bank.c:26

c
u16 far_data_read16(u8 bank, const void* addr)
{
    return __farpeek16(bank, (u16)addr);
}
far_data_read8

Liest über __farpeek8 ein Byte aus der angegebenen ROM-Bank und Adresse, stellt die vorherige Bank wieder her und liefert den Wert.

Syntax

c
u8 far_data_read8(u8 bank, const void* addr);

Parameter

bank

Vorzeichenlose 8-Bit-ROM-Banknummer. Bei Aufrufen muss sie zur Funktionsplatzierung passen, bei Lesezugriffen wählt sie die Quelle. Verwenden Sie den gültigen Bereich des Modultyps.

addr

Nahzeiger auf lesbare Bytes in der gewählten ROM-Bank. Er enthält keine Banknummer.

Rückgabewert

Das gelesene Byte als u8 (0–255).

Bedingungen und Grenzen

Das gesamte Byte oder Wort muss in der gewählten CPU-Zuordnung lesbar sein. Zeiger werden nicht geprüft, Adressen nicht begrenzt und Fenstergrenzen lösen keinen automatischen Wechsel zur nächsten ROM-Bank aus. Ein Wort benötigt zwei gültige aufeinanderfolgende Bytes.

Fernlesezugriffe und Kopien arbeiten synchron und nutzen gemeinsamen Arbeitsspeicher des Compilers. Ein Interrupt darf währenddessen keinen weiteren Banktransfer über denselben Speicher ausführen. Auf GB nutzt die Kopierhilfe außerdem einen gemeinsamen HRAM-Platz für die gespeicherte Bank. Das Beispiel führt die Operationen aus festem Code ohne konkurrierenden Transfer-Handler aus.

FC-Banknummern sind logische Nummern des Compilers. Null bezeichnet gemeinsames ROM, kein Umschaltziel; die Hilfsroutine setzt null auf Bank 1 um. Bei SUROM512 sind nur 1–30 gültig: Eine direkt an das Umschalt-Intrinsic übergebene Konstante außerhalb des Bereichs führt zu einem Buildfehler; ein ungültiger Laufzeitwert wählt 1 und setzt den Mapper-Fehlerzustand. Lesen Sie gemeinsames ROM direkt, statt Bank null anzufordern.

Anwendungsbeispiel

c
byte_value=far_data_read8(3,payload); // One byte: 0xD3.
bank_expect(byte_value==0xD3,5);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieser Ausschnitt liest mit far_data_read8 den Ausdruck payload in Bank 3 und prüft D3. Das vollständige Programm bestätigt durch einen Nahzugriff auf home2 außerdem die Wiederherstellung von Bank 2.

Das vollständige Programm zeigt Datenzugriffe über Bank und Nahadresse, bankübergreifende Callbacks und den Unterschied zwischen Bibliothekszustand und tatsächlicher Zuordnung. Alle Zahlen sind hexadezimal. BANK IN und BANK OUT müssen 02 zeigen, BYTE HEX D3, WORD HEX 5C7A sowie FAILED CHECKS und FIRST FAILURE jeweils 00. CGB und FC zeigen blaue Schrift, DMG schwarze.

CALL COUNT zeigt 02: Das Makro far_call und __farcall rufen den Callback jeweils einmal auf.

far_data_read8: MMC3
MMC3

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/bank.h:20

Deklarationshinweise im Original
Read one byte from an explicit ROM bank and 16-bit CPU address.

kitaqfc/lib/bank.c:20

c
u8 far_data_read8(u8 bank, const void* addr)
{
    return __farpeek8(bank, (u16)addr);
}
farptr_make

Speichert ein Bankbyte und einen CPU-sichtbaren Zeiger im BankPtr des Aufrufers. Dabei entsteht nur ein Deskriptor; weder wird die Bank umgeschaltet noch werden die referenzierten Daten gelesen.

Syntax

c
void farptr_make(BankPtr* out, u8 bank, const u8* ptr);

Parameter

out

Zeiger auf beschreibbaren Speicher für einen drei Byte großen BankPtr. Ein Nullzeiger für out führt zu keiner Schreiboperation.

bank

Vorzeichenlose 8-Bit-ROM-Banknummer. Bei Aufrufen muss sie zur Funktionsplatzierung passen, bei Lesezugriffen wählt sie die Quelle. Verwenden Sie den gültigen Bereich des Modultyps.

ptr

Im Deskriptor zu speichernde CPU-sichtbare 16-Bit-Adresse. Sie wird unverändert übernommen; ihre Gültigkeit in der gewählten Bank wird nicht geprüft.

Rückgabewert

Keiner (void).

Anwendungsbeispiel

c
farptr_make(&pointer,3,payload+1); // Store a bank and address; do not read ROM.
bank_expect(pointer.bank==3 && pointer.ptr==payload+1,8);
farptr_make(0,1,home1); // A null destination is ignored.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Der Deskriptor erhält Bank 3 und payload+1. Seine Leseoperationen liefern 7A, 5C7A und die drei Bytes 7A 5C 96. Der Aufruf mit Nullausgabe darf keinen Zustand ändern.

Das vollständige Programm zeigt Datenzugriffe über Bank und Nahadresse, bankübergreifende Callbacks und den Unterschied zwischen Bibliothekszustand und tatsächlicher Zuordnung. Alle Zahlen sind hexadezimal. BANK IN und BANK OUT müssen 02 zeigen, BYTE HEX D3, WORD HEX 5C7A sowie FAILED CHECKS und FIRST FAILURE jeweils 00. CGB und FC zeigen blaue Schrift, DMG schwarze.

CALL COUNT zeigt 02: Das Makro far_call und __farcall rufen den Callback jeweils einmal auf.

farptr_make: MMC3
MMC3

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/bank.h:26

Deklarationshinweise im Original
Store a bank/address pair without reading memory; null output is ignored.

kitaqfc/lib/bank.c:38

c
void farptr_make(BankPtr* out, u8 bank, const u8* ptr)
{
    if (out == 0) return;
    out->bank = bank;
    out->ptr = ptr;
}
farptr_read

Kopiert len Bytes von einem BankPtr in beschreibbaren RAM. Da der Deskriptor als Wert übergeben wird, zeigt der Zeiger des Aufrufers weiterhin auf den Anfang der Quelle.

Syntax

c
void farptr_read(BankPtr ptr, void* dst, u16 len);

Parameter

ptr

Ein BankPtr-Wert mit den Feldern bank und ptr. Übergeben Sie den Deskriptor selbst, nicht seine Adresse. Der Deskriptor des Aufrufers bleibt unverändert.

dst

Ziel in beschreibbarem Speicher mit genügend Platz für alle kopierten Byte. Abgesehen von einem Transfer mit Länge null erfolgt keine Prüfung auf Nullzeiger oder ungültige Zieladressen.

len

Byteanzahl, 0–65535. Bei null wird kein Speicher kopiert; Bankauswahl und Wiederherstellung werden trotzdem ausgeführt.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Der gesamte Quellbereich muss in der vorgesehenen ROM-Zuordnung lesbar und der gesamte Zielbereich beschreibbar sein. Die Kopie schaltet am Fensterende nicht automatisch zur nächsten Bank, behandelt Überlappungen nicht wie memmove und steuert keine sicheren VRAM-Schreibzeitpunkte. Verwenden Sie für VRAM die Grafikübertragungs-APIs.

Fernlesezugriffe und Kopien arbeiten synchron und nutzen gemeinsamen Arbeitsspeicher des Compilers. Ein Interrupt darf währenddessen keinen weiteren Banktransfer über denselben Speicher ausführen. Auf GB nutzt die Kopierhilfe außerdem einen gemeinsamen HRAM-Platz für die gespeicherte Bank. Das Beispiel führt die Operationen aus festem Code ohne konkurrierenden Transfer-Handler aus.

FC-Banknummern sind logische Nummern des Compilers. Null bezeichnet gemeinsames ROM, kein Umschaltziel; die Hilfsroutine setzt null auf Bank 1 um. Bei SUROM512 sind nur 1–30 gültig: Eine direkt an das Umschalt-Intrinsic übergebene Konstante außerhalb des Bereichs führt zu einem Buildfehler; ein ungültiger Laufzeitwert wählt 1 und setzt den Mapper-Fehlerzustand. Lesen Sie gemeinsames ROM direkt, statt Bank null anzufordern.

Anwendungsbeispiel

c
farptr_read(pointer,buffer,3);
bank_expect(buffer[0]==0x7A && buffer[1]==0x5C && buffer[2]==0x96,11);
bank_expect(pointer.bank==3 && pointer.ptr==payload+1,23);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieser Ausschnitt kopiert mit farptr_read 3 Bytes und prüft den Puffer gegen 7A 5C 96. Quelldeskriptor oder Quellzeiger des Aufrufers bleiben erhalten; das vollständige Programm prüft zusätzlich eine Kopie der Länge null und die Bankwiederherstellung.

Das vollständige Programm zeigt Datenzugriffe über Bank und Nahadresse, bankübergreifende Callbacks und den Unterschied zwischen Bibliothekszustand und tatsächlicher Zuordnung. Alle Zahlen sind hexadezimal. BANK IN und BANK OUT müssen 02 zeigen, BYTE HEX D3, WORD HEX 5C7A sowie FAILED CHECKS und FIRST FAILURE jeweils 00. CGB und FC zeigen blaue Schrift, DMG schwarze.

CALL COUNT zeigt 02: Das Makro far_call und __farcall rufen den Callback jeweils einmal auf.

farptr_read: MMC3
MMC3

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/bank.h:32

Deklarationshinweise im Original
Copy len bytes from a far pointer; the caller provides a sufficiently large destination.

kitaqfc/lib/bank.c:58

c
void farptr_read(BankPtr ptr, void* dst, u16 len)
{
    __far_memcpy((u8*)dst, ptr.bank, (u16)ptr.ptr, len);
}
farptr_read16

Liest ein Little-Endian-Wort aus Bank und Adresse eines BankPtr. Der Deskriptor wird als Wert übergeben; sein Zeiger wird nicht weitergesetzt.

Syntax

c
u16 farptr_read16(BankPtr ptr);

Parameter

ptr

Ein BankPtr-Wert mit den Feldern bank und ptr. Übergeben Sie den Deskriptor selbst, nicht seine Adresse. Der Deskriptor des Aufrufers bleibt unverändert.

Rückgabewert

Das gelesene Little-Endian-Wort als u16 (0–65535).

Bedingungen und Grenzen

Das gesamte Byte oder Wort muss in der gewählten CPU-Zuordnung lesbar sein. Zeiger werden nicht geprüft, Adressen nicht begrenzt und Fenstergrenzen lösen keinen automatischen Wechsel zur nächsten ROM-Bank aus. Ein Wort benötigt zwei gültige aufeinanderfolgende Bytes.

Fernlesezugriffe und Kopien arbeiten synchron und nutzen gemeinsamen Arbeitsspeicher des Compilers. Ein Interrupt darf währenddessen keinen weiteren Banktransfer über denselben Speicher ausführen. Auf GB nutzt die Kopierhilfe außerdem einen gemeinsamen HRAM-Platz für die gespeicherte Bank. Das Beispiel führt die Operationen aus festem Code ohne konkurrierenden Transfer-Handler aus.

FC-Banknummern sind logische Nummern des Compilers. Null bezeichnet gemeinsames ROM, kein Umschaltziel; die Hilfsroutine setzt null auf Bank 1 um. Bei SUROM512 sind nur 1–30 gültig: Eine direkt an das Umschalt-Intrinsic übergebene Konstante außerhalb des Bereichs führt zu einem Buildfehler; ein ungültiger Laufzeitwert wählt 1 und setzt den Mapper-Fehlerzustand. Lesen Sie gemeinsames ROM direkt, statt Bank null anzufordern.

Anwendungsbeispiel

c
bank_expect(farptr_read16(pointer)==0x5C7A,10);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieser Ausschnitt liest mit farptr_read16 den Ausdruck pointer.ptr in Bank 3 und prüft 5C7A. Das vollständige Programm bestätigt durch einen Nahzugriff auf home2 außerdem die Wiederherstellung von Bank 2.

Das vollständige Programm zeigt Datenzugriffe über Bank und Nahadresse, bankübergreifende Callbacks und den Unterschied zwischen Bibliothekszustand und tatsächlicher Zuordnung. Alle Zahlen sind hexadezimal. BANK IN und BANK OUT müssen 02 zeigen, BYTE HEX D3, WORD HEX 5C7A sowie FAILED CHECKS und FIRST FAILURE jeweils 00. CGB und FC zeigen blaue Schrift, DMG schwarze.

CALL COUNT zeigt 02: Das Makro far_call und __farcall rufen den Callback jeweils einmal auf.

farptr_read16: MMC3
MMC3

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/bank.h:30

Deklarationshinweise im Original
Read a 16-bit value using both components of the far pointer.

kitaqfc/lib/bank.c:52

c
u16 farptr_read16(BankPtr ptr)
{
    return __farpeek16(ptr.bank, (u16)ptr.ptr);
}
farptr_read8

Liest ein Byte über beide Felder eines als Wert übergebenen BankPtr. Der Deskriptor ergänzt die Banknummer, die einem gewöhnlichen Nahzeiger fehlt.

Syntax

c
u8 farptr_read8(BankPtr ptr);

Parameter

ptr

Ein BankPtr-Wert mit den Feldern bank und ptr. Übergeben Sie den Deskriptor selbst, nicht seine Adresse. Der Deskriptor des Aufrufers bleibt unverändert.

Rückgabewert

Das gelesene Byte als u8 (0–255).

Bedingungen und Grenzen

Das gesamte Byte oder Wort muss in der gewählten CPU-Zuordnung lesbar sein. Zeiger werden nicht geprüft, Adressen nicht begrenzt und Fenstergrenzen lösen keinen automatischen Wechsel zur nächsten ROM-Bank aus. Ein Wort benötigt zwei gültige aufeinanderfolgende Bytes.

Fernlesezugriffe und Kopien arbeiten synchron und nutzen gemeinsamen Arbeitsspeicher des Compilers. Ein Interrupt darf währenddessen keinen weiteren Banktransfer über denselben Speicher ausführen. Auf GB nutzt die Kopierhilfe außerdem einen gemeinsamen HRAM-Platz für die gespeicherte Bank. Das Beispiel führt die Operationen aus festem Code ohne konkurrierenden Transfer-Handler aus.

FC-Banknummern sind logische Nummern des Compilers. Null bezeichnet gemeinsames ROM, kein Umschaltziel; die Hilfsroutine setzt null auf Bank 1 um. Bei SUROM512 sind nur 1–30 gültig: Eine direkt an das Umschalt-Intrinsic übergebene Konstante außerhalb des Bereichs führt zu einem Buildfehler; ein ungültiger Laufzeitwert wählt 1 und setzt den Mapper-Fehlerzustand. Lesen Sie gemeinsames ROM direkt, statt Bank null anzufordern.

Anwendungsbeispiel

c
bank_expect(farptr_read8(pointer)==0x7A,9);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieser Ausschnitt liest mit farptr_read8 den Ausdruck pointer.ptr in Bank 3 und prüft 7A. Das vollständige Programm bestätigt durch einen Nahzugriff auf home2 außerdem die Wiederherstellung von Bank 2.

Das vollständige Programm zeigt Datenzugriffe über Bank und Nahadresse, bankübergreifende Callbacks und den Unterschied zwischen Bibliothekszustand und tatsächlicher Zuordnung. Alle Zahlen sind hexadezimal. BANK IN und BANK OUT müssen 02 zeigen, BYTE HEX D3, WORD HEX 5C7A sowie FAILED CHECKS und FIRST FAILURE jeweils 00. CGB und FC zeigen blaue Schrift, DMG schwarze.

CALL COUNT zeigt 02: Das Makro far_call und __farcall rufen den Callback jeweils einmal auf.

farptr_read8: MMC3
MMC3

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/bank.h:28

Deklarationshinweise im Original
Read one byte using both the bank and address of the supplied far pointer.

kitaqfc/lib/bank.c:46

c
u8 farptr_read8(BankPtr ptr)
{
    return __farpeek8(ptr.bank, (u16)ptr.ptr);
}

chain.h — Ringpuffer für Positionsverläufe

Verwenden Sie ChainBody für gegliederte Schlangen oder Seile und Chain für einen aufgezeichneten Positionsverlauf. Jedes Körpergelenk speichert seine aktuelle Position und eine von 16 Richtungen; Biegungen wandern pro Aktualisierung um ein Gelenk nach hinten. Die Körperoperationen unterstützen umlaufende Spielfelder, Wachstum durch Duplizieren des Schwanzendes und Korrekturen von bis zu zwei Pixeln je Achse.

chain_wrap_delta

Berechnet die kürzeste vorzeichenbehaftete Verschiebung von der aktuellen Position zu einem Ziel auf einer Achse mit verbundenen Enden. Verwenden Sie dies für Verfolgung oder Distanzvergleiche über einen Feldrand hinweg.

Syntax

c
s16 chain_wrap_delta(u8 target, u8 current, u16 size);

Parameter

target

Zielkoordinate, 0..size−1.

current

Aktuelle Koordinate, 0..size−1.

size

Länge der umlaufenden Achse, 1..256: Breite für X, Höhe für Y. Das Argument hat 16 Bit, damit 256 darstellbar ist.

Rückgabewert

Gibt die kürzeste Verschiebung als s16 zurück: positiv zu steigenden, negativ zu fallenden Koordinaten, null bei gleicher Position. Gültige Eingaben ergeben −128..+128. Auf dem Bildschirm sind Verschiebungen nach rechts und unten positiv.

Bedingungen und Grenzen

Binden Sie chain.h ein und kompilieren Sie chain.c genau einmal. Chain oder ChainBody müssen nicht initialisiert werden. Die Funktion berechnet nur eine Verschiebung und ändert weder Koordinatenarrays noch Gelenkanzahl oder Bildschirm.

Die Funktion prüft und normalisiert Eingaben nicht. Übergeben Sie weder size=0 noch size>256 noch Koordinaten ab size. Bilden Sie Koordinaten aus einem größeren System vor dem Aufruf umlaufend auf 0..size−1 ab.

Bei gleich langen Wegen bleibt das Vorzeichen der direkten Differenz target−current erhalten. Bei size=160 liefert 0→80 den Wert +80 und 80→0 den Wert −80. Bei size=1 ist null die einzige gültige Koordinate und auch das Ergebnis ist null.

Anwendungsbeispiel

c
distances[0]=chain_wrap_delta(1,159,160);   // +2: cross the right edge.
    distances[1]=chain_wrap_delta(159,1,160);   // -2: cross the left edge.
    distances[2]=chain_wrap_delta(80,0,160);    // +80: keep the direct sign.
    distances[3]=chain_wrap_delta(0,80,160);    // -80: same-length routes.
    distances[4]=chain_wrap_delta(0,0,1);       // 0: the only valid position.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieses Beispiel zeigt umlaufende Koordinaten. Jeder Pfeil führt von der aktuellen Position zum Ziel. Angezeigt werden +02/−02 beim Überqueren eines Rands bei Breite 160, +80/−80 für ein halbes Feld und +00 bei Breite 1. Die führende Null ist dezimale Stellenfüllung. Das Beispiel zeichnet und bewegt kein Objekt.

chain_wrap_delta: NTSC
NTSC

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/chain.h:39

Deklarationshinweise im Original
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

c
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

Verknüpft drei Gelenkarrays des aufrufenden Codes und setzt die Gelenkanzahl auf null, ohne Speicher zu reservieren.

Syntax

c
u8 chain_body_init(ChainBody* body, u8* x, u8* y, u8* heading, u8 capacity, u16 width, u16 height);

Parameter

body

Ziel-ChainBody; null wird ignoriert. Übergeben Sie außer bei der Initialisierung einen initialisierten Zustand.

x

Array der Gelenk-X-Koordinaten.

y

Array der Gelenk-Y-Koordinaten.

heading

Array der Gelenkrichtungen.

capacity

Reservierte Array-Länge, 1..255.

width

Breite des umlaufenden Felds, 1..256.

height

Höhe des umlaufenden Felds, 1..256.

Rückgabewert

Gibt bei Erfolg 1 zurück, bei ungültigen Argumenten 0. Ein Fehlschlag bei nicht leerem Körperzeiger setzt capacity und count auf null und deaktiviert Aktualisierungen.

Bedingungen und Grenzen

Binden Sie chain.h ein und kompilieren Sie chain.c genau einmal. ChainBody speichert die aktuelle Position und Richtung jedes Gelenks. Es ist ein eigener Zustandstyp, getrennt vom Positionsverlaufsring Chain.

Stellen Sie drei getrennte beschreibbare Arrays x, y und heading mit je capacity Bytes bereit und halten Sie sie während der Körpernutzung gültig. Index null ist der Kopf und in count enthalten. Ändern Sie nach der Initialisierung weder Speicherzeiger noch Kapazität oder Feldabmessungen.

Richtungen verwenden 16 Sektoren im Uhrzeigersinn: 0=rechts, 4=unten, 8=links, 12=oben. Nur die unteren vier Eingabebits werden verwendet. Bildschirmkoordinaten steigen nach rechts und unten; jede Abmessung beträgt 1..256 Pixel.

Anwendungsbeispiel

c
chain_body_init(&body,joint_x,joint_y,joint_heading,8,160,144);
    // Eight caller-owned slots, including the head, on a wrapped 160x144 field.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Bild zeigt oben einen geraden Körper, in der Mitte eine Aktualisierung nach einer Abwärtskurve und unten vier Aktualisierungen danach. Koordinaten werden in doppelter logischer Größe gezeichnet. Die Biegung wandert vom Kopf rechts nach hinten. CGB und FC zeigen Kopf rot, Körper blau und Schwanz grün; DMG verwendet Schwarz. Vier Ausgleichsaktualisierungen trennen das duplizierte Schwanzende nach dem Wachstum. Es sind drei Ansichten derselben acht Gelenke, kein Körper mit 24 Gelenken.

chain_body_init: NTSC — Das Bild zeigt oben einen geraden Körper, in der Mitte eine Aktualisierung nach einer Abwärtskurve und unten vier Aktualisierungen danach. Koordinaten werden in doppelter logischer Größe gezeichnet. Die Biegung wandert vom Kopf rechts nach hinten. CGB und FC zeigen Kopf rot, Körper blau und Schwanz grün; DMG verwendet Schwarz. Vier Ausgleichsaktualisierungen trennen das duplizierte Schwanzende nach dem Wachstum. Es sind drei Ansichten derselben acht Gelenke, kein Körper mit 24 Gelenken.
NTSC — Das Bild zeigt oben einen geraden Körper, in der Mitte eine Aktualisierung nach einer Abwärtskurve und unten vier Aktualisierungen danach. Koordinaten werden in doppelter logischer Größe gezeichnet. Die Biegung wandert vom Kopf rechts nach hinten. CGB und FC zeigen Kopf rot, Körper blau und Schwanz grün; DMG verwendet Schwarz. Vier Ausgleichsaktualisierungen trennen das duplizierte Schwanzende nach dem Wachstum. Es sind drei Ansichten derselben acht Gelenke, kein Körper mit 24 Gelenken.

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/chain.h:57

Deklarationshinweise im Original
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

c
u8 chain_body_init(ChainBody* body, u8* x, u8* y, u8* heading, u8 capacity, u16 width, u16 height)
{
    if (body == 0) return 0;
    body->x = x;
    body->y = y;
    body->heading = heading;
    body->count = 0;
    body->capacity = 0;
    body->width = width;
    body->height = height;
    if (x == 0 || y == 0 || heading == 0 || capacity == 0) return 0;
    if (width == 0 || width > 256 || height == 0 || height > 256) return 0;
    body->capacity = capacity;
    return 1;
}
chain_body_reset

Erzeugt eine gerade Anfangsanordnung, indem Gelenke hinter dem angegebenen Kopf platziert werden.

Syntax

c
u8 chain_body_reset(ChainBody* body, u8 count, u8 head_x, u8 head_y, u8 heading);

Parameter

body

Ziel-ChainBody; null wird ignoriert. Übergeben Sie außer bei der Initialisierung einen initialisierten Zustand.

count

Gelenkanzahl einschließlich Kopf, 1..capacity.

head_x

Kopf-X-Koordinate, auf die Feldbreite umlaufend abgebildet.

head_y

Kopf-Y-Koordinate, auf die Feldhöhe umlaufend abgebildet.

heading

Kopfrichtung im System mit 16 Sektoren.

Rückgabewert

Gibt bei Erfolg 1 zurück. Eine Anzahl von null oder über der Kapazität oder ein Nullzeiger liefert 0, ohne die Anordnung zu ändern.

Bedingungen und Grenzen

Binden Sie chain.h ein und kompilieren Sie chain.c genau einmal. ChainBody speichert die aktuelle Position und Richtung jedes Gelenks. Es ist ein eigener Zustandstyp, getrennt vom Positionsverlaufsring Chain.

Stellen Sie drei getrennte beschreibbare Arrays x, y und heading mit je capacity Bytes bereit und halten Sie sie während der Körpernutzung gültig. Index null ist der Kopf und in count enthalten. Ändern Sie nach der Initialisierung weder Speicherzeiger noch Kapazität oder Feldabmessungen.

Richtungen verwenden 16 Sektoren im Uhrzeigersinn: 0=rechts, 4=unten, 8=links, 12=oben. Nur die unteren vier Eingabebits werden verwendet. Bildschirmkoordinaten steigen nach rechts und unten; jede Abmessung beträgt 1..256 Pixel.

Der orthogonale Abstand beträgt vier Pixel. Zwischenrichtungen verwenden Ganzzahlvektoren wie (4,1), (3,3) und (1,4); die euklidische Distanz beträgt daher nicht exakt vier Pixel. Die anfängliche Anordnung kann einen Feldrand überschreiten.

Anwendungsbeispiel

c
chain_body_reset(&body,7,48,16,0); // Seven joints, facing right.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Bild zeigt oben einen geraden Körper, in der Mitte eine Aktualisierung nach einer Abwärtskurve und unten vier Aktualisierungen danach. Koordinaten werden in doppelter logischer Größe gezeichnet. Die Biegung wandert vom Kopf rechts nach hinten. CGB und FC zeigen Kopf rot, Körper blau und Schwanz grün; DMG verwendet Schwarz. Vier Ausgleichsaktualisierungen trennen das duplizierte Schwanzende nach dem Wachstum. Es sind drei Ansichten derselben acht Gelenke, kein Körper mit 24 Gelenken.

chain_body_reset: NTSC — Das Bild zeigt oben einen geraden Körper, in der Mitte eine Aktualisierung nach einer Abwärtskurve und unten vier Aktualisierungen danach. Koordinaten werden in doppelter logischer Größe gezeichnet. Die Biegung wandert vom Kopf rechts nach hinten. CGB und FC zeigen Kopf rot, Körper blau und Schwanz grün; DMG verwendet Schwarz. Vier Ausgleichsaktualisierungen trennen das duplizierte Schwanzende nach dem Wachstum. Es sind drei Ansichten derselben acht Gelenke, kein Körper mit 24 Gelenken.
NTSC — Das Bild zeigt oben einen geraden Körper, in der Mitte eine Aktualisierung nach einer Abwärtskurve und unten vier Aktualisierungen danach. Koordinaten werden in doppelter logischer Größe gezeichnet. Die Biegung wandert vom Kopf rechts nach hinten. CGB und FC zeigen Kopf rot, Körper blau und Schwanz grün; DMG verwendet Schwarz. Vier Ausgleichsaktualisierungen trennen das duplizierte Schwanzende nach dem Wachstum. Es sind drei Ansichten derselben acht Gelenke, kein Körper mit 24 Gelenken.

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/chain.h:61

Deklarationshinweise im Original
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

c
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

Setzt die Kopfanordnung und zieht jedes Gelenk schrittweise zu einem Anschlusspunkt hinter seinem Vorgänger. Richtungsänderungen wandern pro Aktualisierung um ein Gelenk weiter.

Syntax

c
void chain_body_step(ChainBody* body, u8 head_x, u8 head_y, u8 heading);

Parameter

body

Ziel-ChainBody; null wird ignoriert. Übergeben Sie außer bei der Initialisierung einen initialisierten Zustand.

head_x

Kopf-X-Koordinate, auf die Feldbreite umlaufend abgebildet.

head_y

Kopf-Y-Koordinate, auf die Feldhöhe umlaufend abgebildet.

heading

Kopfrichtung im System mit 16 Sektoren.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Binden Sie chain.h ein und kompilieren Sie chain.c genau einmal. ChainBody speichert die aktuelle Position und Richtung jedes Gelenks. Es ist ein eigener Zustandstyp, getrennt vom Positionsverlaufsring Chain.

Stellen Sie drei getrennte beschreibbare Arrays x, y und heading mit je capacity Bytes bereit und halten Sie sie während der Körpernutzung gültig. Index null ist der Kopf und in count enthalten. Ändern Sie nach der Initialisierung weder Speicherzeiger noch Kapazität oder Feldabmessungen.

Richtungen verwenden 16 Sektoren im Uhrzeigersinn: 0=rechts, 4=unten, 8=links, 12=oben. Nur die unteren vier Eingabebits werden verwendet. Bildschirmkoordinaten steigen nach rechts und unten; jede Abmessung beträgt 1..256 Pixel.

Ermittelt aus der aktualisierten Position des Vorgängers den Zielanschlusspunkt und berechnet dann je Achse die kürzeste umlaufende Verschiebung. Null bewegt nicht; Betrag 1..4 bewegt ein Pixel, ab 5 zwei Pixel. Bei genau einer halben Feldlänge bleibt das ursprüngliche Vorzeichen erhalten.

Gibt die vor der Aktualisierung gespeicherte Richtung jedes Gelenks an das nächste weiter, sodass eine Biegung durch den Körper wandert. Ein leerer Körper bleibt unverändert.

Der aufrufende Code verwaltet Kopfgeschwindigkeit, Beschleunigung, Kollisionen, Zeichnen und Warten. Aktualisieren Sie gewöhnlich zuerst den Kopf und rufen Sie chain_body_step einmal pro Simulationsschritt auf. Dies ist Gelenkverfolgung, kein Starrkörper- oder exakter Längenbedingungslöser.

Anwendungsbeispiel

c
chain_body_step(&body,48,20,4); // The head turns down; only joint 1 receives 4.
    show_pose(8,34);
    for(step=1;step<4;step++) {
        chain_body_step(&body,48,(u8)(20+step),4);
    }
    // After four ticks, the new heading has reached joints 1 through 4.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Bild zeigt oben einen geraden Körper, in der Mitte eine Aktualisierung nach einer Abwärtskurve und unten vier Aktualisierungen danach. Koordinaten werden in doppelter logischer Größe gezeichnet. Die Biegung wandert vom Kopf rechts nach hinten. CGB und FC zeigen Kopf rot, Körper blau und Schwanz grün; DMG verwendet Schwarz. Vier Ausgleichsaktualisierungen trennen das duplizierte Schwanzende nach dem Wachstum. Es sind drei Ansichten derselben acht Gelenke, kein Körper mit 24 Gelenken.

chain_body_step: NTSC — Das Bild zeigt oben einen geraden Körper, in der Mitte eine Aktualisierung nach einer Abwärtskurve und unten vier Aktualisierungen danach. Koordinaten werden in doppelter logischer Größe gezeichnet. Die Biegung wandert vom Kopf rechts nach hinten. CGB und FC zeigen Kopf rot, Körper blau und Schwanz grün; DMG verwendet Schwarz. Vier Ausgleichsaktualisierungen trennen das duplizierte Schwanzende nach dem Wachstum. Es sind drei Ansichten derselben acht Gelenke, kein Körper mit 24 Gelenken.
NTSC — Das Bild zeigt oben einen geraden Körper, in der Mitte eine Aktualisierung nach einer Abwärtskurve und unten vier Aktualisierungen danach. Koordinaten werden in doppelter logischer Größe gezeichnet. Die Biegung wandert vom Kopf rechts nach hinten. CGB und FC zeigen Kopf rot, Körper blau und Schwanz grün; DMG verwendet Schwarz. Vier Ausgleichsaktualisierungen trennen das duplizierte Schwanzende nach dem Wachstum. Es sind drei Ansichten derselben acht Gelenke, kein Körper mit 24 Gelenken.

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/chain.h:66

Deklarationshinweise im Original
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

c
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

Kopiert aktuelle Position und Richtung des Schwanzendes in den nächsten freien Platz und erhöht die Anzahl um eins.

Syntax

c
u8 chain_body_grow(ChainBody* body);

Parameter

body

Ziel-ChainBody; null wird ignoriert. Übergeben Sie außer bei der Initialisierung einen initialisierten Zustand.

Rückgabewert

Gibt beim Anhängen eines Gelenks 1 zurück; bei leerem, vollem, deaktiviertem Körper oder Nullzeiger 0.

Bedingungen und Grenzen

Binden Sie chain.h ein und kompilieren Sie chain.c genau einmal. ChainBody speichert die aktuelle Position und Richtung jedes Gelenks. Es ist ein eigener Zustandstyp, getrennt vom Positionsverlaufsring Chain.

Stellen Sie drei getrennte beschreibbare Arrays x, y und heading mit je capacity Bytes bereit und halten Sie sie während der Körpernutzung gültig. Index null ist der Kopf und in count enthalten. Ändern Sie nach der Initialisierung weder Speicherzeiger noch Kapazität oder Feldabmessungen.

Richtungen verwenden 16 Sektoren im Uhrzeigersinn: 0=rechts, 4=unten, 8=links, 12=oben. Nur die unteren vier Eingabebits werden verwendet. Bildschirmkoordinaten steigen nach rechts und unten; jede Abmessung beträgt 1..256 Pixel.

Das neue Schwanzende überlappt zunächst das vorige und trennt sich bei folgenden chain_body_step-Aufrufen. Wachstum allein bewegt weder Kopf noch andere Gelenke.

Anwendungsbeispiel

c
chain_body_grow(&body); // Copy the tail pose into the eighth slot.
    chain_body_step(&body,48,16,0);
    chain_body_step(&body,48,16,0);
    chain_body_step(&body,48,16,0);
    chain_body_step(&body,48,16,0); // Allow the duplicated tail to separate.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Bild zeigt oben einen geraden Körper, in der Mitte eine Aktualisierung nach einer Abwärtskurve und unten vier Aktualisierungen danach. Koordinaten werden in doppelter logischer Größe gezeichnet. Die Biegung wandert vom Kopf rechts nach hinten. CGB und FC zeigen Kopf rot, Körper blau und Schwanz grün; DMG verwendet Schwarz. Vier Ausgleichsaktualisierungen trennen das duplizierte Schwanzende nach dem Wachstum. Es sind drei Ansichten derselben acht Gelenke, kein Körper mit 24 Gelenken.

chain_body_grow: NTSC — Das Bild zeigt oben einen geraden Körper, in der Mitte eine Aktualisierung nach einer Abwärtskurve und unten vier Aktualisierungen danach. Koordinaten werden in doppelter logischer Größe gezeichnet. Die Biegung wandert vom Kopf rechts nach hinten. CGB und FC zeigen Kopf rot, Körper blau und Schwanz grün; DMG verwendet Schwarz. Vier Ausgleichsaktualisierungen trennen das duplizierte Schwanzende nach dem Wachstum. Es sind drei Ansichten derselben acht Gelenke, kein Körper mit 24 Gelenken.
NTSC — Das Bild zeigt oben einen geraden Körper, in der Mitte eine Aktualisierung nach einer Abwärtskurve und unten vier Aktualisierungen danach. Koordinaten werden in doppelter logischer Größe gezeichnet. Die Biegung wandert vom Kopf rechts nach hinten. CGB und FC zeigen Kopf rot, Körper blau und Schwanz grün; DMG verwendet Schwarz. Vier Ausgleichsaktualisierungen trennen das duplizierte Schwanzende nach dem Wachstum. Es sind drei Ansichten derselben acht Gelenke, kein Körper mit 24 Gelenken.

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/chain.h:69

Deklarationshinweise im Original
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

c
u8 chain_body_grow(ChainBody* body)
{
    u8 tail;
    u8 next;
    if (body == 0) return 0;
    next = body->count;
    if (next == 0 || next >= body->capacity) return 0;
    tail = (u8)(next - 1);
    body->x[(__safe_index u8)next] = body->x[(__safe_index u8)tail];
    body->y[(__safe_index u8)next] = body->y[(__safe_index u8)tail];
    body->heading[(__safe_index u8)next] = body->heading[(__safe_index u8)tail];
    body->count = (u8)(next + 1);
    return 1;
}
chain_body_clear

Setzt die Gelenkanzahl auf null und erhält Arrays sowie Feldeinstellungen.

Syntax

c
void chain_body_clear(ChainBody* body);

Parameter

body

Ziel-ChainBody; null wird ignoriert. Übergeben Sie außer bei der Initialisierung einen initialisierten Zustand.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Binden Sie chain.h ein und kompilieren Sie chain.c genau einmal. ChainBody speichert die aktuelle Position und Richtung jedes Gelenks. Es ist ein eigener Zustandstyp, getrennt vom Positionsverlaufsring Chain.

Stellen Sie drei getrennte beschreibbare Arrays x, y und heading mit je capacity Bytes bereit und halten Sie sie während der Körpernutzung gültig. Index null ist der Kopf und in count enthalten. Ändern Sie nach der Initialisierung weder Speicherzeiger noch Kapazität oder Feldabmessungen.

Richtungen verwenden 16 Sektoren im Uhrzeigersinn: 0=rechts, 4=unten, 8=links, 12=oben. Nur die unteren vier Eingabebits werden verwendet. Bildschirmkoordinaten steigen nach rechts und unten; jede Abmessung beträgt 1..256 Pixel.

Die Array-Bytes werden nicht gelöscht. Beginnen Sie mit chain_body_reset neu; chain_body_grow unmittelbar nach dem Leeren hängt kein Gelenk an.

Anwendungsbeispiel

c
chain_body_clear(&body); // Forget the pose; the three arrays remain owned by us.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Bild zeigt oben einen geraden Körper, in der Mitte eine Aktualisierung nach einer Abwärtskurve und unten vier Aktualisierungen danach. Koordinaten werden in doppelter logischer Größe gezeichnet. Die Biegung wandert vom Kopf rechts nach hinten. CGB und FC zeigen Kopf rot, Körper blau und Schwanz grün; DMG verwendet Schwarz. Vier Ausgleichsaktualisierungen trennen das duplizierte Schwanzende nach dem Wachstum. Es sind drei Ansichten derselben acht Gelenke, kein Körper mit 24 Gelenken.

chain_body_clear: NTSC — Das Bild zeigt oben einen geraden Körper, in der Mitte eine Aktualisierung nach einer Abwärtskurve und unten vier Aktualisierungen danach. Koordinaten werden in doppelter logischer Größe gezeichnet. Die Biegung wandert vom Kopf rechts nach hinten. CGB und FC zeigen Kopf rot, Körper blau und Schwanz grün; DMG verwendet Schwarz. Vier Ausgleichsaktualisierungen trennen das duplizierte Schwanzende nach dem Wachstum. Es sind drei Ansichten derselben acht Gelenke, kein Körper mit 24 Gelenken.
NTSC — Das Bild zeigt oben einen geraden Körper, in der Mitte eine Aktualisierung nach einer Abwärtskurve und unten vier Aktualisierungen danach. Koordinaten werden in doppelter logischer Größe gezeichnet. Die Biegung wandert vom Kopf rechts nach hinten. CGB und FC zeigen Kopf rot, Körper blau und Schwanz grün; DMG verwendet Schwarz. Vier Ausgleichsaktualisierungen trennen das duplizierte Schwanzende nach dem Wachstum. Es sind drei Ansichten derselben acht Gelenke, kein Körper mit 24 Gelenken.

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/chain.h:71

Deklarationshinweise im Original
Remove all joints while retaining caller-owned storage and playfield settings.

kitaqfc/lib/chain.c:233

c
void chain_body_clear(ChainBody* body)
{
    if (body == 0) return;
    body->count = 0;
}
chain_clear

Verwirft den aufgezeichneten Verlauf, damit dasselbe Speicherarray erneut verwendet werden kann.

Syntax

c
void chain_clear(Chain* chain);

Parameter

chain

Zeiger auf das initialisierte Chain-Objekt.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Setzt Anzahl und head auf null, ohne das Speicherarray zu löschen oder freizugeben. Der Aufrufer verwaltet Chain und das Punktarray und muss beide gültig halten. Die Kapazität darf höchstens 128 betragen, damit die 8-Bit-Indexaddition beim Lesen nicht überläuft.

Die FC-Version tut bei chain == 0 nichts.

Anwendungsbeispiel

c
chain_clear(&trail);result[11]=chain_get_count(&trail);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel leert einen Verlauf mit vier Punkten und prüft, dass die Anzahl danach null ist.

chain_clear: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/chain.h:24

Deklarationshinweise im Original
Forget the recorded points without clearing or freeing the backing storage.

kitaqfc/lib/chain.c:16

c
void chain_clear(Chain* chain)
{
    if (chain == 0) return;
    chain->count = 0;
    chain->head = 0;
}
chain_get_count

Liest die Anzahl der aktuell im Verlauf verfügbaren Positionen.

Syntax

c
u8 chain_get_count(const Chain* chain);

Parameter

chain

Zeiger auf das initialisierte Chain-Objekt.

Rückgabewert

Gibt eine Anzahl zwischen null und der Kapazität zurück, bei Nullzeiger null.

Bedingungen und Grenzen

Der Aufrufer verwaltet sowohl Chain als auch das Punktarray und muss beide gültig halten. Verwenden Sie höchstens 128 Plätze, damit die 8-Bit-Indexaddition beim Lesen nicht überläuft.

Anwendungsbeispiel

c
result[4]=chain_get_count(&trail);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Nach fünf Einfügungen in vier Plätze bleibt die Anzahl vier. Nach dem Leeren ist sie null; bei Kapazität null bleibt sie stets null.

chain_get_count: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/chain.h:33

Deklarationshinweise im Original
Return the number of stored points, or zero for a null chain.

kitaqfc/lib/chain.c:66

c
u8 chain_get_count(const Chain* chain)
{
    if (chain == 0) return 0;
    return chain->count;
}
chain_get_segment

Liest eine gespeicherte Position anhand ihres Alters im Verlauf.

Syntax

c
u8 chain_get_segment(const Chain* chain, u8 index, ChainPoint* out);

Parameter

chain

Zeiger auf das initialisierte Chain-Objekt.

index

Alter des Punkts: 0 bezeichnet den neuesten, count - 1 den ältesten noch gespeicherten Punkt.

out

Eigenständiges, beschreibbares ChainPoint-Objekt für das Ergebnis; ein Nullzeiger führt zum Fehlschlag.

Rückgabewert

Gibt bei Erfolg 1, bei ungültiger Anfrage 0 zurück. Ein nichtnulliger out-Zeiger wird vor der Prüfung auf (0,0) gesetzt.

Bedingungen und Grenzen

out darf keinen Speicher mit dem zugrunde liegenden Array oder mit Chain teilen, da das Nullsetzen der Ausgabe Quelldaten zerstören würde. Der Aufrufer verwaltet Chain und das Punktarray und muss beide gültig halten. Höchstens 128 Plätze verhindern einen Überlauf der 8-Bit-Indexaddition beim Lesen.

Anwendungsbeispiel

c
result[1]=chain_get_segment(&trail,0,&point);result[2]=point.x;result[3]=point.y;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Index 0 liest den neuesten Punkt (40,24), Index 3 den ältesten (16,8). Der ungültige Index 4 meldet einen Fehler und setzt die Ausgabe auf (0,0).

chain_get_segment: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/chain.h:31

Deklarationshinweise im Original
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

c
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

Verknüpft Speicher mit einem Ringpuffer für Positionsverläufe und beginnt ohne aufgezeichnete Punkte.

Syntax

c
void chain_init(Chain* chain, ChainPoint* storage, u8 capacity);

Parameter

chain

Zu initialisierendes, beschreibbares Chain-Objekt.

storage

Array mit Platz für capacity Einträge vom Typ ChainPoint.

capacity

Anzahl der Punktplätze. Für einen nutzbaren Verlauf sind 1 bis 128 zulässig; null deaktiviert die Aufzeichnung.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Der Aufrufer verwaltet sowohl Chain als auch das Punktarray und muss beide gültig halten. Verwenden Sie höchstens 128 Plätze, damit die 8-Bit-Indexaddition beim Lesen nicht überläuft.

Die FC-Version tut bei chain == 0 nichts.

Anwendungsbeispiel

c
chain_init(&trail,storage,4);result[0]=chain_get_count(&trail);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel bindet vier Punktplätze ein und prüft, dass die anfängliche Anzahl null ist.

chain_init: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/chain.h:22

Deklarationshinweise im Original
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

c
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

Fügt die neueste Position am Kopf des Verlaufs ein und ersetzt bei vollem Puffer den ältesten Punkt.

Syntax

c
void chain_push_head(Chain* chain, s16 x, s16 y);

Parameter

chain

Zeiger auf das initialisierte Chain-Objekt.

x

X-Koordinate des neuen Punkts mit Vorzeichen.

y

Y-Koordinate des neuen Punkts mit Vorzeichen.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Bei Nullzeiger oder Kapazität null geschieht nichts. Der Aufrufer verwaltet Chain und das Punktarray und muss beide gültig halten. Die Kapazität darf höchstens 128 betragen, damit die 8-Bit-Indexaddition beim Lesen nicht überläuft.

Anwendungsbeispiel

c
chain_push_head(&trail,8,8);chain_push_head(&trail,16,8);chain_push_head(&trail,24,16);chain_push_head(&trail,32,16);chain_push_head(&trail,40,24);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Nach fünf Einfügungen in vier Plätze ist (40,24) der neueste und (16,8) der älteste noch vorhandene Punkt. Der ursprüngliche Punkt (8,8) wurde ersetzt.

chain_push_head: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/chain.h:27

Deklarationshinweise im Original
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

c
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 — Kollisionstests für Rechtecke und andere Formen

Prüft Rechteck/Rechteck- und Rechteck/Punkt-Überlappungen in FC-Weltkoordinaten mit vorzeichenlosen 16-Bit-Positionen.

nes_box16_contains_point

Prüft, ob ein Punkt innerhalb eines FC-Rechtecks liegt. Die linke und obere Kante zählen dazu, die rechte und untere nicht.

Syntax

c
unsigned char nes_box16_contains_point(struct NesBox16* box, unsigned short px, unsigned short py);

Parameter

box

Lesbares NesBox16; übergeben Sie keinen Nullzeiger.

px

X-Koordinate des Punkts als vorzeichenloser 16-Bit-Wert.

py

Y-Koordinate des Punkts als vorzeichenloser 16-Bit-Wert.

Rückgabewert

Gibt innerhalb 1 zurück, außerhalb 0.

Bedingungen und Grenzen

x, y sind vorzeichenlose 16-Bit-Koordinaten; Breite und Höhe sind Byte-Werte. Verwenden Sie positive Abmessungen und halten Sie die Summen aus Koordinate und Abmessung bei höchstens 65535. Rechtecke über einen Koordinatenüberlauf hinweg werden nicht unterstützt.

Anwendungsbeispiel

c
result[6]=nes_box16_contains_point(&na,9,1);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Jede Koordinateneinheit entspricht einer Kachel. Rechteck A bei (1,1) und B bei (5,4) sind jeweils 8×6 groß. Nur von A belegte Zellen zeigen A, nur von B belegte zeigen B, und die 4×3 große Überlappung zeigt zwölf O-Zellen. Die rechte Kante von A bei x=9 zählt nicht dazu. Auf dem CGB ist A rot, B blau und O grün.

nes_box16_contains_point: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/collision.h:18

Deklarationshinweise im Original
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

c
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

Prüft, ob sich zwei per Zeiger übergebene FC-Rechtecke mit einer Fläche größer als null überlappen.

Syntax

c
unsigned char nes_box16_intersects(struct NesBox16* a, struct NesBox16* b);

Parameter

a

Erstes lesbares NesBox16; übergeben Sie keinen Nullzeiger.

b

Zweites lesbares NesBox16.

Rückgabewert

Gibt bei Überlappung 1 zurück, bei getrennten Rechtecken oder bloßer Kantenberührung 0.

Bedingungen und Grenzen

x, y sind vorzeichenlose 16-Bit-Koordinaten; Breite und Höhe sind Byte-Werte. Verwenden Sie positive Abmessungen und halten Sie die Summen aus Koordinate und Abmessung bei höchstens 65535. Rechtecke über einen Koordinatenüberlauf hinweg werden nicht unterstützt.

Anwendungsbeispiel

c
result[5]=nes_box16_intersects(&na,&nb);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Jede Koordinateneinheit entspricht einer Kachel. Rechteck A bei (1,1) und B bei (5,4) sind jeweils 8×6 groß. Nur von A belegte Zellen zeigen A, nur von B belegte zeigen B, und die 4×3 große Überlappung zeigt zwölf O-Zellen. Die rechte Kante von A bei x=9 zählt nicht dazu. Auf dem CGB ist A rot, B blau und O grün.

nes_box16_intersects: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/collision.h:15

Deklarationshinweise im Original
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

c
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 mit 64 Geschossen

danmaku ist ein Festkommapool für 64 Geschosse. Initialisieren Sie ihn, erzeugen Sie Geschosse, rufen Sie step für Bewegung und Kollisionen sowie draw zum Aufbau von OAM auf und führen Sie anschließend DMA während VBlank aus. Spielereingaben, Schaden, Punkte und Audio behandelt der Spielcode. Das Beispiel lädt eine eigens gestaltete Rautenkachel ins CHR-RAM; die Bibliothek kann auch Sprites aus CHR-ROM verwenden.

danmaku_reset

Deaktiviert alle Geschosse und setzt Treffer- und Streifereignisse, Höchst- und Gesamtzähler sowie die Zeiger für Vergabe und Zeichenreihenfolge zurück.

Syntax

c
void danmaku_reset(void);

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Spielerposition und dm_invulnerable bleiben erhalten. OAM und Anzeige werden nicht gelöscht. Um sichtbare Geschosse zu entfernen, zeichnen Sie den leeren Pool und führen DMA aus oder blenden die OAM-Einträge separat aus.

Reservieren Sie beschreibbares PRG-RAM der Cartridge bei $6000–$627F (640 Bytes) für 64 Geschosse. Aktivieren Sie dieses RAM im Cartridge-Mapper. Aufgrund des gemeinsam genutzten Zustands ist die Bibliothek nicht reentrant.

dm_count ist die Anzahl aktiver Geschosse, dm_peak deren bisheriger Höchststand. Die 16-Bit-Zähler dm_spawned und dm_rejected zählen erfolgreiche bzw. fehlgeschlagene Erzeugungsversuche und laufen nach 65535 auf null über. dm_x und dm_y sind die Mittelpunktkoordinaten. Ignorieren Sie diese Werte, wenn dm_active null ist.

KUROSAKI prüft vier Compilerkonfigurationen auf sämtliche Pixel, Geschossanzahl und -positionen, reserviertes OAM und wechselnde Zeichenreihenfolge. Separate numerische Prüfungen decken Treffer, Streifkontakte, das Entfernen außerhalb des Bildschirms und einen vollen Pool ab. Tests auf echter Hardware wurden nicht durchgeführt.

Anwendungsbeispiel

c
danmaku_reset();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Die vier gelben Geschosse links haben sich von (48,64) aus jeweils 16 Pixel nach oben, unten, links und rechts bewegt. Die sechzehn gelben Geschosse rechts bilden einen Ring etwa 32 Pixel um (160,104). Der cyanfarbene Spieler bei (112,192) belegt den reservierten OAM-Platz null. Das Beispiel hält das Bild nach sechzehn Logikaktualisierungen fest.

danmaku_reset: Standardeinstellung — Die vier gelben Geschosse links haben sich von (48,64) aus jeweils 16 Pixel nach oben, unten, links und rechts bewegt. Die sechzehn gelben Geschosse rechts bilden einen Ring etwa 32 Pixel um (160,104). Der cyanfarbene Spieler bei (112,192) belegt den reservierten OAM-Platz null. Das Beispiel hält das Bild nach sechzehn Logikaktualisierungen fest.
Standardeinstellung — Die vier gelben Geschosse links haben sich von (48,64) aus jeweils 16 Pixel nach oben, unten, links und rechts bewegt. Die sechzehn gelben Geschosse rechts bilden einen Ring etwa 32 Pixel um (160,104). Der cyanfarbene Spieler bei (112,192) belegt den reservierten OAM-Platz null. Das Beispiel hält das Bild nach sechzehn Logikaktualisierungen fest.

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.png
Implementierung und Quelltext

kitaqfc/lib/danmaku.h:26

Deklarationshinweise im Original
Reset the pool, counters and rotating OAM priority. Player settings survive.

kitaqfc/lib/danmaku.c:40

c
void danmaku_reset(void) {
    danmaku_clear();
    dm_peak=0;dm_spawned=0;dm_rejected=0;dm_cursor=0;dm_draw_phase=0;
}
danmaku_clear

Deaktiviert alle Geschosse und setzt dm_count, dm_hit und dm_graze auf null. Damit entfernen Sie Geschosse während des Spiels.

Syntax

c
void danmaku_clear(void);

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Behält dm_peak, dm_spawned, dm_rejected, die Zeiger für Vergabe und Zeichenreihenfolge sowie die Spielereinstellungen bei. Das Beispiel erzeugt ein Geschoss und entfernt es wieder: Die aktive Anzahl wird null, die Gesamtzahl erzeugter Geschosse bleibt eins. Aktualisieren Sie OAM separat.

Reservieren Sie beschreibbares PRG-RAM der Cartridge bei $6000–$627F (640 Bytes) für 64 Geschosse. Aktivieren Sie dieses RAM im Cartridge-Mapper. Aufgrund des gemeinsam genutzten Zustands ist die Bibliothek nicht reentrant.

dm_count ist die Anzahl aktiver Geschosse, dm_peak deren bisheriger Höchststand. Die 16-Bit-Zähler dm_spawned und dm_rejected zählen erfolgreiche bzw. fehlgeschlagene Erzeugungsversuche und laufen nach 65535 auf null über. dm_x und dm_y sind die Mittelpunktkoordinaten. Ignorieren Sie diese Werte, wenn dm_active null ist.

KUROSAKI prüft vier Compilerkonfigurationen auf sämtliche Pixel, Geschossanzahl und -positionen, reserviertes OAM und wechselnde Zeichenreihenfolge. Separate numerische Prüfungen decken Treffer, Streifkontakte, das Entfernen außerhalb des Bildschirms und einen vollen Pool ab. Tests auf echter Hardware wurden nicht durchgeführt.

Anwendungsbeispiel

c
danmaku_clear();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Die vier gelben Geschosse links haben sich von (48,64) aus jeweils 16 Pixel nach oben, unten, links und rechts bewegt. Die sechzehn gelben Geschosse rechts bilden einen Ring etwa 32 Pixel um (160,104). Der cyanfarbene Spieler bei (112,192) belegt den reservierten OAM-Platz null. Das Beispiel hält das Bild nach sechzehn Logikaktualisierungen fest.

danmaku_clear: Standardeinstellung — Die vier gelben Geschosse links haben sich von (48,64) aus jeweils 16 Pixel nach oben, unten, links und rechts bewegt. Die sechzehn gelben Geschosse rechts bilden einen Ring etwa 32 Pixel um (160,104). Der cyanfarbene Spieler bei (112,192) belegt den reservierten OAM-Platz null. Das Beispiel hält das Bild nach sechzehn Logikaktualisierungen fest.
Standardeinstellung — Die vier gelben Geschosse links haben sich von (48,64) aus jeweils 16 Pixel nach oben, unten, links und rechts bewegt. Die sechzehn gelben Geschosse rechts bilden einen Ring etwa 32 Pixel um (160,104). Der cyanfarbene Spieler bei (112,192) belegt den reservierten OAM-Platz null. Das Beispiel hält das Bild nach sechzehn Logikaktualisierungen fest.

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.png
Implementierung und Quelltext

kitaqfc/lib/danmaku.h:28

Deklarationshinweise im Original
Remove all bullets and step events; preserve lifetime/peak counters.

kitaqfc/lib/danmaku.c:35

c
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

Sucht zyklisch einen freien Poolplatz und initialisiert Position, Geschwindigkeit und den Zustand „noch kein Streifkontakt“. Die Erzeugung allein bewegt das Geschoss nicht und prüft keine Kollisionen.

Syntax

c
u8 danmaku_spawn(u8 x, u8 y, s8 vx, s8 vy);

Parameter

x

Horizontale Mittelpunktkoordinate in Pixeln; zulässig sind 8 bis 247.

y

Vertikale Mittelpunktkoordinate in Pixeln; zulässig sind 24 bis 231.

vx

Horizontale Geschwindigkeit im vorzeichenbehafteten Q4.4-Format. 16 bewegt um ein Pixel pro Aktualisierung, −16 um ein Pixel in die Gegenrichtung. Die Werte −128 bis 127 stehen für −8 bis +7,9375 Pixel.

vy

Vertikale Geschwindigkeit im vorzeichenbehafteten Q4.4-Format. 16 bewegt um ein Pixel pro Aktualisierung, −16 um ein Pixel in die Gegenrichtung. Die Werte −128 bis 127 stehen für −8 bis +7,9375 Pixel.

Rückgabewert

Gibt bei Erfolg 1 zurück, bei ungültiger Position oder vollem Pool mit 64 Plätzen dagegen 0. Erfolg erhöht dm_count und dm_spawned und aktualisiert bei Bedarf dm_peak. Ein Fehlschlag erhöht dm_rejected.

Bedingungen und Grenzen

Reservieren Sie beschreibbares PRG-RAM der Cartridge bei $6000–$627F (640 Bytes) für 64 Geschosse. Aktivieren Sie dieses RAM im Cartridge-Mapper. Aufgrund des gemeinsam genutzten Zustands ist die Bibliothek nicht reentrant.

dm_count ist die Anzahl aktiver Geschosse, dm_peak deren bisheriger Höchststand. Die 16-Bit-Zähler dm_spawned und dm_rejected zählen erfolgreiche bzw. fehlgeschlagene Erzeugungsversuche und laufen nach 65535 auf null über. dm_x und dm_y sind die Mittelpunktkoordinaten. Ignorieren Sie diese Werte, wenn dm_active null ist.

KUROSAKI prüft vier Compilerkonfigurationen auf sämtliche Pixel, Geschossanzahl und -positionen, reserviertes OAM und wechselnde Zeichenreihenfolge. Separate numerische Prüfungen decken Treffer, Streifkontakte, das Entfernen außerhalb des Bildschirms und einen vollen Pool ab. Tests auf echter Hardware wurden nicht durchgeführt.

Anwendungsbeispiel

c
danmaku_spawn(48,64,16,0);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Die vier gelben Geschosse links haben sich von (48,64) aus jeweils 16 Pixel nach oben, unten, links und rechts bewegt. Die sechzehn gelben Geschosse rechts bilden einen Ring etwa 32 Pixel um (160,104). Der cyanfarbene Spieler bei (112,192) belegt den reservierten OAM-Platz null. Das Beispiel hält das Bild nach sechzehn Logikaktualisierungen fest.

danmaku_spawn: Standardeinstellung — Die vier gelben Geschosse links haben sich von (48,64) aus jeweils 16 Pixel nach oben, unten, links und rechts bewegt. Die sechzehn gelben Geschosse rechts bilden einen Ring etwa 32 Pixel um (160,104). Der cyanfarbene Spieler bei (112,192) belegt den reservierten OAM-Platz null. Das Beispiel hält das Bild nach sechzehn Logikaktualisierungen fest.
Standardeinstellung — Die vier gelben Geschosse links haben sich von (48,64) aus jeweils 16 Pixel nach oben, unten, links und rechts bewegt. Die sechzehn gelben Geschosse rechts bilden einen Ring etwa 32 Pixel um (160,104). Der cyanfarbene Spieler bei (112,192) belegt den reservierten OAM-Platz null. Das Beispiel hält das Bild nach sechzehn Logikaktualisierungen fest.

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.png
Implementierung und Quelltext

kitaqfc/lib/danmaku.h:31

Deklarationshinweise im Original
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

c
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

Erzeugt Geschosse mit jeweils festem Richtungszuwachs. Schrittweite und Anzahl ermöglichen einen Fächer oder einen vollständigen Ring.

Syntax

c
void danmaku_fan(u8 x, u8 y, u8 direction, u8 step, u8 count, u8 speed);

Parameter

x

Horizontale Mittelpunktkoordinate in Pixeln; zulässig sind 8 bis 247.

y

Vertikale Mittelpunktkoordinate in Pixeln; zulässig sind 24 bis 231.

direction

Anfangsrichtung in 32 Schritten pro Umdrehung: 0 rechts, 8 unten, 16 links, 24 oben. Es werden nur die unteren fünf Bits verwendet.

step

Richtungszuwachs nach jedem Geschoss, umlaufend modulo 32. Bei null fliegen alle Geschosse in dieselbe Richtung.

count

Anzahl der Erzeugungsversuche. Werte über 64 werden auf 64 begrenzt; null bewirkt nichts.

speed

Geschwindigkeitsbetrag in Sechzehntelpixeln pro Aktualisierung: 16 entspricht einem Pixel, 32 zwei Pixeln. Werte über 64 werden auf 64 begrenzt.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Die Geschwindigkeiten stammen aus einer ganzzahligen Sinustabelle und werden gegen null abgeschnitten. Diagonale Geschwindigkeiten und Radien sind daher quantisiert. Ein voller Pool bricht die restlichen Versuche nicht ab; jeder Fehlschlag erhöht dm_rejected.

Reservieren Sie beschreibbares PRG-RAM der Cartridge bei $6000–$627F (640 Bytes) für 64 Geschosse. Aktivieren Sie dieses RAM im Cartridge-Mapper. Aufgrund des gemeinsam genutzten Zustands ist die Bibliothek nicht reentrant.

dm_count ist die Anzahl aktiver Geschosse, dm_peak deren bisheriger Höchststand. Die 16-Bit-Zähler dm_spawned und dm_rejected zählen erfolgreiche bzw. fehlgeschlagene Erzeugungsversuche und laufen nach 65535 auf null über. dm_x und dm_y sind die Mittelpunktkoordinaten. Ignorieren Sie diese Werte, wenn dm_active null ist.

KUROSAKI prüft vier Compilerkonfigurationen auf sämtliche Pixel, Geschossanzahl und -positionen, reserviertes OAM und wechselnde Zeichenreihenfolge. Separate numerische Prüfungen decken Treffer, Streifkontakte, das Entfernen außerhalb des Bildschirms und einen vollen Pool ab. Tests auf echter Hardware wurden nicht durchgeführt.

Anwendungsbeispiel

c
danmaku_fan(160,104,0,2,16,32);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Die vier gelben Geschosse links haben sich von (48,64) aus jeweils 16 Pixel nach oben, unten, links und rechts bewegt. Die sechzehn gelben Geschosse rechts bilden einen Ring etwa 32 Pixel um (160,104). Der cyanfarbene Spieler bei (112,192) belegt den reservierten OAM-Platz null. Das Beispiel hält das Bild nach sechzehn Logikaktualisierungen fest.

danmaku_fan: Standardeinstellung — Die vier gelben Geschosse links haben sich von (48,64) aus jeweils 16 Pixel nach oben, unten, links und rechts bewegt. Die sechzehn gelben Geschosse rechts bilden einen Ring etwa 32 Pixel um (160,104). Der cyanfarbene Spieler bei (112,192) belegt den reservierten OAM-Platz null. Das Beispiel hält das Bild nach sechzehn Logikaktualisierungen fest.
Standardeinstellung — Die vier gelben Geschosse links haben sich von (48,64) aus jeweils 16 Pixel nach oben, unten, links und rechts bewegt. Die sechzehn gelben Geschosse rechts bilden einen Ring etwa 32 Pixel um (160,104). Der cyanfarbene Spieler bei (112,192) belegt den reservierten OAM-Platz null. Das Beispiel hält das Bild nach sechzehn Logikaktualisierungen fest.

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.png
Implementierung und Quelltext

kitaqfc/lib/danmaku.h:34

Deklarationshinweise im Original
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

c
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

Bewegt jedes aktive Geschoss einmal, entfernt Geschosse außerhalb des Bildschirms und prüft Treffer sowie Streifkontakte am Spieler. Die Geschosszeit schreitet mit den Aufrufen fort, nicht mit der tatsächlich verstrichenen Zeit.

Syntax

c
void danmaku_step(void);

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Setzen Sie dm_player_x und dm_player_y vor dem Aufruf auf den Spielermittelpunkt. Nach der Bewegung gilt ein Abstand von höchstens drei Pixeln auf beiden Achsen als Treffer. Ist dm_invulnerable null, wird dm_hit auf eins gesetzt und das Geschoss entfernt. Bei Unverwundbarkeit bleibt es aktiv.

Außerhalb des Trefferbereichs ergibt ein Abstand von höchstens elf Pixeln auf beiden Achsen einmal pro Geschoss einen Streifkontakt. dm_hit und dm_graze werden beim Eintritt zurückgesetzt und beschreiben nur diese Aktualisierung. Ein Geschoss im Trefferbereich zählt bei unverwundbarem Spieler nicht als Streifkontakt.

Diese Funktion schreibt weder OAM noch ruft sie Schadens- oder Sound-Callbacks auf. Lesen Sie dm_hit und dm_graze aus und aktualisieren Sie Spielerzustand oder Punktestand im Spielcode.

Reservieren Sie beschreibbares PRG-RAM der Cartridge bei $6000–$627F (640 Bytes) für 64 Geschosse. Aktivieren Sie dieses RAM im Cartridge-Mapper. Aufgrund des gemeinsam genutzten Zustands ist die Bibliothek nicht reentrant.

dm_count ist die Anzahl aktiver Geschosse, dm_peak deren bisheriger Höchststand. Die 16-Bit-Zähler dm_spawned und dm_rejected zählen erfolgreiche bzw. fehlgeschlagene Erzeugungsversuche und laufen nach 65535 auf null über. dm_x und dm_y sind die Mittelpunktkoordinaten. Ignorieren Sie diese Werte, wenn dm_active null ist.

KUROSAKI prüft vier Compilerkonfigurationen auf sämtliche Pixel, Geschossanzahl und -positionen, reserviertes OAM und wechselnde Zeichenreihenfolge. Separate numerische Prüfungen decken Treffer, Streifkontakte, das Entfernen außerhalb des Bildschirms und einen vollen Pool ab. Tests auf echter Hardware wurden nicht durchgeführt.

Anwendungsbeispiel

c
danmaku_step();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Die vier gelben Geschosse links haben sich von (48,64) aus jeweils 16 Pixel nach oben, unten, links und rechts bewegt. Die sechzehn gelben Geschosse rechts bilden einen Ring etwa 32 Pixel um (160,104). Der cyanfarbene Spieler bei (112,192) belegt den reservierten OAM-Platz null. Das Beispiel hält das Bild nach sechzehn Logikaktualisierungen fest.

danmaku_step: Standardeinstellung — Die vier gelben Geschosse links haben sich von (48,64) aus jeweils 16 Pixel nach oben, unten, links und rechts bewegt. Die sechzehn gelben Geschosse rechts bilden einen Ring etwa 32 Pixel um (160,104). Der cyanfarbene Spieler bei (112,192) belegt den reservierten OAM-Platz null. Das Beispiel hält das Bild nach sechzehn Logikaktualisierungen fest.
Standardeinstellung — Die vier gelben Geschosse links haben sich von (48,64) aus jeweils 16 Pixel nach oben, unten, links und rechts bewegt. Die sechzehn gelben Geschosse rechts bilden einen Ring etwa 32 Pixel um (160,104). Der cyanfarbene Spieler bei (112,192) belegt den reservierten OAM-Platz null. Das Beispiel hält das Bild nach sechzehn Logikaktualisierungen fest.

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.png
Implementierung und Quelltext

kitaqfc/lib/danmaku.h:38

Deklarationshinweise im Original
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

c
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

Erstellt 8×8-Sprites aus den Geschossmittelpunkten und schreibt den angeforderten Bereich des Schatten-OAM, ohne Geschosse zu bewegen oder Kollisionen zu prüfen.

Syntax

c
u8 danmaku_draw(u8 first_oam, u8 slots, u8 tile, u8 attributes);

Parameter

first_oam

Erster OAM-Platz (0 bis 63). Werte ab 64 geben ohne Schreibzugriff null zurück. Das Beispiel beginnt bei eins, um Platz null für den Spieler freizuhalten.

slots

Anzahl aufeinanderfolgender verfügbarer Plätze, begrenzt auf 64−first_oam. Null schreibt nichts, schaltet die Zeichenpriorität aber dennoch weiter.

tile

Von allen Geschossen geteilte 8×8-Musterkachel. Stellen Sie den 8×8-Spritemodus ein; dieser Aufruf verwendet für jedes Geschoss dieselbe Form.

attributes

Gemeinsame NES-Spriteattribute aller Geschosse: Bits 0–1 Palette, Bit 5 hinter dem Hintergrund, Bit 6 horizontale Spiegelung, Bit 7 vertikale Spiegelung.

Rückgabewert

Gibt die Anzahl ins OAM geschriebener Geschosse zurück: das Minimum aus aktiver Anzahl und verfügbaren Plätzen.

Bedingungen und Grenzen

Verschiebt den anfänglichen Geschossplatz bei jedem Aufruf um 13 modulo 64, damit nicht stets dieselben Geschosse Vorrang haben. Ungenutzte Plätze im angeforderten Bereich werden mit Y=240 ausgeblendet; OAM außerhalb dieses Bereichs bleibt unverändert.

Zieht vier von Mittelpunkt-X und fünf von Mittelpunkt-Y ab. Die Hardware addiert eins zu OAM-Y und zentriert dadurch das Sprite. Rufen Sie __oam_dma selbst während VBlank auf. Die Hardwaregrenze von acht Sprites pro Scanline gilt weiterhin.

Reservieren Sie beschreibbares PRG-RAM der Cartridge bei $6000–$627F (640 Bytes) für 64 Geschosse. Aktivieren Sie dieses RAM im Cartridge-Mapper. Aufgrund des gemeinsam genutzten Zustands ist die Bibliothek nicht reentrant.

dm_count ist die Anzahl aktiver Geschosse, dm_peak deren bisheriger Höchststand. Die 16-Bit-Zähler dm_spawned und dm_rejected zählen erfolgreiche bzw. fehlgeschlagene Erzeugungsversuche und laufen nach 65535 auf null über. dm_x und dm_y sind die Mittelpunktkoordinaten. Ignorieren Sie diese Werte, wenn dm_active null ist.

KUROSAKI prüft vier Compilerkonfigurationen auf sämtliche Pixel, Geschossanzahl und -positionen, reserviertes OAM und wechselnde Zeichenreihenfolge. Separate numerische Prüfungen decken Treffer, Streifkontakte, das Entfernen außerhalb des Bildschirms und einen vollen Pool ab. Tests auf echter Hardware wurden nicht durchgeführt.

Anwendungsbeispiel

c
bullet_result[9]=danmaku_draw(1,24,1,0);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Die vier gelben Geschosse links haben sich von (48,64) aus jeweils 16 Pixel nach oben, unten, links und rechts bewegt. Die sechzehn gelben Geschosse rechts bilden einen Ring etwa 32 Pixel um (160,104). Der cyanfarbene Spieler bei (112,192) belegt den reservierten OAM-Platz null. Das Beispiel hält das Bild nach sechzehn Logikaktualisierungen fest.

danmaku_draw: Standardeinstellung — Die vier gelben Geschosse links haben sich von (48,64) aus jeweils 16 Pixel nach oben, unten, links und rechts bewegt. Die sechzehn gelben Geschosse rechts bilden einen Ring etwa 32 Pixel um (160,104). Der cyanfarbene Spieler bei (112,192) belegt den reservierten OAM-Platz null. Das Beispiel hält das Bild nach sechzehn Logikaktualisierungen fest.
Standardeinstellung — Die vier gelben Geschosse links haben sich von (48,64) aus jeweils 16 Pixel nach oben, unten, links und rechts bewegt. Die sechzehn gelben Geschosse rechts bilden einen Ring etwa 32 Pixel um (160,104). Der cyanfarbene Spieler bei (112,192) belegt den reservierten OAM-Platz null. Das Beispiel hält das Bild nach sechzehn Logikaktualisierungen fest.

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.png
Implementierung und Quelltext

kitaqfc/lib/danmaku.h:43

Deklarationshinweise im Original
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

c
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 — RAM-Protokolle und Zusicherungen

Protokolliert Namen, Werte und Frame-Kennungen in einem RAM-Protokoll fester Kapazität. Assertions bewahren Diagnoseinformationen auf und lassen die Ausführung weiterlaufen.

debug_assert_fail

Speichert einen Assertion-Fehlercode und versucht, einen ASSERT-Eintrag anzuhängen.

Syntax

c
void debug_assert_fail(u16 code);

Parameter

code

Zu speichernde 16-Bit-Fehlerkennung.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Die Ausführung läuft weiter. Der letzte Assertion-Code wird auch bei vollem Protokoll aktualisiert. Das Protokoll fasst standardmäßig 32 Einträge und verwirft bei voller Belegung neue Einträge. Wenn Sie DEBUG_TRACE_MAX überschreiben, verwenden Sie in allen Übersetzungseinheiten denselben Wert zwischen 1 und 255. Namen werden als Zeiger gespeichert, nicht kopiert; ihr Speicher muss bis zum Ende der Auswertung lesbar bleiben. Zugriffe aus Hauptprogramm und Interrupts müssen Sie selbst gegeneinander absichern.

Anwendungsbeispiel

c
debug_assert_fail(42);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel speichert Code 42, füllt das Protokoll und speichert dann Code 999. Die Anzahl bleibt 32, der letzte Code wird jedoch zu 999.

debug_assert_fail: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/debug.h:36

Deklarationshinweise im Original
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

c
void debug_assert_fail(u16 code)
{
    kq_debug_last_assert = code;
    debug_push(debug_assert_label, code);
}
debug_get_last_assert

Liest den letzten Assertion-Code unabhängig vom verfügbaren Protokollspeicher.

Syntax

c
u16 debug_get_last_assert(void);

Rückgabewert

Gibt den letzten 16-Bit-Code zurück; nach der Initialisierung ist er null.

Bedingungen und Grenzen

Null ist zugleich der Anfangswert und lässt sich daher nicht von einem mit Code null protokollierten Fehler unterscheiden. Das Lesen löscht den Code nicht.

Anwendungsbeispiel

c
result[22]=debug_get_last_assert();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel prüft 77 aus dem Assertion-Makro, 999 nach dem Füllen des Protokolls und null nach erneuter Initialisierung.

debug_get_last_assert: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/debug.h:42

Deklarationshinweise im Original
Read the latest assertion code, initially zero after debug_init.

kitaqfc/lib/debug.c:86

c
u16 debug_get_last_assert(void)
{
    return kq_debug_last_assert;
}
debug_get_trace_count

Liest die Anzahl gültiger Einträge im Trace-Array.

Syntax

c
u8 debug_get_trace_count(void);

Rückgabewert

Gibt eine Anzahl von null bis DEBUG_TRACE_MAX zurück.

Bedingungen und Grenzen

Das Protokoll fasst standardmäßig 32 Einträge und verwirft bei voller Belegung neue Einträge. Wenn Sie DEBUG_TRACE_MAX überschreiben, verwenden Sie in allen Übersetzungseinheiten denselben Wert zwischen 1 und 255. Namen werden als Zeiger gespeichert, nicht kopiert; ihr Speicher muss bis zum Ende der Auswertung lesbar bleiben. Zugriffe aus Hauptprogramm und Interrupts müssen Sie selbst gegeneinander absichern.

Anwendungsbeispiel

c
result[1]=debug_get_trace_count();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel prüft die ersten zehn Einträge und nach weiteren Schreibzugriffen die Grenze von 32. Bei voller Belegung läuft der Zähler nicht auf null über.

debug_get_trace_count: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/debug.h:38

Deklarationshinweise im Original
Read the number of valid entries in the fixed trace buffer.

kitaqfc/lib/debug.c:74

c
u8 debug_get_trace_count(void)
{
    return kq_debug_trace_count;
}
debug_get_trace_log

Liefert eine Referenz auf das interne Array zur Auswertung gespeicherter Namen, Werte und Frame-Kennungen.

Syntax

c
const DebugTraceEntry* debug_get_trace_log(void);

Rückgabewert

Gibt einen schreibgeschützten Zeiger auf das interne DebugTraceEntry-Array zurück.

Bedingungen und Grenzen

Dies ist keine Kopie. Lesen Sie nur die von debug_get_trace_count() gemeldete Anzahl von Einträgen. Nach der Initialisierung verbliebene alte Bytes sind keine gültigen Datensätze. Das Protokoll fasst standardmäßig 32 Einträge und verwirft bei voller Belegung neue Einträge. Wenn Sie DEBUG_TRACE_MAX überschreiben, verwenden Sie in allen Übersetzungseinheiten denselben Wert zwischen 1 und 255. Namen werden als Zeiger gespeichert, nicht kopiert; ihr Speicher muss bis zum Ende der Auswertung lesbar bleiben. Zugriffe aus Hauptprogramm und Interrupts müssen Sie selbst gegeneinander absichern.

Anwendungsbeispiel

c
entries=debug_get_trace_log();for(i=0;i<10;i++){result[2+i]=entries[i].value;result[12+i]=entries[i].frame;}

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel liest alle zehn Wert- und Frame-Felder und prüft das führende B der Bezeichnung BEGIN.

debug_get_trace_log: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/debug.h:40

Deklarationshinweise im Original
Borrow the internal trace array; bound inspection by debug_get_trace_count.

kitaqfc/lib/debug.c:80

c
const DebugTraceEntry* debug_get_trace_log(void)
{
    return kq_debug_trace_log;
}
debug_init

Initialisiert die gültige Protokolllänge, die Frame-Kennung und den letzten Assertion-Code.

Syntax

c
void debug_init(void);

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Die Bytes vorhandener Einträge werden nicht gelöscht. Rufen Sie die Funktion vor dem ersten Protokolleintrag auf. Das Protokoll fasst standardmäßig 32 Einträge und verwirft bei voller Belegung neue Einträge. Wenn Sie DEBUG_TRACE_MAX überschreiben, verwenden Sie in allen Übersetzungseinheiten denselben Wert zwischen 1 und 255. Namen werden als Zeiger gespeichert, nicht kopiert; ihr Speicher muss bis zum Ende der Auswertung lesbar bleiben. Zugriffe aus Hauptprogramm und Interrupts müssen Sie selbst gegeneinander absichern.

Anwendungsbeispiel

c
debug_init();result[0]=debug_get_trace_count();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel prüft zunächst die Anzahl null, setzt dann ein gefülltes Protokoll zurück und bestätigt, dass Anzahl und Assertion-Code gelöscht sind, während die alten Arraywerte erhalten bleiben.

debug_init: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/debug.h:25

Deklarationshinweise im Original
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

c
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

Schreibt eine benannte Frame-Markierung, um eine Stelle im Ablauf zu kennzeichnen.

Syntax

c
void debug_mark_frame(const u8* label);

Parameter

label

Nullterminierte Bezeichnung in Speicher, der bis zur Auswertung lesbar bleiben muss.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Das Protokoll fasst standardmäßig 32 Einträge und verwirft bei voller Belegung neue Einträge. Wenn Sie DEBUG_TRACE_MAX überschreiben, verwenden Sie in allen Übersetzungseinheiten denselben Wert zwischen 1 und 255. Namen werden als Zeiger gespeichert, nicht kopiert; ihr Speicher muss bis zum Ende der Auswertung lesbar bleiben. Zugriffe aus Hauptprogramm und Interrupts müssen Sie selbst gegeneinander absichern.

Anwendungsbeispiel

c
debug_mark_frame("BEGIN");

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Die Markierung BEGIN speichert den Wert 65535 (0xFFFF) mit der Frame-Kennung 513.

debug_mark_frame: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/debug.h:29

Deklarationshinweise im Original
Append a named marker with the reserved marker value 0xFFFF.

kitaqfc/lib/debug.c:48

c
void debug_mark_frame(const u8* label)
{
    debug_push(label, 0xFFFF);
}
debug_set_frame

Legt die Frame-Kennung fest, die in nachfolgende Protokolleinträge kopiert wird.

Syntax

c
void debug_set_frame(u16 frame);

Parameter

frame

16-Bit-Frame-Nummer für nachfolgende Einträge.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Die Funktion wartet weder auf einen Frame noch erhöht sie die Kennung automatisch. Übergeben Sie ausdrücklich den Frame-Zähler des Spiels. Das Protokoll fasst standardmäßig 32 Einträge und verwirft bei voller Belegung neue Einträge. Wenn Sie DEBUG_TRACE_MAX überschreiben, verwenden Sie in allen Übersetzungseinheiten denselben Wert zwischen 1 und 255. Namen werden als Zeiger gespeichert, nicht kopiert; ihr Speicher muss bis zum Ende der Auswertung lesbar bleiben. Zugriffe aus Hauptprogramm und Interrupts müssen Sie selbst gegeneinander absichern.

Anwendungsbeispiel

c
debug_set_frame(513);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel setzt die Kennung auf 513, schreibt zehn Einträge und liest zur Kontrolle alle zehn Frame-Felder zurück.

debug_set_frame: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/debug.h:27

Deklarationshinweise im Original
Choose the frame tag stored in subsequent debug entries.

kitaqfc/lib/debug.c:29

c
void debug_set_frame(u16 frame)
{
    kq_debug_frame = frame;
}
debug_trace_u16

Protokolliert einen benannten 16-Bit-Punktestand oder Zähler.

Syntax

c
void debug_trace_u16(const u8* name, u16 value);

Parameter

name

Nullterminierte Bezeichnung in Speicher, der bis zur Auswertung lesbar bleiben muss.

value

Zu protokollierender Wert von 0 bis 65535.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Das Protokoll fasst standardmäßig 32 Einträge und verwirft bei voller Belegung neue Einträge. Wenn Sie DEBUG_TRACE_MAX überschreiben, verwenden Sie in allen Übersetzungseinheiten denselben Wert zwischen 1 und 255. Namen werden als Zeiger gespeichert, nicht kopiert; ihr Speicher muss bis zum Ende der Auswertung lesbar bleiben. Zugriffe aus Hauptprogramm und Interrupts müssen Sie selbst gegeneinander absichern.

Anwendungsbeispiel

c
debug_trace_u16("WORD",4660);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Der Eintrag WORD speichert 4660 (0x1234); das Beispiel liest ihn zur Prüfung beider Bytes zurück.

debug_trace_u16: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/debug.h:33

Deklarationshinweise im Original
Append a 16-bit value with the current frame tag.

kitaqfc/lib/debug.c:60

c
void debug_trace_u16(const u8* name, u16 value)
{
    debug_push(name, value);
}
debug_trace_u8

Protokolliert einen 8-Bit-Zustandswert mit Namen und aktueller Frame-Kennung.

Syntax

c
void debug_trace_u8(const u8* name, u8 value);

Parameter

name

Nullterminierte Bezeichnung in Speicher, der bis zur Auswertung lesbar bleiben muss.

value

Wert von 0 bis 255, der mit Nullen auf das 16-Bit-Protokollfeld erweitert wird.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Das Protokoll fasst standardmäßig 32 Einträge und verwirft bei voller Belegung neue Einträge. Wenn Sie DEBUG_TRACE_MAX überschreiben, verwenden Sie in allen Übersetzungseinheiten denselben Wert zwischen 1 und 255. Namen werden als Zeiger gespeichert, nicht kopiert; ihr Speicher muss bis zum Ende der Auswertung lesbar bleiben. Zugriffe aus Hauptprogramm und Interrupts müssen Sie selbst gegeneinander absichern.

Anwendungsbeispiel

c
debug_trace_u8("BYTE",255);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Der Eintrag BYTE speichert 255 und prüft, dass das 16-Bit-Wertfeld im Protokoll ebenfalls 255 enthält.

debug_trace_u8: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/debug.h:31

Deklarationshinweise im Original
Widen a byte value into the trace entry's 16-bit value field.

kitaqfc/lib/debug.c:54

c
void debug_trace_u8(const u8* name, u8 value)
{
    debug_push(name, (u16)value);
}
KITAQGB_ASSERT

Als Anweisung verwendbares Makro, das bei falscher Bedingung Assertion-Code 1 protokolliert.

Syntax

c
#define KITAQGB_ASSERT(cond) do { if (!(cond)) debug_assert_fail((u16)1); } while (0)

Parameter

cond

Bedingung, die erfüllt sein soll; null bedeutet einen Fehler.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Die Bedingung wird einmal ausgewertet. Bei wahr wird nichts protokolliert, bei falsch der Fehler aufgezeichnet, ohne die Ausführung anzuhalten. Durch die Form do…while (0) lässt sich das Makro in einem if…else als einzelne Anweisung verwenden.

Anwendungsbeispiel

c
KITAQGB_ASSERT(1);KITAQGB_ASSERT(0);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Eine wahre und eine falsche Assertion erzeugen genau einen Eintrag mit Code 1.

KITAQGB_ASSERT: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/debug.h:48

c
#define KITAQGB_ASSERT(cond) do { if (!(cond)) debug_assert_fail((u16)1); } while (0)
KITAQGB_ASSERT_CODE

Protokolliert den gewählten Assertion-Code nur bei falscher Bedingung.

Syntax

c
#define KITAQGB_ASSERT_CODE(cond, code) do { if (!(cond)) debug_assert_fail((u16)(code)); } while (0)

Parameter

cond

Bedingung, die erfüllt sein soll.

code

Code-Ausdruck, der im Fehlerfall ausgewertet und in 16 Bits umgewandelt wird.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Die Bedingung wird einmal ausgewertet, der Code-Ausdruck nur im Fehlerfall. Nach dem Protokollieren läuft die Ausführung weiter.

Anwendungsbeispiel

c
KITAQGB_ASSERT_CODE(1,++side_effect);KITAQGB_ASSERT_CODE(0,77);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Bei wahrer Bedingung wird der Code-Ausdruck ++side_effect nicht ausgewertet; die Variable bleibt null. Eine falsche Bedingung protokolliert Code 77.

KITAQGB_ASSERT_CODE: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/debug.h:49

c
#define KITAQGB_ASSERT_CODE(cond, code) do { if (!(cond)) debug_assert_fail((u16)(code)); } while (0)
KITAQGB_MARK_FRAME

Wandelt eine Bezeichnung in einen Zeichenkettenzeiger um und fügt eine Frame-Markierung mit dem Wert 0xFFFF hinzu.

Syntax

c
#define KITAQGB_MARK_FRAME(label) debug_mark_frame((const u8*)(label))

Parameter

label

Nullterminierte Bezeichnung in Speicher, der bis zur Auswertung lesbar bleiben muss.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Das Protokoll fasst standardmäßig 32 Einträge und verwirft bei voller Belegung neue Einträge. Wenn Sie DEBUG_TRACE_MAX überschreiben, verwenden Sie in allen Übersetzungseinheiten denselben Wert zwischen 1 und 255. Namen werden als Zeiger gespeichert, nicht kopiert; ihr Speicher muss bis zum Ende der Auswertung lesbar bleiben. Zugriffe aus Hauptprogramm und Interrupts müssen Sie selbst gegeneinander absichern.

Anwendungsbeispiel

c
KITAQGB_MARK_FRAME("END");

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Die Markierung END wird auf den Wert 65535 und die Frame-Kennung 513 geprüft.

KITAQGB_MARK_FRAME: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/debug.h:47

c
#define KITAQGB_MARK_FRAME(label) debug_mark_frame((const u8*)(label))
KITAQGB_TRACE

Wandelt einen Wert ausdrücklich in 16 Bits um und protokolliert ihn mit Namen.

Syntax

c
#define KITAQGB_TRACE(name, value) debug_trace_u16((const u8*)(name), (u16)(value))

Parameter

name

Nullterminierte Bezeichnung in Speicher, der bis zur Auswertung lesbar bleiben muss.

value

Ausdruck, der vor dem Protokollieren in 16 Bits umgewandelt wird.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Das Makro ist immer aktiv; Build-Einstellungen deaktivieren es nicht automatisch. Es protokolliert 16-Bit-Werte genauso wie KITAQGB_TRACE_U16. Das Protokoll fasst standardmäßig 32 Einträge und verwirft bei voller Belegung neue Einträge. Wenn Sie DEBUG_TRACE_MAX überschreiben, verwenden Sie in allen Übersetzungseinheiten denselben Wert zwischen 1 und 255. Namen werden als Zeiger gespeichert, nicht kopiert; ihr Speicher muss bis zum Ende der Auswertung lesbar bleiben. Zugriffe aus Hauptprogramm und Interrupts müssen Sie selbst gegeneinander absichern.

Anwendungsbeispiel

c
KITAQGB_TRACE("SCORE",600);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel speichert 600 und liest den Wert zur Prüfung aus dem Protokoll zurück.

KITAQGB_TRACE: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/debug.h:46

c
#define KITAQGB_TRACE(name, value) debug_trace_u16((const u8*)(name), (u16)(value))
KITAQGB_TRACE_U16

Wandelt einen Wert ausdrücklich in 16 Bits um und protokolliert ihn mit Namen.

Syntax

c
#define KITAQGB_TRACE_U16(name, value) debug_trace_u16((const u8*)(name), (u16)(value))

Parameter

name

Nullterminierte Bezeichnung in Speicher, der bis zur Auswertung lesbar bleiben muss.

value

Ausdruck, der vor dem Protokollieren in 16 Bits umgewandelt wird.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Das Makro ist immer aktiv; Build-Einstellungen deaktivieren es nicht automatisch. Das Protokoll fasst standardmäßig 32 Einträge und verwirft bei voller Belegung neue Einträge. Wenn Sie DEBUG_TRACE_MAX überschreiben, verwenden Sie in allen Übersetzungseinheiten denselben Wert zwischen 1 und 255. Namen werden als Zeiger gespeichert, nicht kopiert; ihr Speicher muss bis zum Ende der Auswertung lesbar bleiben. Zugriffe aus Hauptprogramm und Interrupts müssen Sie selbst gegeneinander absichern.

Anwendungsbeispiel

c
KITAQGB_TRACE_U16("WORD2",500);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel speichert 500 und liest den Wert zur Prüfung aus dem Protokoll zurück.

KITAQGB_TRACE_U16: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/debug.h:45

c
#define KITAQGB_TRACE_U16(name, value) debug_trace_u16((const u8*)(name), (u16)(value))
KITAQGB_TRACE_U8

Wandelt einen Wert ausdrücklich in 8 Bits um und protokolliert ihn mit Namen.

Syntax

c
#define KITAQGB_TRACE_U8(name, value) debug_trace_u8((const u8*)(name), (u8)(value))

Parameter

name

Nullterminierte Bezeichnung in Speicher, der bis zur Auswertung lesbar bleiben muss.

value

Ausdruck, der vor dem Protokollieren in 8 Bits umgewandelt wird.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Das Makro ist immer aktiv; Build-Einstellungen deaktivieren es nicht automatisch. Das Protokoll fasst standardmäßig 32 Einträge und verwirft bei voller Belegung neue Einträge. Wenn Sie DEBUG_TRACE_MAX überschreiben, verwenden Sie in allen Übersetzungseinheiten denselben Wert zwischen 1 und 255. Namen werden als Zeiger gespeichert, nicht kopiert; ihr Speicher muss bis zum Ende der Auswertung lesbar bleiben. Zugriffe aus Hauptprogramm und Interrupts müssen Sie selbst gegeneinander absichern.

Anwendungsbeispiel

c
KITAQGB_TRACE_U8("CAST",0x1234);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel speichert 52. Von 0x1234 bleibt nur das niederwertige Byte 0x34 erhalten.

KITAQGB_TRACE_U8: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/debug.h:44

c
#define KITAQGB_TRACE_U8(name, value) debug_trace_u8((const u8*)(name), (u8)(value))

entity.h — Objektpools mit festen Arrays

entity ist ein Objektpool mit einem Array fester Größe für Zustände wie Gegner, Geschosse und Sammelobjekte. Sie belegen einen freien Platz, greifen über dessen ID darauf zu und verwenden den Platz erneut, sobald das Objekt nicht mehr benötigt wird. Es wird kein Heap-Speicher angefordert. Koordinaten- und Geschwindigkeitseinheiten, Bewegung, Kollisionen und Timer-Aktualisierungen legt das Spiel fest.

Binden Sie entity.h ein und kompilieren Sie entity.c genau einmal. Rufen Sie zuerst entity_init auf und prüfen Sie, dass entity_create nicht 0xFF zurückgibt. ENTITY_MAX hat standardmäßig den Wert 16. Die IDs unterstützen 1 bis 255 Plätze; die tatsächlich nutzbare Anzahl hängt jedoch vom verfügbaren RAM ab. Verwenden Sie in allen Übersetzungseinheiten dieselbe Kapazitätsdefinition.

Der von entity_get zurückgegebene Zeiger verweist auf wiederverwendbaren Poolspeicher. Nach der Freigabe kann dieselbe ID ein anderes Objekt bezeichnen. Weder ID noch Zeiger stellen daher eine dauerhafte Identität dar. entity_destroy deaktiviert lediglich den Platz. Der Aufrufer muss Sprites ausblenden oder freigeben und andere Ressourcen aufräumen. Das Feld sprite dient der Verwaltung und aktualisiert OAM nicht automatisch.

entity_update_all und entity_draw_all durchlaufen aktive Plätze in aufsteigender ID-Reihenfolge und rufen fn(id) auf. Implementieren Sie die eigentliche Aktualisierung oder Darstellung im Callback. Ein Null-Callback bewirkt nichts. Wenn ein Callback einen späteren Platz belegt oder freigibt, wirkt sich das bereits auf den laufenden Durchlauf aus. Ein Aktualisierungsdurchlauf vor dem Zeichendurchlauf trennt beide Aufgaben.

Lege den Callback in die gemeinsame PRG-Bank 0 oder halte seine Bank während des gesamten Aufrufs eingeblendet. Ein Funktionszeiger enthält eine 16-Bit-CPU-Adresse und schaltet keine Bank um. Parameter und lokale Variablen der FC-Funktionen belegen feste Speicherbereiche. Rufe den Entity-Durchlauf daher weder rekursiv auf noch erneut aus einem Interrupt, während er bereits läuft.

entity_clear_all

Gibt alle Entities frei und setzt ihre Felder einschließlich der Markierung für fehlende Sprites zurück.

Syntax

c
void entity_clear_all(void);

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Der Pool ist ein festes Array ohne Heap-Allokation. ENTITY_MAX ist standardmäßig 16 und muss in allen Übersetzungseinheiten gleich mit einem Wert von 1 bis 255 definiert sein. IDs beginnen bei null; 0xFF kennzeichnet einen Fehlschlag.

Setzt in allen Plätzen active,type,x,y,vx,vy,state,timer auf null und sprite auf 0xFF. Hardware-Sprites werden dadurch weder verborgen noch freigegeben; ihre Ressourcen müssen separat aufgeräumt werden.

Anwendungsbeispiel

c
entity_clear_all();
after_clear = entity_count_active();
if (after_clear != 0 || entity_get(reused) != 0) { failures++; }

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm zeigt den Lebenszyklus eines wiederverwendbaren Platzes. Lesen Sie Zahlen mit ihren Beschriftungen: CREATED 002 nach zwei Belegungen, AFTER FREE 001 nach Freigabe der ersten, REUSED ID 000 bei Wiederverwendung der kleinsten freien ID und AFTER CLEAR 000 nach Leeren des Pools. Geprüft werden auch null-Abfrage nach Freigabe und zurückgesetzte Felder nach Neubelegung. FAILED CHECKS 000 bestätigt die erwarteten Werte.

Der FC-Durchlauf ruft jeden Callback für beide aktiven Entities auf: UPDATE CALLS 002 und DRAW CALLS 002. Der Aktualisierungs-Callback verschiebt beide um ein Tile nach rechts. Der Zeichen-Callback setzt zur Darstellung der Objekte A auf Tile (3,12) und B auf (7,12). Das sind vom Callback gezeichnete Hintergrund-Schrift-Tiles, keine automatisch belegten Sprites.

entity_clear_all: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/entity.h:47

Deklarationshinweise im Original
Release every entity and restore deterministic defaults, including the no-sprite sentinel.

kitaqfc/lib/entity.c:14

c
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

Zählt belegte Entity-Plätze, ohne ihren Zustand zu ändern.

Syntax

c
u8 entity_count_active(void);

Rückgabewert

Anzahl der Plätze mit einem von null verschiedenen active-Byte, von 0 bis ENTITY_MAX. Das ist die Belegung, nicht die höchste ID oder die Anzahl sichtbarer Sprites.

Bedingungen und Grenzen

Der Pool ist ein festes Array ohne Heap-Allokation. ENTITY_MAX ist standardmäßig 16 und muss in allen Übersetzungseinheiten gleich mit einem Wert von 1 bis 255 definiert sein. IDs beginnen bei null; 0xFF kennzeichnet einen Fehlschlag.

Anwendungsbeispiel

c
created = entity_count_active();
if (created != 2) { failures++; }

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm zeigt den Lebenszyklus eines wiederverwendbaren Platzes. Lesen Sie Zahlen mit ihren Beschriftungen: CREATED 002 nach zwei Belegungen, AFTER FREE 001 nach Freigabe der ersten, REUSED ID 000 bei Wiederverwendung der kleinsten freien ID und AFTER CLEAR 000 nach Leeren des Pools. Geprüft werden auch null-Abfrage nach Freigabe und zurückgesetzte Felder nach Neubelegung. FAILED CHECKS 000 bestätigt die erwarteten Werte.

Der FC-Durchlauf ruft jeden Callback für beide aktiven Entities auf: UPDATE CALLS 002 und DRAW CALLS 002. Der Aktualisierungs-Callback verschiebt beide um ein Tile nach rechts. Der Zeichen-Callback setzt zur Darstellung der Objekte A auf Tile (3,12) und B auf (7,12). Das sind vom Callback gezeichnete Hintergrund-Schrift-Tiles, keine automatisch belegten Sprites.

entity_count_active: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/entity.h:45

Deklarationshinweise im Original
Count occupied slots without changing entity state.

kitaqfc/lib/entity.c:94

c
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

Reserviert eine Entity mit Typ und Position; liefert ihre wiederverwendbare ID oder bei vollem Pool 0xFF.

Syntax

c
u8 entity_create(u8 type, s16 x, s16 y);

Parameter

type

Vom Spiel definierte Typkennung von 0 bis 255. Der Pool speichert sie, wählt damit aber weder Verhalten noch Zeichenroutinen aus.

x, y

Vorzeichenbehaftete 16-Bit-Koordinaten (-32768–32767). Die Einheit bestimmt das Spiel, etwa Pixel oder Q8.8. Der Pool rechnet keine Einheiten um, begrenzt keine Positionen und wendet Geschwindigkeiten nicht automatisch an.

Rückgabewert

Die kleinste freie Platz-ID (0–ENTITY_MAX-1) oder 0xFF, falls keiner frei ist. Erfolgreiche Belegung setzt active=1, speichert Typ und Position, löscht Geschwindigkeit/Zustand/Timer und setzt sprite=0xFF.

Bedingungen und Grenzen

Der Pool ist ein festes Array ohne Heap-Allokation. ENTITY_MAX ist standardmäßig 16 und muss in allen Übersetzungseinheiten gleich mit einem Wert von 1 bis 255 definiert sein. IDs beginnen bei null; 0xFF kennzeichnet einen Fehlschlag.

Anwendungsbeispiel

c
first = entity_create(1, 2, 12);
second = entity_create(2, 6, 12);
if (first == 0xFF || second == 0xFF) { failures++; }

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm zeigt den Lebenszyklus eines wiederverwendbaren Platzes. Lesen Sie Zahlen mit ihren Beschriftungen: CREATED 002 nach zwei Belegungen, AFTER FREE 001 nach Freigabe der ersten, REUSED ID 000 bei Wiederverwendung der kleinsten freien ID und AFTER CLEAR 000 nach Leeren des Pools. Geprüft werden auch null-Abfrage nach Freigabe und zurückgesetzte Felder nach Neubelegung. FAILED CHECKS 000 bestätigt die erwarteten Werte.

Der FC-Durchlauf ruft jeden Callback für beide aktiven Entities auf: UPDATE CALLS 002 und DRAW CALLS 002. Der Aktualisierungs-Callback verschiebt beide um ein Tile nach rechts. Der Zeichen-Callback setzt zur Darstellung der Objekte A auf Tile (3,12) und B auf (7,12). Das sind vom Callback gezeichnete Hintergrund-Schrift-Tiles, keine automatisch belegten Sprites.

entity_create: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/entity.h:32

Deklarationshinweise im Original
Returns a reusable slot ID, or 0xFF if no slot is free.

kitaqfc/lib/entity.c:34

c
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

Gibt den Platz von Entity id frei; die Nutzdaten werden erst bei erneuter Belegung zurückgesetzt.

Syntax

c
void entity_destroy(u8 id);

Parameter

id

Wiederverwendbarer Platzindex von 0 bis ENTITY_MAX-1. Werte außerhalb dieses Bereichs sind ungültig. Das Freigeben einer ungültigen ID bewirkt nichts; die Abfrage liefert null.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Der Pool ist ein festes Array ohne Heap-Allokation. ENTITY_MAX ist standardmäßig 16 und muss in allen Übersetzungseinheiten gleich mit einem Wert von 1 bis 255 definiert sein. IDs beginnen bei null; 0xFF kennzeichnet einen Fehlschlag.

Freigeben löscht nur active, nicht die übrigen Felder, Sprites oder Assets. Spätere Belegung kann dieselbe ID und Adresse für eine andere Entity verwenden. Das Spiel muss die zugehörigen Ressourcen selbst aufräumen.

Anwendungsbeispiel

c
entity_destroy(first);
after_free = entity_count_active();
if (entity_get(first) != 0 || after_free != 1) { failures++; }

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm zeigt den Lebenszyklus eines wiederverwendbaren Platzes. Lesen Sie Zahlen mit ihren Beschriftungen: CREATED 002 nach zwei Belegungen, AFTER FREE 001 nach Freigabe der ersten, REUSED ID 000 bei Wiederverwendung der kleinsten freien ID und AFTER CLEAR 000 nach Leeren des Pools. Geprüft werden auch null-Abfrage nach Freigabe und zurückgesetzte Felder nach Neubelegung. FAILED CHECKS 000 bestätigt die erwarteten Werte.

Der FC-Durchlauf ruft jeden Callback für beide aktiven Entities auf: UPDATE CALLS 002 und DRAW CALLS 002. Der Aktualisierungs-Callback verschiebt beide um ein Tile nach rechts. Der Zeichen-Callback setzt zur Darstellung der Objekte A auf Tile (3,12) und B auf (7,12). Das sind vom Callback gezeichnete Hintergrund-Schrift-Tiles, keine automatisch belegten Sprites.

entity_destroy: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/entity.h:35

Deklarationshinweise im Original
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

c
void entity_destroy(u8 id)
{
    if (id >= ENTITY_MAX) return;
    entity_pool[(__safe_index u8)id].active = 0;
}
entity_draw_all

Durchläuft aktive Entities und übergibt jede ID an den Zeichen-Callback. Der Durchlauf entspricht entity_update_all; ohne vom Callback eingereichte Zeichendaten werden keine Sprites oder Pixel gezeichnet.

Syntax

c
void entity_draw_all(EntityFn fn);

Parameter

fn

Funktionszeiger mit Signatur void fn(u8 id). Er erhält eine Platz-ID; auf Felder greifen Sie über entity_get(id) zu. Null ist zulässig und führt zu keinen Aufrufen.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Der Pool ist ein festes Array ohne Heap-Allokation. ENTITY_MAX ist standardmäßig 16 und muss in allen Übersetzungseinheiten gleich mit einem Wert von 1 bis 255 definiert sein. IDs beginnen bei null; 0xFF kennzeichnet einen Fehlschlag.

Der Durchlauf prüft die Aktivität erst beim Erreichen eines Platzes. Ein Callback kann spätere Plätze deaktivieren und damit überspringen lassen oder aktivieren und noch im selben Durchlauf besuchen lassen. Es wird kein Schnappschuss der anfänglichen Belegung verwendet.

Lege den Callback in die gemeinsame PRG-Bank 0 oder halte seine Bank während des gesamten Aufrufs eingeblendet. Ein Funktionszeiger enthält eine 16-Bit-CPU-Adresse und schaltet keine Bank um. Parameter und lokale Variablen der FC-Funktionen belegen feste Speicherbereiche. Rufe den Entity-Durchlauf daher weder rekursiv auf noch erneut aus einem Interrupt, während er bereits läuft.

Anwendungsbeispiel

c
void demo_draw(u8 id) {
    Entity* entity;
    entity = entity_get(id);
    if (entity != 0) {
        m_put((u8)entity->x, (u8)entity->y, (u8)('A' + entity->type - 1));
        draw_calls++;
    }
}

// From main(), after creating two entities:
draw_calls = 0;
entity_draw_all(demo_draw);
automatic_draws = draw_calls;
if (automatic_draws != 2) { failures++; }

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm zeigt den Lebenszyklus eines wiederverwendbaren Platzes. Lesen Sie Zahlen mit ihren Beschriftungen: CREATED 002 nach zwei Belegungen, AFTER FREE 001 nach Freigabe der ersten, REUSED ID 000 bei Wiederverwendung der kleinsten freien ID und AFTER CLEAR 000 nach Leeren des Pools. Geprüft werden auch null-Abfrage nach Freigabe und zurückgesetzte Felder nach Neubelegung. FAILED CHECKS 000 bestätigt die erwarteten Werte.

Der FC-Durchlauf ruft jeden Callback für beide aktiven Entities auf: UPDATE CALLS 002 und DRAW CALLS 002. Der Aktualisierungs-Callback verschiebt beide um ein Tile nach rechts. Der Zeichen-Callback setzt zur Darstellung der Objekte A auf Tile (3,12) und B auf (7,12). Das sind vom Callback gezeichnete Hintergrund-Schrift-Tiles, keine automatisch belegten Sprites.

entity_draw_all: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/entity.h:43

Deklarationshinweise im Original
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

c
void entity_draw_all(EntityFn fn)
{
    entity_update_all(fn);
}
entity_get

Liefert einen Zeiger auf die aktive Entity oder null bei ungültiger bzw. freier ID. Der Speicherplatz wird wiederverwendet.

Syntax

c
Entity* entity_get(u8 id);

Parameter

id

Wiederverwendbarer Platzindex von 0 bis ENTITY_MAX-1. Werte außerhalb dieses Bereichs sind ungültig. Das Freigeben einer ungültigen ID bewirkt nichts; die Abfrage liefert null.

Rückgabewert

Schreibbarer Zeiger auf den aktiven Pool-Platz oder null bei ungültiger bzw. inaktiver ID. Der Speicher gehört dem Pool; geben Sie ihn nicht selbst frei und verwenden Sie den Zeiger nicht als dauerhafte Identität über Freigabe und Neubelegung hinweg.

Bedingungen und Grenzen

Der Pool ist ein festes Array ohne Heap-Allokation. ENTITY_MAX ist standardmäßig 16 und muss in allen Übersetzungseinheiten gleich mit einem Wert von 1 bis 255 definiert sein. IDs beginnen bei null; 0xFF kennzeichnet einen Fehlschlag.

Freigeben löscht nur active, nicht die übrigen Felder, Sprites oder Assets. Spätere Belegung kann dieselbe ID und Adresse für eine andere Entity verwenden. Das Spiel muss die zugehörigen Ressourcen selbst aufräumen.

Anwendungsbeispiel

c
current_entity = entity_get(first);
if (current_entity != 0) { current_entity->vx = 5; }
else { failures++; }

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm zeigt den Lebenszyklus eines wiederverwendbaren Platzes. Lesen Sie Zahlen mit ihren Beschriftungen: CREATED 002 nach zwei Belegungen, AFTER FREE 001 nach Freigabe der ersten, REUSED ID 000 bei Wiederverwendung der kleinsten freien ID und AFTER CLEAR 000 nach Leeren des Pools. Geprüft werden auch null-Abfrage nach Freigabe und zurückgesetzte Felder nach Neubelegung. FAILED CHECKS 000 bestätigt die erwarteten Werte.

Der FC-Durchlauf ruft jeden Callback für beide aktiven Entities auf: UPDATE CALLS 002 und DRAW CALLS 002. Der Aktualisierungs-Callback verschiebt beide um ein Tile nach rechts. Der Zeichen-Callback setzt zur Darstellung der Objekte A auf Tile (3,12) und B auf (7,12). Das sind vom Callback gezeichnete Hintergrund-Schrift-Tiles, keine automatisch belegten Sprites.

entity_get: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/entity.h:37

Deklarationshinweise im Original
Returns null for an invalid or inactive ID; the returned pointer aliases reusable pool storage.

kitaqfc/lib/entity.c:66

c
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

Initialisiert alle Plätze im Entity-Pool.

Syntax

c
void entity_init(void);

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Der Pool ist ein festes Array ohne Heap-Allokation. ENTITY_MAX ist standardmäßig 16 und muss in allen Übersetzungseinheiten gleich mit einem Wert von 1 bis 255 definiert sein. IDs beginnen bei null; 0xFF kennzeichnet einen Fehlschlag.

Setzt in allen Plätzen active,type,x,y,vx,vy,state,timer auf null und sprite auf 0xFF. Hardware-Sprites werden dadurch weder verborgen noch freigegeben; ihre Ressourcen müssen separat aufgeräumt werden.

Anwendungsbeispiel

c
entity_init();
if (entity_count_active() != 0) { failures++; }

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm zeigt den Lebenszyklus eines wiederverwendbaren Platzes. Lesen Sie Zahlen mit ihren Beschriftungen: CREATED 002 nach zwei Belegungen, AFTER FREE 001 nach Freigabe der ersten, REUSED ID 000 bei Wiederverwendung der kleinsten freien ID und AFTER CLEAR 000 nach Leeren des Pools. Geprüft werden auch null-Abfrage nach Freigabe und zurückgesetzte Felder nach Neubelegung. FAILED CHECKS 000 bestätigt die erwarteten Werte.

Der FC-Durchlauf ruft jeden Callback für beide aktiven Entities auf: UPDATE CALLS 002 und DRAW CALLS 002. Der Aktualisierungs-Callback verschiebt beide um ein Tile nach rechts. Der Zeichen-Callback setzt zur Darstellung der Objekte A auf Tile (3,12) und B auf (7,12). Das sind vom Callback gezeichnete Hintergrund-Schrift-Tiles, keine automatisch belegten Sprites.

entity_init: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/entity.h:30

Deklarationshinweise im Original
Reset every slot before the game starts using the pool.

kitaqfc/lib/entity.c:8

c
void entity_init(void)
{
    entity_clear_all();
}
entity_update_all

Durchläuft aktive Plätze nach aufsteigender ID und ruft für jeden einmal fn(id) auf. Bewegung, Kollisionen oder Timer implementiert der Callback; der Pool stellt diese Logik nicht bereit. Ein null-Callback bewirkt nichts.

Syntax

c
void entity_update_all(EntityFn fn);

Parameter

fn

Funktionszeiger mit Signatur void fn(u8 id). Er erhält eine Platz-ID; auf Felder greifen Sie über entity_get(id) zu. Null ist zulässig und führt zu keinen Aufrufen.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Der Pool ist ein festes Array ohne Heap-Allokation. ENTITY_MAX ist standardmäßig 16 und muss in allen Übersetzungseinheiten gleich mit einem Wert von 1 bis 255 definiert sein. IDs beginnen bei null; 0xFF kennzeichnet einen Fehlschlag.

Der Durchlauf prüft die Aktivität erst beim Erreichen eines Platzes. Ein Callback kann spätere Plätze deaktivieren und damit überspringen lassen oder aktivieren und noch im selben Durchlauf besuchen lassen. Es wird kein Schnappschuss der anfänglichen Belegung verwendet.

Lege den Callback in die gemeinsame PRG-Bank 0 oder halte seine Bank während des gesamten Aufrufs eingeblendet. Ein Funktionszeiger enthält eine 16-Bit-CPU-Adresse und schaltet keine Bank um. Parameter und lokale Variablen der FC-Funktionen belegen feste Speicherbereiche. Rufe den Entity-Durchlauf daher weder rekursiv auf noch erneut aus einem Interrupt, während er bereits läuft.

Anwendungsbeispiel

c
void demo_update(u8 id) {
    Entity* entity;
    entity = entity_get(id);
    if (entity != 0) { entity->x = entity->x + 1; update_calls++; }
}

// From main(), after creating two entities:
update_calls = 0;
entity_update_all(demo_update);
automatic_updates = update_calls;
if (automatic_updates != 2) { failures++; }

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm zeigt den Lebenszyklus eines wiederverwendbaren Platzes. Lesen Sie Zahlen mit ihren Beschriftungen: CREATED 002 nach zwei Belegungen, AFTER FREE 001 nach Freigabe der ersten, REUSED ID 000 bei Wiederverwendung der kleinsten freien ID und AFTER CLEAR 000 nach Leeren des Pools. Geprüft werden auch null-Abfrage nach Freigabe und zurückgesetzte Felder nach Neubelegung. FAILED CHECKS 000 bestätigt die erwarteten Werte.

Der FC-Durchlauf ruft jeden Callback für beide aktiven Entities auf: UPDATE CALLS 002 und DRAW CALLS 002. Der Aktualisierungs-Callback verschiebt beide um ein Tile nach rechts. Der Zeichen-Callback setzt zur Darstellung der Objekte A auf Tile (3,12) und B auf (7,12). Das sind vom Callback gezeichnete Hintergrund-Schrift-Tiles, keine automatisch belegten Sprites.

entity_update_all: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/entity.h:40

Deklarationshinweise im Original
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

c
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);
    }
}

FDS-Dateien und Speicherplätze fester Größe

fds_file.h bietet das Laden von Dateien in Spielpuffer und das Schreiben in einen reservierten Speicherplatz auf Diskette. fds_save.h bindet dieselben Deklarationen ein. Verwenden Sie fds_overlay.h für Aufrufe von Overlay-Code.

__fds_load_file() / __fds_save_file()

fds_file_io.c fds_file_io_manifest.json fds_file_io_payload.bin

fds_sound.h

Deklariert Compiler-Intrinsics für 64-stufige Wellenform, Modulationstabelle, Tonhöhe, Lautstärke und Hüllkurven. KITAQFC erzeugt ihre Implementierungen.

Erstellen Sie mit --mapper=fds ein .fds-Abbild. Diese Lektion verwendet Sound ohne Datenträger-I/O. Die Aufnahme nutzt KUROSAKIs direkten RAM-Start und Audiomodell. Die leere Testfirmware implementiert keine BIOS-Routinen und wird nicht verteilt. Normaler Diskettenstart und echte Hardware benötigen eine passende Startumgebung.

Funktionsreferenz: __fds_sound_enable, __fds_wave_load, __fds_mod_load, __fds_freq_set, __fds_volume_set, __fds_env_set

fixed.h — Q8.8-Festkommaarithmetik und Rechtecke

Q8.8-Arithmetik stellt gebrochene Koordinaten und Geschwindigkeiten mit Ganzzahlen dar und ergänzt sie um Kollisionsprüfungen für Rechtecke und Punkte. Beachten Sie die Genauigkeit und Wertebereiche jeder Operation.

fix_div

Dividiert Q8.8-Werte nach einer Verringerung der Operandengenauigkeit.

Syntax

c
fix8 fix_div(fix8 a, fix8 b);

Parameter

a

Linker Operand im Q8.8-Format.

b

Rechter Operand im Q8.8-Format.

Rückgabewert

Gibt einen Q8.8-Quotienten zurück, bei b == 0 hingegen null.

Bedingungen und Grenzen

Berechnet wird ((a >> 4) * 256) / (b >> 4). Ein von null verschiedener Divisor darf durch die Verschiebung nicht null werden; übergeben Sie daher keine positiven Rohwerte von 1 bis 15. Auch der skalierte Zähler muss in 16 Bits passen.

Anwendungsbeispiel

c
result[3]=fix_div(768,512);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

3,0 geteilt durch 2,0 ergibt 1,5 (Rohwert 384). Ein eigener Test prüft den ausdrücklich vorgesehenen Rückgabewert bei Divisor null.

fix_div: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/fixed.h:35

Deklarationshinweise im Original
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

c
fix8 fix_div(fix8 a, fix8 b)
{
    if (b == 0) return 0;
    return (fix8)(((a >> 4) * 256) / (b >> 4));
}
fix_from_int

Wandelt eine ganzzahlige Koordinate oder Geschwindigkeit in Q8.8 um, damit nachfolgende Berechnungen Nachkommastellen erhalten können.

Syntax

c
fix8 fix_from_int(s16 n);

Parameter

n

Die umzuwandelnde ganze Zahl im Bereich −128 bis 127.

Rückgabewert

Gibt den Rohwert n × 256 zurück.

Bedingungen und Grenzen

fix8 ist ein vorzeichenbehaftetes Q8.8-Format: Der Rohwert 256 steht für 1,0. Zwischenwerte und Ergebnisse müssen im 16-Bit-Wertebereich bleiben.

Anwendungsbeispiel

c
result[0]=fix_from_int(-3);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel wandelt −3 um. Die Anzeige −00768 entspricht dem Q8.8-Rohwert −768.

fix_from_int: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/fixed.h:26

Deklarationshinweise im Original
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

c
fix8 fix_from_int(s16 n)
{
    return (fix8)(n << 8);
}
fix_lerp

Interpoliert mit einem 8-Bit-Gewicht von einem Q8.8-Wert in Richtung eines anderen.

Syntax

c
fix8 fix_lerp(fix8 a, fix8 b, u8 t_q8);

Parameter

a

Linker Operand im Q8.8-Format.

b

Rechter Operand im Q8.8-Format.

t_q8

Interpolationsgewicht von 0 bis 255.

Rückgabewert

Gibt den näherungsweise interpolierten Q8.8-Wert zurück.

Bedingungen und Grenzen

Differenz und Gewicht werden jeweils um vier Bits nach rechts geschoben. Dadurch gibt es nur 16 Gewichtsstufen; selbst 255 muss den Endwert nicht erreichen. b - a und das Endergebnis müssen im 16-Bit-Bereich bleiben.

Anwendungsbeispiel

c
result[4]=fix_lerp(0,1024,128);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Zwischen 0 und 4,0 ergibt Gewicht 128 den Wert 2,0 (Rohwert 512). Gewicht 255 liefert 3,75 (Rohwert 960) und zeigt damit, dass der Endwert nicht erreicht wird.

fix_lerp: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/fixed.h:38

Deklarationshinweise im Original
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

c
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

Multipliziert zwei Q8.8-Werte mit einem rechenarmen Näherungsverfahren.

Syntax

c
fix8 fix_mul(fix8 a, fix8 b);

Parameter

a

Linker Operand im Q8.8-Format.

b

Rechter Operand im Q8.8-Format.

Rückgabewert

Gibt das Produkt im Q8.8-Format zurück.

Bedingungen und Grenzen

Vor der Multiplikation wird jeder Operand um vier Bits nach rechts geschoben; seine vier niederwertigsten Bits gehen verloren. Das ist ungenauer als ein vollständiges 16-mal-16-Bit-Produkt. fix8 ist vorzeichenbehaftetes Q8.8, wobei der Rohwert 256 für 1,0 steht. Zwischenwerte und Ergebnisse müssen im 16-Bit-Bereich bleiben.

Anwendungsbeispiel

c
result[2]=fix_mul(384,512);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

1,5 mal 2,0 ergibt 3,0 (Rohwert 768). Das Programm prüft auch die Quantisierung: Rohwert 271 mal Rohwert 271 ergibt 256.

fix_mul: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/fixed.h:31

Deklarationshinweise im Original
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

c
fix8 fix_mul(fix8 a, fix8 b)
{
    return (fix8)((a >> 4) * (b >> 4));
}
fix_to_int

Gewinnt eine ganzzahlige Koordinate aus Q8.8, indem die Nachkommabits verworfen werden. Negative Werte werden gegen minus unendlich abgerundet.

Syntax

c
s16 fix_to_int(fix8 x);

Parameter

x

Der in eine ganze Zahl umzuwandelnde Q8.8-Wert.

Rückgabewert

Gibt eine vorzeichenbehaftete ganze Zahl zurück.

Bedingungen und Grenzen

fix8 ist ein vorzeichenbehaftetes Q8.8-Format: Der Rohwert 256 steht für 1,0. Zwischenwerte und Ergebnisse müssen im 16-Bit-Wertebereich bleiben.

Anwendungsbeispiel

c
result[1]=fix_to_int(-384);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Der Rohwert −384 (−1,5) ergibt −2 und wird als −00002 angezeigt. Ein Grenzwerttest bestätigt außerdem, dass der Rohwert −1 zu −1 wird.

fix_to_int: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/fixed.h:28

Deklarationshinweise im Original
Discard the eight fractional bits using a signed right shift.

kitaqfc/lib/fixed.c:11

c
s16 fix_to_int(fix8 x)
{
    return (s16)(x >> 8);
}
kq_abs_s16

Ermittelt den Betrag eines vorzeichenbehafteten 16-Bit-Werts.

Syntax

c
s16 kq_abs_s16(s16 v);

Parameter

v

Vorzeichenbehafteter 16-Bit-Wert, dessen Betrag benötigt wird.

Rückgabewert

Gibt einen nichtnegativen Betrag zurück, mit Ausnahme des nicht darstellbaren Betrags von −32768.

Bedingungen und Grenzen

Der positive Betrag 32768 passt nicht in s16. Schließen Sie −32768 aus, wenn das Ergebnis nichtnegativ sein muss.

Anwendungsbeispiel

c
result[0]=kq_abs_s16(-123);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel wandelt −123 in 123 um, etwa zur Bestimmung des Betrags einer Koordinatendifferenz.

kq_abs_s16: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/fixed.h:41

Deklarationshinweise im Original
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

c
s16 kq_abs_s16(s16 v)
{
    if (v < 0) return (s16)(0 - v);
    return v;
}
kq_clamp_s16

Begrenzt eine Koordinate oder Geschwindigkeit auf ein Intervall einschließlich seiner Grenzen.

Syntax

c
s16 kq_clamp_s16(s16 v, s16 lo, s16 hi);

Parameter

v

Zu begrenzender Wert mit Vorzeichen.

lo

Einschließlich geltende Untergrenze.

hi

Einschließlich geltende Obergrenze.

Rückgabewert

Gibt unterhalb des Intervalls lo, oberhalb hi und innerhalb v zurück.

Bedingungen und Grenzen

Geben Sie ein gültiges Intervall mit lo <= hi an.

Anwendungsbeispiel

c
result[3]=kq_clamp_s16(25,-10,10);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Begrenzen von 25 auf −10…10 ergibt 10. Geprüft werden auch −11→−10 an der unteren Grenze und 3→3 innerhalb des Intervalls.

kq_clamp_s16: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/fixed.h:47

Deklarationshinweise im Original
Clamp to an inclusive interval; callers must provide lo <= hi.

kitaqfc/lib/fixed.c:65

c
s16 kq_clamp_s16(s16 v, s16 lo, s16 hi)
{
    if (v < lo) return lo;
    if (v > hi) return hi;
    return v;
}
kq_max_s16

Wählt den größeren von zwei vorzeichenbehafteten 16-Bit-Werten.

Syntax

c
s16 kq_max_s16(s16 a, s16 b);

Parameter

a

Erster zu vergleichender Wert mit Vorzeichen.

b

Zweiter zu vergleichender Wert mit Vorzeichen.

Rückgabewert

Gibt den ausgewählten Operanden zurück.

Bedingungen und Grenzen

Der Vergleich berücksichtigt das Vorzeichen. Bei gleichen Operanden wird dieser gemeinsame Wert zurückgegeben; beide Eingaben bleiben unverändert.

Anwendungsbeispiel

c
result[2]=kq_max_s16(-7,4);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Der Vergleich von −7 und 4 ergibt 4. Negative Ergebnisse werden mit Minuszeichen angezeigt.

kq_max_s16: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/fixed.h:45

Deklarationshinweise im Original
Select the larger signed value.

kitaqfc/lib/fixed.c:58

c
s16 kq_max_s16(s16 a, s16 b)
{
    if (a > b) return a;
    return b;
}
kq_min_s16

Wählt den kleineren von zwei vorzeichenbehafteten 16-Bit-Werten.

Syntax

c
s16 kq_min_s16(s16 a, s16 b);

Parameter

a

Erster zu vergleichender Wert mit Vorzeichen.

b

Zweiter zu vergleichender Wert mit Vorzeichen.

Rückgabewert

Gibt den ausgewählten Operanden zurück.

Bedingungen und Grenzen

Der Vergleich berücksichtigt das Vorzeichen. Bei gleichen Operanden wird dieser gemeinsame Wert zurückgegeben; beide Eingaben bleiben unverändert.

Anwendungsbeispiel

c
result[1]=kq_min_s16(-7,4);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Der Vergleich von −7 und 4 ergibt -7. Negative Ergebnisse werden mit Minuszeichen angezeigt.

kq_min_s16: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/fixed.h:43

Deklarationshinweise im Original
Select the smaller signed value.

kitaqfc/lib/fixed.c:51

c
s16 kq_min_s16(s16 a, s16 b)
{
    if (a < b) return a;
    return b;
}
kq_point_in_rect

Prüft, ob ein Punkt im Rechteck liegt; linke und obere Kante sind eingeschlossen.

Syntax

c
u8 kq_point_in_rect(s16 x, s16 y, KQRect r);

Parameter

x

X-Koordinate des Punkts im Koordinatensystem des Rechtecks.

y

Y-Koordinate des Punkts.

r

Zu prüfendes Rechteck, als Wert übergeben.

Rückgabewert

Gibt innen 1 und außen 0 zurück.

Bedingungen und Grenzen

Verwenden Sie positive Abmessungen; Koordinate plus Größe muss als s16 darstellbar bleiben. Rechte und untere Kante sind ausgeschlossen. Rechtecke mit Fläche null werden nicht ausdrücklich abgewiesen.

Anwendungsbeispiel

c
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();
}}

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Jede Koordinateneinheit entspricht einer Kachel. Rechteck A bei (1,1) und B bei (5,4) sind jeweils 8×6 groß. Nur von A belegte Zellen zeigen A, nur von B belegte zeigen B, und die 4×3 große Überlappung zeigt zwölf O-Zellen. Die rechte Kante von A bei x=9 zählt nicht dazu. Auf dem CGB ist A rot, B blau und O grün.

kq_point_in_rect: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/fixed.h:54

Deklarationshinweise im Original
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

c
u8 kq_point_in_rect(s16 x, s16 y, KQRect r)
{
    if (x < r.x) return 0;
    if (y < r.y) return 0;
    if (x >= (s16)(r.x + r.w)) return 0;
    if (y >= (s16)(r.y + r.h)) return 0;
    return 1;
}
kq_rect_intersect

Prüft, ob sich zwei achsenparallele Rechtecke mit positiver Fläche überschneiden.

Syntax

c
u8 kq_rect_intersect(KQRect a, KQRect b);

Parameter

a

Erstes Rechteck, als Wert übergeben: x, y geben die linke obere Ecke an, w, h seine Breite und Höhe.

b

Zweites Rechteck im selben Koordinatensystem wie A.

Rückgabewert

Gibt bei Überschneidung 1 zurück, bei Trennung oder bloßer Kantenberührung 0.

Bedingungen und Grenzen

Verwenden Sie positive Abmessungen; Koordinate plus Größe muss als s16 darstellbar bleiben. Rechte und untere Kante sind ausgeschlossen. Rechtecke mit Fläche null werden nicht ausdrücklich abgewiesen.

Anwendungsbeispiel

c
result[0]=kq_rect_intersect(a,b);result[2]=kq_rect_intersect(a,touch);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Jede Koordinateneinheit entspricht einer Kachel. Rechteck A bei (1,1) und B bei (5,4) sind jeweils 8×6 groß. Nur von A belegte Zellen zeigen A, nur von B belegte zeigen B, und die 4×3 große Überlappung zeigt zwölf O-Zellen. Die rechte Kante von A bei x=9 zählt nicht dazu. Auf dem CGB ist A rot, B blau und O grün.

kq_rect_intersect: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/fixed.h:51

Deklarationshinweise im Original
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

c
u8 kq_rect_intersect(KQRect a, KQRect b)
{
    if ((s16)(a.x + a.w) <= b.x) return 0;
    if ((s16)(b.x + b.w) <= a.x) return 0;
    if ((s16)(a.y + a.h) <= b.y) return 0;
    if ((s16)(b.y + b.h) <= a.y) return 0;
    return 1;
}

input.h — Tastenzustand, Drücken, Loslassen und Wiederholung

Verwende input_down für fortlaufende Bewegung, input_pressed für einmalige Aktionen, input_released für Aktionen beim Loslassen und input_repeat für Menüs mit Tastenwiederholung. Einmal initialisieren, einmal pro Eingabetakt aktualisieren, danach beliebig oft abfragen. btn_down, btn_pressed, btn_released und btn_repeat sind Aliase dieser vier Abfragen.

Liest Controller 1 mit __pad_read1_safe, ordnet die NES-Bits in das gemeinsame BTN_*-Format um, speichert den vorherigen Zustand und berechnet Druck-, Loslass- und Wiederholungsmasken. Controller 2 wird nicht erfasst. Einmal pro Eingabetakt aufrufen.

Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.

Die Intervalle zählen Updates, keine Millisekunden. Ein neuer Tastendruck erzeugt sofort einen Impuls. Bei INPUT_REPEAT_DELAY=18 und INPUT_REPEAT_RATE=5 folgt der nächste nach 19 Updates, weitere jeweils nach 6. Jede Taste hat einen eigenen Zähler. Die Makros müssen auch beim Kompilieren von input.c entsprechend gesetzt sein; nur den Header des aufrufenden Codes zu ändern, konfiguriert die Bibliothek nicht um.

btn_down

btn_down ist ein Alias für input_down. Prüft, ob mindestens eine der ausgewählten Tasten gerade gehalten wird.

Prüft, ob eine durch mask gewählte Taste gerade gehalten wird.

Syntax

c
u8 btn_down(u8 mask);

Parameter

mask

Eine BTN_*-Maske oder mehrere mit | verknüpfte Masken. Eine einzige passende Taste genügt; BTN_A | BTN_B verlangt nicht beide zugleich. Maske 0 liefert immer 0. Alle gehaltenen Tasten prüfst du mit (input_current() & mask) == mask.

Rückgabewert

Genau 1, wenn mindestens eine gewählte Taste die abgefragte Bedingung erfüllt, sonst 0. Der Rückgabewert ist keine Tastenmaske.

Bedingungen und Grenzen

Der Header definiert ein objektartiges Makro, das zum Implementierungsnamen expandiert. Argumente, Rückgabewerte und Zustandszugriffe entsprechen dem Ziel; der Alias fügt keinen eigenen Zustand oder Verarbeitungsschritt hinzu. Verwenden Sie wie im vollständigen Beispiel und Buildbefehl input.h/input.c für Eingaben oder system.h/system.c für Framedienste.

Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.

Abfragen lesen den letzten input_update()-Zustand, ohne erneut abzufragen, ein Ereignis zu verbrauchen oder einen Zähler weiterzuführen. Mehrfache Abfragen im selben Takt liefern dasselbe Ergebnis. Bei zweimaligem input_update() mit gehaltener Taste ist das neue Druckereignis im zweiten Aufruf gelöscht.

input_down

Anwendungsbeispiel

c
if (btn_down(BTN_A)!=0) held_ticks++;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieses Programm zeigt den Unterschied zwischen einer gehaltenen Taste, einem neuen Tastendruck, dem Loslassen und der automatischen Wiederholung. Halten Sie A für 40 Aktualisierungen gedrückt und lassen Sie die Taste dann los. FIRST DOWN, FIRST PRESS und FIRST REPEAT sind 1; FIRST CURRENT ist 16. HELD TICKS ist 40, PRESS COUNT ist 1 und REPEAT COUNT ist 5. Beim Loslassen ist RELEASE 1, LAST CURRENT 0 und LAST PREVIOUS 16. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Zähler; das Programm prüft die Wiederholungsabstände anhand der tatsächlich beobachteten Dauer.

btn_down: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-cache
Implementierung und Quelltext

kitaqfc/lib/input.h:53

c
#define btn_down input_down

kitaqfc/lib/input.c:85

c
u8 input_down(u8 mask) { return (u8)((kq_input_keys & mask) != 0); }
btn_pressed

btn_pressed ist ein Alias für input_pressed. Prüft, ob bei der letzten Eingabeaktualisierung mindestens eine ausgewählte Taste neu gedrückt wurde.

Prüft, ob eine maskierte Taste bei der letzten Eingabeaktualisierung neu gedrückt wurde.

Syntax

c
u8 btn_pressed(u8 mask);

Parameter

mask

Eine BTN_*-Maske oder mehrere mit | verknüpfte Masken. Eine einzige passende Taste genügt; BTN_A | BTN_B verlangt nicht beide zugleich. Maske 0 liefert immer 0. Alle gehaltenen Tasten prüfst du mit (input_current() & mask) == mask.

Rückgabewert

Genau 1, wenn mindestens eine gewählte Taste die abgefragte Bedingung erfüllt, sonst 0. Der Rückgabewert ist keine Tastenmaske.

Bedingungen und Grenzen

Der Header definiert ein objektartiges Makro, das zum Implementierungsnamen expandiert. Argumente, Rückgabewerte und Zustandszugriffe entsprechen dem Ziel; der Alias fügt keinen eigenen Zustand oder Verarbeitungsschritt hinzu. Verwenden Sie wie im vollständigen Beispiel und Buildbefehl input.h/input.c für Eingaben oder system.h/system.c für Framedienste.

Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.

Abfragen lesen den letzten input_update()-Zustand, ohne erneut abzufragen, ein Ereignis zu verbrauchen oder einen Zähler weiterzuführen. Mehrfache Abfragen im selben Takt liefern dasselbe Ergebnis. Bei zweimaligem input_update() mit gehaltener Taste ist das neue Druckereignis im zweiten Aufruf gelöscht.

input_pressed

Anwendungsbeispiel

c
if (btn_pressed(BTN_A)!=0) {
        press_count++; seen_press=1;
        first_down=btn_down(BTN_A); first_press=btn_pressed(BTN_A);
        first_repeat=btn_repeat(BTN_A);
        first_current=input_current(); // Only A held: BTN_A, or decimal 16.
        first_previous=input_previous(); // No buttons in the preceding sample: 0.
        if (first_down!=1 || first_press!=1 || first_repeat!=1) failures++;
        if (first_current!=BTN_A || first_previous!=0) failures++;
        if (btn_down(BTN_A|BTN_B)!=1 || btn_down(0)!=0) failures++;
    }

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieses Programm zeigt den Unterschied zwischen einer gehaltenen Taste, einem neuen Tastendruck, dem Loslassen und der automatischen Wiederholung. Halten Sie A für 40 Aktualisierungen gedrückt und lassen Sie die Taste dann los. FIRST DOWN, FIRST PRESS und FIRST REPEAT sind 1; FIRST CURRENT ist 16. HELD TICKS ist 40, PRESS COUNT ist 1 und REPEAT COUNT ist 5. Beim Loslassen ist RELEASE 1, LAST CURRENT 0 und LAST PREVIOUS 16. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Zähler; das Programm prüft die Wiederholungsabstände anhand der tatsächlich beobachteten Dauer.

btn_pressed: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-cache
Implementierung und Quelltext

kitaqfc/lib/input.h:54

c
#define btn_pressed input_pressed

kitaqfc/lib/input.c:87

c
u8 input_pressed(u8 mask) { return (u8)((kq_input_press_keys & mask) != 0); }
btn_released

btn_released ist ein Alias für input_released. Prüft, ob bei der letzten Eingabeaktualisierung mindestens eine ausgewählte Taste losgelassen wurde.

Prüft, ob eine maskierte Taste bei der letzten Eingabeaktualisierung losgelassen wurde.

Syntax

c
u8 btn_released(u8 mask);

Parameter

mask

Eine BTN_*-Maske oder mehrere mit | verknüpfte Masken. Eine einzige passende Taste genügt; BTN_A | BTN_B verlangt nicht beide zugleich. Maske 0 liefert immer 0. Alle gehaltenen Tasten prüfst du mit (input_current() & mask) == mask.

Rückgabewert

Genau 1, wenn mindestens eine gewählte Taste die abgefragte Bedingung erfüllt, sonst 0. Der Rückgabewert ist keine Tastenmaske.

Bedingungen und Grenzen

Der Header definiert ein objektartiges Makro, das zum Implementierungsnamen expandiert. Argumente, Rückgabewerte und Zustandszugriffe entsprechen dem Ziel; der Alias fügt keinen eigenen Zustand oder Verarbeitungsschritt hinzu. Verwenden Sie wie im vollständigen Beispiel und Buildbefehl input.h/input.c für Eingaben oder system.h/system.c für Framedienste.

Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.

Abfragen lesen den letzten input_update()-Zustand, ohne erneut abzufragen, ein Ereignis zu verbrauchen oder einen Zähler weiterzuführen. Mehrfache Abfragen im selben Takt liefern dasselbe Ergebnis. Bei zweimaligem input_update() mit gehaltener Taste ist das neue Druckereignis im zweiten Aufruf gelöscht.

input_released

Anwendungsbeispiel

c
if (btn_released(BTN_A)!=0) {
        release_result=btn_released(BTN_A);
        last_current=input_current(); last_previous=input_previous();
        if (btn_down(BTN_A)!=0 || btn_pressed(BTN_A)!=0 || btn_repeat(BTN_A)!=0) failures++;
        break;
    }

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieses Programm zeigt den Unterschied zwischen einer gehaltenen Taste, einem neuen Tastendruck, dem Loslassen und der automatischen Wiederholung. Halten Sie A für 40 Aktualisierungen gedrückt und lassen Sie die Taste dann los. FIRST DOWN, FIRST PRESS und FIRST REPEAT sind 1; FIRST CURRENT ist 16. HELD TICKS ist 40, PRESS COUNT ist 1 und REPEAT COUNT ist 5. Beim Loslassen ist RELEASE 1, LAST CURRENT 0 und LAST PREVIOUS 16. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Zähler; das Programm prüft die Wiederholungsabstände anhand der tatsächlich beobachteten Dauer.

btn_released: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-cache
Implementierung und Quelltext

kitaqfc/lib/input.h:55

c
#define btn_released input_released

kitaqfc/lib/input.c:89

c
u8 input_released(u8 mask) { return (u8)((kq_input_release_keys & mask) != 0); }
btn_repeat

btn_repeat ist ein Alias für input_repeat. Prüft auf den ersten Tastendruck oder einen vorgesehenen Wiederholungsimpuls bei gehaltener Taste.

Prüft auf erstmaligen Tastendruck oder einen Wiederholungsimpuls einer maskierten Taste.

Syntax

c
u8 btn_repeat(u8 mask);

Parameter

mask

Eine BTN_*-Maske oder mehrere mit | verknüpfte Masken. Eine einzige passende Taste genügt; BTN_A | BTN_B verlangt nicht beide zugleich. Maske 0 liefert immer 0. Alle gehaltenen Tasten prüfst du mit (input_current() & mask) == mask.

Rückgabewert

Genau 1, wenn mindestens eine gewählte Taste die abgefragte Bedingung erfüllt, sonst 0. Der Rückgabewert ist keine Tastenmaske.

Bedingungen und Grenzen

Der Header definiert ein objektartiges Makro, das zum Implementierungsnamen expandiert. Argumente, Rückgabewerte und Zustandszugriffe entsprechen dem Ziel; der Alias fügt keinen eigenen Zustand oder Verarbeitungsschritt hinzu. Verwenden Sie wie im vollständigen Beispiel und Buildbefehl input.h/input.c für Eingaben oder system.h/system.c für Framedienste.

Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.

Abfragen lesen den letzten input_update()-Zustand, ohne erneut abzufragen, ein Ereignis zu verbrauchen oder einen Zähler weiterzuführen. Mehrfache Abfragen im selben Takt liefern dasselbe Ergebnis. Bei zweimaligem input_update() mit gehaltener Taste ist das neue Druckereignis im zweiten Aufruf gelöscht.

Die Intervalle zählen Updates, keine Millisekunden. Ein neuer Tastendruck erzeugt sofort einen Impuls. Bei INPUT_REPEAT_DELAY=18 und INPUT_REPEAT_RATE=5 folgt der nächste nach 19 Updates, weitere jeweils nach 6. Jede Taste hat einen eigenen Zähler. Die Makros müssen auch beim Kompilieren von input.c entsprechend gesetzt sein; nur den Header des aufrufenden Codes zu ändern, konfiguriert die Bibliothek nicht um.

input_repeat

Anwendungsbeispiel

c
if (btn_repeat(BTN_A)!=0) {
        // The initial press is pulse 1. Defaults then wait 19 updates, followed by 6.
        if (repeat_count==1 && held_ticks-previous_pulse!=19) failures++;
        if (repeat_count>1 && held_ticks-previous_pulse!=6) failures++;
        previous_pulse=held_ticks; repeat_count++;
        if (btn_repeat(BTN_A)!=1) failures++; // Reading again does not consume it.
    }

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieses Programm zeigt den Unterschied zwischen einer gehaltenen Taste, einem neuen Tastendruck, dem Loslassen und der automatischen Wiederholung. Halten Sie A für 40 Aktualisierungen gedrückt und lassen Sie die Taste dann los. FIRST DOWN, FIRST PRESS und FIRST REPEAT sind 1; FIRST CURRENT ist 16. HELD TICKS ist 40, PRESS COUNT ist 1 und REPEAT COUNT ist 5. Beim Loslassen ist RELEASE 1, LAST CURRENT 0 und LAST PREVIOUS 16. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Zähler; das Programm prüft die Wiederholungsabstände anhand der tatsächlich beobachteten Dauer.

btn_repeat: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-cache
Implementierung und Quelltext

kitaqfc/lib/input.h:56

c
#define btn_repeat input_repeat

kitaqfc/lib/input.c:91

c
u8 input_repeat(u8 mask) { return (u8)((kq_input_repeat_keys & mask) != 0); }
input_current

Liefert die vollständige Maske gehaltener Tasten der letzten Aktualisierung.

Syntax

c
u8 input_current(void);

Rückgabewert

Eine 8-Bit-Maske im gemeinsamen BTN_*-Format. Mehrere Tasten können zugleich gesetzt sein; 0 bedeutet keine.

Bedingungen und Grenzen

Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.

Abfragen lesen den letzten input_update()-Zustand, ohne erneut abzufragen, ein Ereignis zu verbrauchen oder einen Zähler weiterzuführen. Mehrfache Abfragen im selben Takt liefern dasselbe Ergebnis. Bei zweimaligem input_update() mit gehaltener Taste ist das neue Druckereignis im zweiten Aufruf gelöscht.

Anwendungsbeispiel

c
first_current=input_current(); // Only A held: BTN_A, or decimal 16.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieses Programm zeigt den Unterschied zwischen einer gehaltenen Taste, einem neuen Tastendruck, dem Loslassen und der automatischen Wiederholung. Halten Sie A für 40 Aktualisierungen gedrückt und lassen Sie die Taste dann los. FIRST DOWN, FIRST PRESS und FIRST REPEAT sind 1; FIRST CURRENT ist 16. HELD TICKS ist 40, PRESS COUNT ist 1 und REPEAT COUNT ist 5. Beim Loslassen ist RELEASE 1, LAST CURRENT 0 und LAST PREVIOUS 16. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Zähler; das Programm prüft die Wiederholungsabstände anhand der tatsächlich beobachteten Dauer.

input_current: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-cache
Implementierung und Quelltext

kitaqfc/lib/input.h:49

Deklarationshinweise im Original
Read the complete translated held-button mask.

kitaqfc/lib/input.c:93

c
u8 input_current(void) { return kq_input_keys; }
input_down

Prüft, ob eine durch mask gewählte Taste gerade gehalten wird.

Syntax

c
u8 input_down(u8 mask);

Parameter

mask

Eine BTN_*-Maske oder mehrere mit | verknüpfte Masken. Eine einzige passende Taste genügt; BTN_A | BTN_B verlangt nicht beide zugleich. Maske 0 liefert immer 0. Alle gehaltenen Tasten prüfst du mit (input_current() & mask) == mask.

Rückgabewert

Genau 1, wenn mindestens eine gewählte Taste die abgefragte Bedingung erfüllt, sonst 0. Der Rückgabewert ist keine Tastenmaske.

Bedingungen und Grenzen

Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.

Abfragen lesen den letzten input_update()-Zustand, ohne erneut abzufragen, ein Ereignis zu verbrauchen oder einen Zähler weiterzuführen. Mehrfache Abfragen im selben Takt liefern dasselbe Ergebnis. Bei zweimaligem input_update() mit gehaltener Taste ist das neue Druckereignis im zweiten Aufruf gelöscht.

Anwendungsbeispiel

c
if (input_down(BTN_A)!=0) held_ticks++;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieses Programm zeigt den Unterschied zwischen einer gehaltenen Taste, einem neuen Tastendruck, dem Loslassen und der automatischen Wiederholung. Halten Sie A für 40 Aktualisierungen gedrückt und lassen Sie die Taste dann los. FIRST DOWN, FIRST PRESS und FIRST REPEAT sind 1; FIRST CURRENT ist 16. HELD TICKS ist 40, PRESS COUNT ist 1 und REPEAT COUNT ist 5. Beim Loslassen ist RELEASE 1, LAST CURRENT 0 und LAST PREVIOUS 16. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Zähler; das Programm prüft die Wiederholungsabstände anhand der tatsächlich beobachteten Dauer.

input_down: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-cache
Implementierung und Quelltext

kitaqfc/lib/input.h:41

Deklarationshinweise im Original
Return true when any masked logical button is held.

kitaqfc/lib/input.c:85

c
u8 input_down(u8 mask) { return (u8)((kq_input_keys & mask) != 0); }
input_init

Setzt die Masken für aktuellen und vorherigen Zustand, neue Tastendrücke, Loslassen und Wiederholung auf 0 und alle acht Wiederholungszähler auf INPUT_REPEAT_DELAY. Liest den Controller nicht. Eine beim ersten anschließenden Update gehaltene Taste gilt als neu gedrückt.

Syntax

c
void input_init(void);

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.

Die Intervalle zählen Updates, keine Millisekunden. Ein neuer Tastendruck erzeugt sofort einen Impuls. Bei INPUT_REPEAT_DELAY=18 und INPUT_REPEAT_RATE=5 folgt der nächste nach 19 Updates, weitere jeweils nach 6. Jede Taste hat einen eigenen Zähler. Die Makros müssen auch beim Kompilieren von input.c entsprechend gesetzt sein; nur den Header des aufrufenden Codes zu ändern, konfiguriert die Bibliothek nicht um.

Anwendungsbeispiel

c
input_init();
if (input_current()!=0 || input_previous()!=0) failures++;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieses Programm zeigt den Unterschied zwischen einer gehaltenen Taste, einem neuen Tastendruck, dem Loslassen und der automatischen Wiederholung. Halten Sie A für 40 Aktualisierungen gedrückt und lassen Sie die Taste dann los. FIRST DOWN, FIRST PRESS und FIRST REPEAT sind 1; FIRST CURRENT ist 16. HELD TICKS ist 40, PRESS COUNT ist 1 und REPEAT COUNT ist 5. Beim Loslassen ist RELEASE 1, LAST CURRENT 0 und LAST PREVIOUS 16. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Zähler; das Programm prüft die Wiederholungsabstände anhand der tatsächlich beobachteten Dauer.

input_init: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-cache
Implementierung und Quelltext

kitaqfc/lib/input.h:35

Deklarationshinweise im Original
Clear held/edge/repeat masks and reset each independent repeat countdown.

kitaqfc/lib/input.c:34

c
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

Prüft, ob eine maskierte Taste bei der letzten Eingabeaktualisierung neu gedrückt wurde.

Syntax

c
u8 input_pressed(u8 mask);

Parameter

mask

Eine BTN_*-Maske oder mehrere mit | verknüpfte Masken. Eine einzige passende Taste genügt; BTN_A | BTN_B verlangt nicht beide zugleich. Maske 0 liefert immer 0. Alle gehaltenen Tasten prüfst du mit (input_current() & mask) == mask.

Rückgabewert

Genau 1, wenn mindestens eine gewählte Taste die abgefragte Bedingung erfüllt, sonst 0. Der Rückgabewert ist keine Tastenmaske.

Bedingungen und Grenzen

Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.

Abfragen lesen den letzten input_update()-Zustand, ohne erneut abzufragen, ein Ereignis zu verbrauchen oder einen Zähler weiterzuführen. Mehrfache Abfragen im selben Takt liefern dasselbe Ergebnis. Bei zweimaligem input_update() mit gehaltener Taste ist das neue Druckereignis im zweiten Aufruf gelöscht.

Anwendungsbeispiel

c
if (input_pressed(BTN_A)!=0) {
        press_count++; seen_press=1;
        first_down=input_down(BTN_A); first_press=input_pressed(BTN_A);
        first_repeat=input_repeat(BTN_A);
        first_current=input_current(); // Only A held: BTN_A, or decimal 16.
        first_previous=input_previous(); // No buttons in the preceding sample: 0.
        if (first_down!=1 || first_press!=1 || first_repeat!=1) failures++;
        if (first_current!=BTN_A || first_previous!=0) failures++;
        if (input_down(BTN_A|BTN_B)!=1 || input_down(0)!=0) failures++;
    }

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieses Programm zeigt den Unterschied zwischen einer gehaltenen Taste, einem neuen Tastendruck, dem Loslassen und der automatischen Wiederholung. Halten Sie A für 40 Aktualisierungen gedrückt und lassen Sie die Taste dann los. FIRST DOWN, FIRST PRESS und FIRST REPEAT sind 1; FIRST CURRENT ist 16. HELD TICKS ist 40, PRESS COUNT ist 1 und REPEAT COUNT ist 5. Beim Loslassen ist RELEASE 1, LAST CURRENT 0 und LAST PREVIOUS 16. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Zähler; das Programm prüft die Wiederholungsabstände anhand der tatsächlich beobachteten Dauer.

input_pressed: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-cache
Implementierung und Quelltext

kitaqfc/lib/input.h:43

Deklarationshinweise im Original
Return true when any masked button became pressed in the latest input update.

kitaqfc/lib/input.c:87

c
u8 input_pressed(u8 mask) { return (u8)((kq_input_press_keys & mask) != 0); }
input_previous

Liefert die gespeicherte Tastenmaske vor der letzten Eingabeaktualisierung.

Syntax

c
u8 input_previous(void);

Rückgabewert

Eine 8-Bit-Maske im gemeinsamen BTN_*-Format. Mehrere Tasten können zugleich gesetzt sein; 0 bedeutet keine.

Bedingungen und Grenzen

Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.

Abfragen lesen den letzten input_update()-Zustand, ohne erneut abzufragen, ein Ereignis zu verbrauchen oder einen Zähler weiterzuführen. Mehrfache Abfragen im selben Takt liefern dasselbe Ergebnis. Bei zweimaligem input_update() mit gehaltener Taste ist das neue Druckereignis im zweiten Aufruf gelöscht.

Anwendungsbeispiel

c
first_previous=input_previous(); // No buttons in the preceding sample: 0.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieses Programm zeigt den Unterschied zwischen einer gehaltenen Taste, einem neuen Tastendruck, dem Loslassen und der automatischen Wiederholung. Halten Sie A für 40 Aktualisierungen gedrückt und lassen Sie die Taste dann los. FIRST DOWN, FIRST PRESS und FIRST REPEAT sind 1; FIRST CURRENT ist 16. HELD TICKS ist 40, PRESS COUNT ist 1 und REPEAT COUNT ist 5. Beim Loslassen ist RELEASE 1, LAST CURRENT 0 und LAST PREVIOUS 16. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Zähler; das Programm prüft die Wiederholungsabstände anhand der tatsächlich beobachteten Dauer.

input_previous: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-cache
Implementierung und Quelltext

kitaqfc/lib/input.h:51

Deklarationshinweise im Original
Read the translated held-button mask from before the latest update.

kitaqfc/lib/input.c:95

c
u8 input_previous(void) { return kq_input_prev_keys; }
input_released

Prüft, ob eine maskierte Taste bei der letzten Eingabeaktualisierung losgelassen wurde.

Syntax

c
u8 input_released(u8 mask);

Parameter

mask

Eine BTN_*-Maske oder mehrere mit | verknüpfte Masken. Eine einzige passende Taste genügt; BTN_A | BTN_B verlangt nicht beide zugleich. Maske 0 liefert immer 0. Alle gehaltenen Tasten prüfst du mit (input_current() & mask) == mask.

Rückgabewert

Genau 1, wenn mindestens eine gewählte Taste die abgefragte Bedingung erfüllt, sonst 0. Der Rückgabewert ist keine Tastenmaske.

Bedingungen und Grenzen

Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.

Abfragen lesen den letzten input_update()-Zustand, ohne erneut abzufragen, ein Ereignis zu verbrauchen oder einen Zähler weiterzuführen. Mehrfache Abfragen im selben Takt liefern dasselbe Ergebnis. Bei zweimaligem input_update() mit gehaltener Taste ist das neue Druckereignis im zweiten Aufruf gelöscht.

Anwendungsbeispiel

c
if (input_released(BTN_A)!=0) {
        release_result=input_released(BTN_A);
        last_current=input_current(); last_previous=input_previous();
        if (input_down(BTN_A)!=0 || input_pressed(BTN_A)!=0 || input_repeat(BTN_A)!=0) failures++;
        break;
    }

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieses Programm zeigt den Unterschied zwischen einer gehaltenen Taste, einem neuen Tastendruck, dem Loslassen und der automatischen Wiederholung. Halten Sie A für 40 Aktualisierungen gedrückt und lassen Sie die Taste dann los. FIRST DOWN, FIRST PRESS und FIRST REPEAT sind 1; FIRST CURRENT ist 16. HELD TICKS ist 40, PRESS COUNT ist 1 und REPEAT COUNT ist 5. Beim Loslassen ist RELEASE 1, LAST CURRENT 0 und LAST PREVIOUS 16. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Zähler; das Programm prüft die Wiederholungsabstände anhand der tatsächlich beobachteten Dauer.

input_released: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-cache
Implementierung und Quelltext

kitaqfc/lib/input.h:45

Deklarationshinweise im Original
Return true when any masked button became released in the latest update.

kitaqfc/lib/input.c:89

c
u8 input_released(u8 mask) { return (u8)((kq_input_release_keys & mask) != 0); }
input_repeat

Prüft auf erstmaligen Tastendruck oder einen Wiederholungsimpuls einer maskierten Taste.

Syntax

c
u8 input_repeat(u8 mask);

Parameter

mask

Eine BTN_*-Maske oder mehrere mit | verknüpfte Masken. Eine einzige passende Taste genügt; BTN_A | BTN_B verlangt nicht beide zugleich. Maske 0 liefert immer 0. Alle gehaltenen Tasten prüfst du mit (input_current() & mask) == mask.

Rückgabewert

Genau 1, wenn mindestens eine gewählte Taste die abgefragte Bedingung erfüllt, sonst 0. Der Rückgabewert ist keine Tastenmaske.

Bedingungen und Grenzen

Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.

Abfragen lesen den letzten input_update()-Zustand, ohne erneut abzufragen, ein Ereignis zu verbrauchen oder einen Zähler weiterzuführen. Mehrfache Abfragen im selben Takt liefern dasselbe Ergebnis. Bei zweimaligem input_update() mit gehaltener Taste ist das neue Druckereignis im zweiten Aufruf gelöscht.

Die Intervalle zählen Updates, keine Millisekunden. Ein neuer Tastendruck erzeugt sofort einen Impuls. Bei INPUT_REPEAT_DELAY=18 und INPUT_REPEAT_RATE=5 folgt der nächste nach 19 Updates, weitere jeweils nach 6. Jede Taste hat einen eigenen Zähler. Die Makros müssen auch beim Kompilieren von input.c entsprechend gesetzt sein; nur den Header des aufrufenden Codes zu ändern, konfiguriert die Bibliothek nicht um.

Anwendungsbeispiel

c
if (input_repeat(BTN_A)!=0) {
        // The initial press is pulse 1. Defaults then wait 19 updates, followed by 6.
        if (repeat_count==1 && held_ticks-previous_pulse!=19) failures++;
        if (repeat_count>1 && held_ticks-previous_pulse!=6) failures++;
        previous_pulse=held_ticks; repeat_count++;
        if (input_repeat(BTN_A)!=1) failures++; // Reading again does not consume it.
    }

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieses Programm zeigt den Unterschied zwischen einer gehaltenen Taste, einem neuen Tastendruck, dem Loslassen und der automatischen Wiederholung. Halten Sie A für 40 Aktualisierungen gedrückt und lassen Sie die Taste dann los. FIRST DOWN, FIRST PRESS und FIRST REPEAT sind 1; FIRST CURRENT ist 16. HELD TICKS ist 40, PRESS COUNT ist 1 und REPEAT COUNT ist 5. Beim Loslassen ist RELEASE 1, LAST CURRENT 0 und LAST PREVIOUS 16. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Zähler; das Programm prüft die Wiederholungsabstände anhand der tatsächlich beobachteten Dauer.

input_repeat: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-cache
Implementierung und Quelltext

kitaqfc/lib/input.h:47

Deklarationshinweise im Original
Return true for a masked initial press or scheduled repeat pulse.

kitaqfc/lib/input.c:91

c
u8 input_repeat(u8 mask) { return (u8)((kq_input_repeat_keys & mask) != 0); }
input_update

Liest Controller 1 mit __pad_read1_safe, ordnet die NES-Bits in das gemeinsame BTN_*-Format um, speichert den vorherigen Zustand und berechnet Druck-, Loslass- und Wiederholungsmasken. Controller 2 wird nicht erfasst. Einmal pro Eingabetakt aufrufen.

Syntax

c
void input_update(void);

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Gemeinsame Masken: BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80. Ein gesetztes Bit bedeutet gedrückt. input_* verwendet dieses Format auf GB und FC; rohe FC-Pad-Abfragen verwenden eine andere Bitreihenfolge.

Die Intervalle zählen Updates, keine Millisekunden. Ein neuer Tastendruck erzeugt sofort einen Impuls. Bei INPUT_REPEAT_DELAY=18 und INPUT_REPEAT_RATE=5 folgt der nächste nach 19 Updates, weitere jeweils nach 6. Jede Taste hat einen eigenen Zähler. Die Makros müssen auch beim Kompilieren von input.c entsprechend gesetzt sein; nur den Header des aufrufenden Codes zu ändern, konfiguriert die Bibliothek nicht um.

Die sichere Abfrage wiederholt Paare vollständiger Lesevorgänge, bis beide Masken übereinstimmen. Jeder Lesevorgang strobt $4016 und setzt die serielle Leseposition beider Controller zurück. Die Zahl der Versuche ist unbegrenzt. Diese Prüfung belegt keine Kompatibilität mit sämtlichen DMC-/Peripheriekombinationen.

Anwendungsbeispiel

c
input_update(); // One update per input tick, followed by any number of queries.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieses Programm zeigt den Unterschied zwischen einer gehaltenen Taste, einem neuen Tastendruck, dem Loslassen und der automatischen Wiederholung. Halten Sie A für 40 Aktualisierungen gedrückt und lassen Sie die Taste dann los. FIRST DOWN, FIRST PRESS und FIRST REPEAT sind 1; FIRST CURRENT ist 16. HELD TICKS ist 40, PRESS COUNT ist 1 und REPEAT COUNT ist 5. Beim Loslassen ist RELEASE 1, LAST CURRENT 0 und LAST PREVIOUS 16. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Zähler; das Programm prüft die Wiederholungsabstände anhand der tatsächlich beobachteten Dauer.

input_update: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-cache
Implementierung und Quelltext

kitaqfc/lib/input.h:39

Deklarationshinweise im Original
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

c
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 — Wiederholung bei gehaltener Taste

Diese Ergänzung zu pad.c fügt Controller 1 unabhängige Wiederholungszähler pro Taste hinzu. Wartezeit und Intervall zur Laufzeit einstellen, den Controller abfragen und die Wiederholung einmal pro Takt weiterführen. Druck-, Loslass- und Halteabfragen nutzen den Controllerzustand; nur die Wiederholungsabfrage hängt von nes_pad_repeat_step() ab.

Anfangszähler von 0 bis 255. Nach dem sofortigen Impuls eines neuen Tastendrucks folgt der nächste nach delay + 1 Wiederholungsschritten. Gezählt werden Aufrufe von nes_pad_repeat_step(), nur bei genau einem Aufruf pro Frame entsprechen sie Frames.

Zähler zwischen späteren Impulsen, von 0 bis 255. Das tatsächliche Intervall beträgt interval + 1 Schritte; 0 liefert nach der Anfangswartezeit in jedem gehaltenen Schritt einen Impuls. Die acht Tastenzähler arbeiten unabhängig.

nes_pad_held

Filtert die zuletzt erfassten gehaltenen Tasten von Controller 1. Für fortlaufende Aktionen, solange ausgewählte Tasten gedrückt bleiben. Liest den gespeicherten Zustand ohne erneute Hardwareabfrage.

Syntax

c
unsigned char nes_pad_held(unsigned char mask);

Parameter

mask

Die im rohen NES-Bitformat beizubehaltenden Tasten, bei Bedarf mit | kombiniert. 0 wählt nichts. Das Argument ist ein Filter, keine Controller-Portnummer.

Rückgabewert

Die passenden Bits der gespeicherten Maske an ihren ursprünglichen Positionen. Der Wert kann größer als 1 sein; 0 bedeutet kein Treffer. Die Abfrage verbraucht das Ereignis nicht.

Bedingungen und Grenzen

Rohes NES-Format: A=0x01, B=0x02, SELECT=0x04, START=0x08, UP=0x10, DOWN=0x20, LEFT=0x40, RIGHT=0x80. Ein gesetztes Bit bedeutet gedrückt. Verwende diese Werte mit nes_pad_* und rohen __pad_*-Ergebnissen, nicht die gemeinsamen BTN_*-Masken aus input.h.

Initialisiere die vier nes_pad1_*-Zustandsbytes vor der ersten Abfrage mit 0. Danach einmal pro Eingabetakt abfragen. pressed = current & ~previous und released = previous & ~current beschreiben die letzte Abfrage. Der Wiederholungszustand wird separat durch nes_pad_repeat_step() aktualisiert.

Anwendungsbeispiel

c
if (nes_pad_held(0x02)!=0) held_ticks++; // B is bit 1 in NES raw format.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieses Programm erklärt die Reihenfolge Einlesen → Wiederholung aktualisieren → Zustand abfragen und zeigt, dass die NES-Abfragen maskierte Bits statt des Wahrheitswerts 1 liefern. Verwenden Sie nes_pad_repeat_config(3, 1), halten Sie B für 40 Aktualisierungen gedrückt und lassen Sie los. FIRST HELD, FIRST TRIGGER und FIRST REPEAT sind 2; HELD TICKS ist 40, PULSE COUNT ist 19 und RELEASE BITS ist 2. Die erste Wiederholung folgt vier Aktualisierungen nach dem ersten Impuls; danach beträgt der Abstand zwei Aktualisierungen. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Impulszahl.

nes_pad_held: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-cache
Implementierung und Quelltext

kitaqfc/lib/input_repeat.h:28

Deklarationshinweise im Original
Return the requested currently-held bits in the NES pad layout.

kitaqfc/lib/input_repeat.c:103

c
unsigned char nes_pad_held(unsigned char mask)
{
    return (unsigned char)(nes_pad1_cur & mask);
}
nes_pad_release

Filtert die Loslassereignisse von Controller 1: ausgewählte Tasten, die zuvor gehalten wurden und nun losgelassen sind. Weiteres Loslassen erzeugt bei der nächsten Abfrage kein neues Ereignis.

Syntax

c
unsigned char nes_pad_release(unsigned char mask);

Parameter

mask

Die im rohen NES-Bitformat beizubehaltenden Tasten, bei Bedarf mit | kombiniert. 0 wählt nichts. Das Argument ist ein Filter, keine Controller-Portnummer.

Rückgabewert

Die passenden Bits der gespeicherten Maske an ihren ursprünglichen Positionen. Der Wert kann größer als 1 sein; 0 bedeutet kein Treffer. Die Abfrage verbraucht das Ereignis nicht.

Bedingungen und Grenzen

Rohes NES-Format: A=0x01, B=0x02, SELECT=0x04, START=0x08, UP=0x10, DOWN=0x20, LEFT=0x40, RIGHT=0x80. Ein gesetztes Bit bedeutet gedrückt. Verwende diese Werte mit nes_pad_* und rohen __pad_*-Ergebnissen, nicht die gemeinsamen BTN_*-Masken aus input.h.

Initialisiere die vier nes_pad1_*-Zustandsbytes vor der ersten Abfrage mit 0. Danach einmal pro Eingabetakt abfragen. pressed = current & ~previous und released = previous & ~current beschreiben die letzte Abfrage. Der Wiederholungszustand wird separat durch nes_pad_repeat_step() aktualisiert.

Anwendungsbeispiel

c
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;
    }

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieses Programm erklärt die Reihenfolge Einlesen → Wiederholung aktualisieren → Zustand abfragen und zeigt, dass die NES-Abfragen maskierte Bits statt des Wahrheitswerts 1 liefern. Verwenden Sie nes_pad_repeat_config(3, 1), halten Sie B für 40 Aktualisierungen gedrückt und lassen Sie los. FIRST HELD, FIRST TRIGGER und FIRST REPEAT sind 2; HELD TICKS ist 40, PULSE COUNT ist 19 und RELEASE BITS ist 2. Die erste Wiederholung folgt vier Aktualisierungen nach dem ersten Impuls; danach beträgt der Abstand zwei Aktualisierungen. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Impulszahl.

nes_pad_release: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-cache
Implementierung und Quelltext

kitaqfc/lib/input_repeat.h:26

Deklarationshinweise im Original
Return the requested newly-released bits from the latest pad poll.

kitaqfc/lib/input_repeat.c:97

c
unsigned char nes_pad_release(unsigned char mask)
{
    return (unsigned char)(nes_pad1_released & mask);
}
nes_pad_repeat

Filtert die Impulse des letzten nes_pad_repeat_step(). Enthält neue Tastendrücke und geplante Wiederholungen beim Halten. Diese Abfrage führt die Zähler nicht weiter.

Syntax

c
unsigned char nes_pad_repeat(unsigned char mask);

Parameter

mask

Die im rohen NES-Bitformat beizubehaltenden Tasten, bei Bedarf mit | kombiniert. 0 wählt nichts. Das Argument ist ein Filter, keine Controller-Portnummer.

Rückgabewert

Die passenden Bits der gespeicherten Maske an ihren ursprünglichen Positionen. Der Wert kann größer als 1 sein; 0 bedeutet kein Treffer. Die Abfrage verbraucht das Ereignis nicht.

Bedingungen und Grenzen

Rohes NES-Format: A=0x01, B=0x02, SELECT=0x04, START=0x08, UP=0x10, DOWN=0x20, LEFT=0x40, RIGHT=0x80. Ein gesetztes Bit bedeutet gedrückt. Verwende diese Werte mit nes_pad_* und rohen __pad_*-Ergebnissen, nicht die gemeinsamen BTN_*-Masken aus input.h.

Initialisiere die vier nes_pad1_*-Zustandsbytes vor der ersten Abfrage mit 0. Danach einmal pro Eingabetakt abfragen. pressed = current & ~previous und released = previous & ~current beschreiben die letzte Abfrage. Der Wiederholungszustand wird separat durch nes_pad_repeat_step() aktualisiert.

Anwendungsbeispiel

c
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.
    }

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieses Programm erklärt die Reihenfolge Einlesen → Wiederholung aktualisieren → Zustand abfragen und zeigt, dass die NES-Abfragen maskierte Bits statt des Wahrheitswerts 1 liefern. Verwenden Sie nes_pad_repeat_config(3, 1), halten Sie B für 40 Aktualisierungen gedrückt und lassen Sie los. FIRST HELD, FIRST TRIGGER und FIRST REPEAT sind 2; HELD TICKS ist 40, PULSE COUNT ist 19 und RELEASE BITS ist 2. Die erste Wiederholung folgt vier Aktualisierungen nach dem ersten Impuls; danach beträgt der Abstand zwei Aktualisierungen. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Impulszahl.

nes_pad_repeat: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-cache
Implementierung und Quelltext

kitaqfc/lib/input_repeat.h:24

Deklarationshinweise im Original
Return the requested repeat-pulse bits from the latest repeat step.

kitaqfc/lib/input_repeat.c:91

c
unsigned char nes_pad_repeat(unsigned char mask)
{
    return (unsigned char)(nes_pad1_repeat & mask);
}
nes_pad_repeat_config

Setzt zur Laufzeit Anfangswartezeit und Wiederholungsintervall, löscht nes_pad1_repeat und setzt die acht Tastenzähler auf delay. Fragt den Controller nicht ab und löscht keine Halte-, Druck- oder Loslassmasken.

Syntax

c
void nes_pad_repeat_config(unsigned char delay, unsigned char interval);

Parameter

delay

Anfangszähler von 0 bis 255. Nach dem sofortigen Impuls eines neuen Tastendrucks folgt der nächste nach delay + 1 Wiederholungsschritten. Gezählt werden Aufrufe von nes_pad_repeat_step(), nur bei genau einem Aufruf pro Frame entsprechen sie Frames.

interval

Zähler zwischen späteren Impulsen, von 0 bis 255. Das tatsächliche Intervall beträgt interval + 1 Schritte; 0 liefert nach der Anfangswartezeit in jedem gehaltenen Schritt einen Impuls. Die acht Tastenzähler arbeiten unabhängig.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Rohes NES-Format: A=0x01, B=0x02, SELECT=0x04, START=0x08, UP=0x10, DOWN=0x20, LEFT=0x40, RIGHT=0x80. Ein gesetztes Bit bedeutet gedrückt. Verwende diese Werte mit nes_pad_* und rohen __pad_*-Ergebnissen, nicht die gemeinsamen BTN_*-Masken aus input.h.

Anwendungsbeispiel

c
nes_pad_repeat_config(3,1); // Next pulse after 4 held updates, then every 2.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieses Programm erklärt die Reihenfolge Einlesen → Wiederholung aktualisieren → Zustand abfragen und zeigt, dass die NES-Abfragen maskierte Bits statt des Wahrheitswerts 1 liefern. Verwenden Sie nes_pad_repeat_config(3, 1), halten Sie B für 40 Aktualisierungen gedrückt und lassen Sie los. FIRST HELD, FIRST TRIGGER und FIRST REPEAT sind 2; HELD TICKS ist 40, PULSE COUNT ist 19 und RELEASE BITS ist 2. Die erste Wiederholung folgt vier Aktualisierungen nach dem ersten Impuls; danach beträgt der Abstand zwei Aktualisierungen. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Impulszahl.

nes_pad_repeat_config: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-cache
Implementierung und Quelltext

kitaqfc/lib/input_repeat.h:16

Deklarationshinweise im Original
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

c
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

Berechnet nes_pad1_repeat aus den zuletzt abgefragten Halte- und Druckmasken neu und führt jeden Zähler um einen Schritt weiter. Zuerst nes_pad_poll(), dann diese Funktion einmal aufrufen. Eine veraltete Druckmaske setzt die Anfangswartezeit immer wieder zurück und erzeugt wiederholt Anfangsimpulse.

Syntax

c
void nes_pad_repeat_step(void);

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Rohes NES-Format: A=0x01, B=0x02, SELECT=0x04, START=0x08, UP=0x10, DOWN=0x20, LEFT=0x40, RIGHT=0x80. Ein gesetztes Bit bedeutet gedrückt. Verwende diese Werte mit nes_pad_* und rohen __pad_*-Ergebnissen, nicht die gemeinsamen BTN_*-Masken aus input.h.

Initialisiere die vier nes_pad1_*-Zustandsbytes vor der ersten Abfrage mit 0. Danach einmal pro Eingabetakt abfragen. pressed = current & ~previous und released = previous & ~current beschreiben die letzte Abfrage. Der Wiederholungszustand wird separat durch nes_pad_repeat_step() aktualisiert.

Anwendungsbeispiel

c
nes_pad_repeat_step(); // Once after each fresh poll; getters do not advance time.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieses Programm erklärt die Reihenfolge Einlesen → Wiederholung aktualisieren → Zustand abfragen und zeigt, dass die NES-Abfragen maskierte Bits statt des Wahrheitswerts 1 liefern. Verwenden Sie nes_pad_repeat_config(3, 1), halten Sie B für 40 Aktualisierungen gedrückt und lassen Sie los. FIRST HELD, FIRST TRIGGER und FIRST REPEAT sind 2; HELD TICKS ist 40, PULSE COUNT ist 19 und RELEASE BITS ist 2. Die erste Wiederholung folgt vier Aktualisierungen nach dem ersten Impuls; danach beträgt der Abstand zwei Aktualisierungen. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Impulszahl.

nes_pad_repeat_step: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-cache
Implementierung und Quelltext

kitaqfc/lib/input_repeat.h:20

Deklarationshinweise im Original
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

c
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

Filtert mit mask die neuen Tastendrücke von Controller 1. Für eine einmalige Aktion beim Wechsel einer ausgewählten Taste von losgelassen zu gedrückt.

Syntax

c
unsigned char nes_pad_trigger(unsigned char mask);

Parameter

mask

Die im rohen NES-Bitformat beizubehaltenden Tasten, bei Bedarf mit | kombiniert. 0 wählt nichts. Das Argument ist ein Filter, keine Controller-Portnummer.

Rückgabewert

Die passenden Bits der gespeicherten Maske an ihren ursprünglichen Positionen. Der Wert kann größer als 1 sein; 0 bedeutet kein Treffer. Die Abfrage verbraucht das Ereignis nicht.

Bedingungen und Grenzen

Rohes NES-Format: A=0x01, B=0x02, SELECT=0x04, START=0x08, UP=0x10, DOWN=0x20, LEFT=0x40, RIGHT=0x80. Ein gesetztes Bit bedeutet gedrückt. Verwende diese Werte mit nes_pad_* und rohen __pad_*-Ergebnissen, nicht die gemeinsamen BTN_*-Masken aus input.h.

Initialisiere die vier nes_pad1_*-Zustandsbytes vor der ersten Abfrage mit 0. Danach einmal pro Eingabetakt abfragen. pressed = current & ~previous und released = previous & ~current beschreiben die letzte Abfrage. Der Wiederholungszustand wird separat durch nes_pad_repeat_step() aktualisiert.

Anwendungsbeispiel

c
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++;
    }

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieses Programm erklärt die Reihenfolge Einlesen → Wiederholung aktualisieren → Zustand abfragen und zeigt, dass die NES-Abfragen maskierte Bits statt des Wahrheitswerts 1 liefern. Verwenden Sie nes_pad_repeat_config(3, 1), halten Sie B für 40 Aktualisierungen gedrückt und lassen Sie los. FIRST HELD, FIRST TRIGGER und FIRST REPEAT sind 2; HELD TICKS ist 40, PULSE COUNT ist 19 und RELEASE BITS ist 2. Die erste Wiederholung folgt vier Aktualisierungen nach dem ersten Impuls; danach beträgt der Abstand zwei Aktualisierungen. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Impulszahl.

nes_pad_trigger: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-cache
Implementierung und Quelltext

kitaqfc/lib/input_repeat.h:22

Deklarationshinweise im Original
Return the requested newly-pressed bits, not a normalized Boolean.

kitaqfc/lib/input_repeat.c:85

c
unsigned char nes_pad_trigger(unsigned char mask)
{
    return (unsigned char)(nes_pad1_pressed & mask);
}

metasprite.h — Bilder aus mehreren Sprites

Verfügbar als C-Funktion in metasprite.c sowie als Makro in nes_game.h, das zu __metasprite_draw expandiert. Beide lesen denselben terminierten Datenstrom und schreiben identische OAM-Einträge aus vier Bytes. Die Beispiele kompilieren beide Formen getrennt.

Die C-Metasprite-Funktionen benötigen nes_oam_shadow[256]. runtime.c definiert diesen Puffer bei 0x0200, reserviert zusätzlich 0x0300–0x03BF für seine VRAM-Warteschlange und stellt __nes_nmi bereit. Binden Sie jede Implementierung nur einmal ein und stimmen Sie die Interruptbehandlung mit dem übrigen Programm ab.

nes_metasprite_draw

Verfügbar als C-Funktion in metasprite.c sowie als Makro in nes_game.h, das zu __metasprite_draw expandiert. Beide lesen denselben terminierten Datenstrom und schreiben identische OAM-Einträge aus vier Bytes. Die Beispiele kompilieren beide Formen getrennt.

Entpackt eine mit einer Endmarkierung versehene Folge von Sprite-Teilen in aufeinanderfolgende Einträge des Schattenpuffers der Seite 02. Jeder Teil addiert seine X/Y-Offsets von je einem Byte zur Basisposition und enthält eine eigene Kachel samt Attributen. Zurückgegeben wird der nächste OAM-Index.

Syntax

c
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))

Parameter

oam_index / i

Sprite-Index von 0 bis 63, kein Byte-Offset. Intern wird er mit vier multipliziert und als 8-Bit-Position gespeichert. Werte außerhalb des Bereichs werden modulo 64 umgebrochen und können einen anderen Eintrag überschreiben. Eine Belegungsprüfung findet nicht statt.

base_x / x

Horizontale Position in Pixeln als vorzeichenloses Byte; keine Tile-Koordinate.

base_y / y

Y-Byte des OAM. Für eine Oberkante unterhalb der Zeile null wird ihre Position minus eins übergeben; 239..255 liegen außerhalb der 240 sichtbaren Zeilen.

metasprite / data

Zeiger auf lesbare Datensätze aus vier Byte: dx, dy, tile, attr. Ein 0xFF an der nächsten dx-Position beendet die Folge; weitere Bytes sind nicht nötig. Offsets werden modulo 256 addiert: 0xFE steht für −2 und dy=0xFF darf −1 darstellen. dx=0xFF ist hingegen die Endmarkierung und kann nicht für −1 verwendet werden. Der Zeiger muss im eingeblendeten Speicher gültig sein.

Rückgabewert

Nächster OAM-Index: (oam_index + geschriebene_Teile) modulo 64. Das ist eine Schreibposition, nicht die Anzahl gezeichneter Teile. Bei einer leeren Folge wird oam_index modulo 64 zurückgegeben.

Bedingungen und Grenzen

Wählen Sie die Header bewusst: nes_game.h und der Sammelheader fc.h definieren die Makros. Für die C-Funktionen binden Sie runtime.h beziehungsweise metasprite.h samt Implementierungen ohne diese Makros ein, oder entfernen Sie die gleichnamigen Makros zuvor mit #undef. Das parameterlose DMA-Makro akzeptiert das Argument page der C-Funktion nicht.

Die C-Metasprite-Funktionen benötigen nes_oam_shadow[256]. runtime.c definiert diesen Puffer bei 0x0200, reserviert zusätzlich 0x0300–0x03BF für seine VRAM-Warteschlange und stellt __nes_nmi bereit. Binden Sie jede Implementierung nur einmal ein und stimmen Sie die Interruptbehandlung mit dem übrigen Programm ab.

Diese Operationen ändern den CPU-RAM bei 0x0200–0x02FF, nicht sofort das Hardware-OAM. Übertragen Sie die fertige Seite mit __oam_dma. Belegungsflags, Koordinatenfelder und Zähler der Sprite-Bibliothek werden nicht mitgeführt. Interrupt-Routinen dürfen eine noch unvollständige Seite weder ändern noch übertragen.

Anzahl der Teile, Bildausschnitt und Kapazität werden nicht geprüft. Fügen Sie eine Endmarkierung ein und verwenden Sie höchstens 64−oam_index Teile. Koordinaten laufen modulo 256 über; nach Eintrag 63 wird bei Eintrag 0 weitergeschrieben. Eine leere Folge ändert nichts. Das Format unterscheidet sich vom MetaSpritePart-Array mit expliziter Anzahl, das metasprite_draw in der Sprite-Bibliothek verwendet.

Anwendungsbeispiel

c
demo_next=nes_metasprite_draw(4,144,31,demo_parts); // C function: returns 6.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

C-RUNTIME kombiniert die C-Funktionen. PAIR zeigt zwei 8×8-Pfeile bei (144,32) und (152,32), den zweiten horizontal gespiegelt. Ein weiteres Paar bei y=64 wird ausgeblendet; HIDE RANGE muss daher leer bleiben. Die beiden Zeichenaufrufe verwenden die Slots 4–5 und 6–7 und ergeben NEXT 08. Seite 02 wird nach Seite 04 kopiert; nur Slot 8 wechselt vom Pfeil-Tile 128 zum Quadrat-Tile 129. nes_oam_dma(4) muss neben PAGE 04 bei (144,96) ein grünes Quadrat anzeigen, während Seite 02 Tile 128 behält.

Die Pfeile haben rote Ränder, grüne Schäfte und blaue Details an der Spitze; das Quadrat-Tile 129 ist grün. Die Prüfung vergleicht pro Bild 8.704 Farbpixel, alle 256 übertragenen OAM-Bytes und die Beschriftungen. Physische Hardware wurde nicht getestet.

nes_metasprite_draw: C-Laufzeit
C-Laufzeit

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm

Anwendungsbeispiel

c
fc_oam_next=nes_metasprite_draw(5,136,95,fc_oam_pair); // Returns 7 after two entries.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel zeigt jede Operation in einer beschrifteten Zeile. SET und MOVE zeigen 8×8-Pfeile nach rechts bei (144,16) und (144,32), TILE ein grünes Quadrat bei (144,48) und ATTR den in beiden Achsen gespiegelten Pfeil bei (144,64). HIDE bei (144,80) und CLEAR bei (144,112) müssen leer bleiben. META zeigt zwei Pfeile bei (136,96) und (144,96), den zweiten horizontal gespiegelt. NEXT 07 bezeichnet die nächste Position nach den Einträgen 5 und 6. Die Ränder sind rot, der Schaft grün und die Spitzendetails blau. Geprüft werden 8.704 Pixel je Bild und die übertragenen OAM-Bytes; echte Hardware wurde nicht getestet.

Das Programm ALIASES bereitet die beschrifteten Zeilen mit Makros aus nes_game.h vor und sendet Seite 02 mit nes_oam_dma(). TRANSFER zeigt den 8×8-Pfeil bei (144,128). Das Beispiel verwendet die Makros, ohne runtime.c oder metasprite.c einzubinden.

nes_metasprite_draw: Aliasse
Aliasse

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/metasprite.h:12

Deklarationshinweise im Original
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

c
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

Blendet aufeinanderfolgende Einträge im OAM-Schattenpuffer aus, indem jedes Y-Byte auf 0xF8 gesetzt wird. Tile, Attribute und X bleiben erhalten. Diese C-Funktion überträgt kein OAM und gibt keine Belegungen der Sprite-Bibliothek frei.

Syntax

c
void nes_metasprite_hide_from(unsigned char oam_index, unsigned char sprite_count);

Parameter

oam_index

Sprite-Index von 0 bis 63, kein Byte-Offset. Intern wird er mit vier multipliziert und als 8-Bit-Position gespeichert. Werte außerhalb des Bereichs werden modulo 64 umgebrochen und können einen anderen Eintrag überschreiben. Eine Belegungsprüfung findet nicht statt.

sprite_count

Anzahl auszublendender Einträge von 0 bis 64−oam_index. Null verändert nichts. Bei größeren Werten läuft der Bytezeiger zum Anfang zurück und kann dort OAM-Einträge ausblenden; die Funktion prüft den Bereich nicht.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Die C-Metasprite-Funktionen benötigen nes_oam_shadow[256]. runtime.c definiert diesen Puffer bei 0x0200, reserviert zusätzlich 0x0300–0x03BF für seine VRAM-Warteschlange und stellt __nes_nmi bereit. Binden Sie jede Implementierung nur einmal ein und stimmen Sie die Interruptbehandlung mit dem übrigen Programm ab.

Diese Operationen ändern den CPU-RAM bei 0x0200–0x02FF, nicht sofort das Hardware-OAM. Übertragen Sie die fertige Seite mit __oam_dma. Belegungsflags, Koordinatenfelder und Zähler der Sprite-Bibliothek werden nicht mitgeführt. Interrupt-Routinen dürfen eine noch unvollständige Seite weder ändern noch übertragen.

Anwendungsbeispiel

c
nes_metasprite_hide_from(6,2); // Hide slots 6 and 7; the pair at slots 4 and 5 remains.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

C-RUNTIME kombiniert die C-Funktionen. PAIR zeigt zwei 8×8-Pfeile bei (144,32) und (152,32), den zweiten horizontal gespiegelt. Ein weiteres Paar bei y=64 wird ausgeblendet; HIDE RANGE muss daher leer bleiben. Die beiden Zeichenaufrufe verwenden die Slots 4–5 und 6–7 und ergeben NEXT 08. Seite 02 wird nach Seite 04 kopiert; nur Slot 8 wechselt vom Pfeil-Tile 128 zum Quadrat-Tile 129. nes_oam_dma(4) muss neben PAGE 04 bei (144,96) ein grünes Quadrat anzeigen, während Seite 02 Tile 128 behält.

Die Pfeile haben rote Ränder, grüne Schäfte und blaue Details an der Spitze; das Quadrat-Tile 129 ist grün. Die Prüfung vergleicht pro Bild 8.704 Farbpixel, alle 256 übertragenen OAM-Bytes und die Beschriftungen. Physische Hardware wurde nicht getestet.

nes_metasprite_hide_from: C-Laufzeit
C-Laufzeit

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/metasprite.h:17

Deklarationshinweise im Original
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

c
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 — Nametable-Ressourcen und ihre Platzierung

Überträgt 32-Kachelzeilen, Rechtecke mit Zeilenabstand, Füllungen und vollständige Bildschirme mit 960+64 Bytes; bearbeitet und überträgt auch Attributschattendaten. Wählen Sie je nach Situation sofortige Übertragungen oder späteren Warteschlangenverbrauch.

Setzen Sie bei direkten Übertragungen das PPUCTRL-Inkrement auf eins und verwenden Sie die Einrichtung bei ausgeschalteter Darstellung oder ein ausreichend langes VBlank-Fenster. Diese Hilfsfunktionen schalten die Darstellung nicht aus und warten nicht.

Binden Sie runtime.c ein. Die Warteschlange kopiert Nutzdaten für eine spätere NMI oder eine sichere Übertragung bei ausgeschalteter Darstellung. Serialisieren Sie Erzeugung und Verbrauch. Geht bei mehreren Zeilen die Kapazität aus, bleiben zuvor aufgenommene Zeilen eingereiht.

nes_attr_apply_now

Überträgt alle 64 Schattenbytes sofort in die Attributtabelle einer Nametable.

Syntax

c
void nes_attr_apply_now(unsigned short nt_base);

Parameter

nt_base

Logische Nametable-Basis $2000/$2400/$2800/$2C00; die Spiegelung bestimmt die physische Unabhängigkeit.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Der gemeinsame 64-Byte-Attributschattenpuffer belegt CPU-RAM $03E0..$041F. Reservieren Sie diesen Bereich. Ein Attributbyte deckt 4×4 Kacheln ab; jedes Zwei-Bit-Feld wählt die Palette für einen 2×2-Kachelquadranten.

Setzen Sie bei direkten Übertragungen das PPUCTRL-Inkrement auf eins und verwenden Sie die Einrichtung bei ausgeschalteter Darstellung oder ein ausreichend langes VBlank-Fenster. Diese Hilfsfunktionen schalten die Darstellung nicht aus und warten nicht.

Anwendungsbeispiel

c
nes_attr_apply_now(0x2000);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Kombinieren Sie Zeilen-, Rechteck-, Füll- und vollständige Tabellenübertragungen. Zwei rote 32×8-Balken erscheinen über einem blauen 16×16-Quadrat und roten 16×24/32×24-Rechtecken. Direkte und eingereihte Übertragungen zeichnen an unterschiedlichen Positionen.

nes_attr_apply_now: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/nametable_asset.h:20

Deklarationshinweise im Original
Upload all attribute shadow bytes immediately; the caller provides safe PPU timing.

kitaqfc/lib/nametable_asset.c:90

c
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

Addiert $3C0 zur Nametable-Basis, um ihre Attributtabelle zu finden.

Syntax

c
unsigned short nes_attr_base_from_nt(unsigned short nt_base);

Parameter

nt_base

Logische Nametable-Basis $2000/$2400/$2800/$2C00; die Spiegelung bestimmt die physische Unabhängigkeit.

Rückgabewert

Gibt nt_base+$3C0 ohne Eingabeprüfung zurück.

Anwendungsbeispiel

c
result[1]=nes_attr_base_from_nt(0x2400);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Kombinieren Sie Zeilen-, Rechteck-, Füll- und vollständige Tabellenübertragungen. Zwei rote 32×8-Balken erscheinen über einem blauen 16×16-Quadrat und roten 16×24/32×24-Rechtecken. Direkte und eingereihte Übertragungen zeichnen an unterschiedlichen Positionen.

nes_attr_base_from_nt: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/nametable_asset.h:11

Deklarationshinweise im Original
Locate the 64-byte attribute table at offset 0x03C0 from a nametable base.

kitaqfc/lib/nametable_asset.c:30

c
unsigned short nes_attr_base_from_nt(unsigned short nt_base)
{
    return (unsigned short)(nt_base + 0x03C0);
}
nes_attr_queue_all

Kopiert den gesamten Attributschattenpuffer in die Warteschlange.

Syntax

c
unsigned char nes_attr_queue_all(unsigned short nt_base);

Parameter

nt_base

Logische Nametable-Basis $2000/$2400/$2800/$2C00; die Spiegelung bestimmt die physische Unabhängigkeit.

Rückgabewert

Gibt bei Aufnahme 1 zurück, bei voller Warteschlange 0; ein Eintrag benötigt 67 Warteschlangenbytes.

Bedingungen und Grenzen

Der gemeinsame 64-Byte-Attributschattenpuffer belegt CPU-RAM $03E0..$041F. Reservieren Sie diesen Bereich. Ein Attributbyte deckt 4×4 Kacheln ab; jedes Zwei-Bit-Feld wählt die Palette für einen 2×2-Kachelquadranten.

Binden Sie runtime.c ein. Die Warteschlange kopiert Nutzdaten für eine spätere NMI oder eine sichere Übertragung bei ausgeschalteter Darstellung. Serialisieren Sie Erzeugung und Verbrauch. Geht bei mehreren Zeilen die Kapazität aus, bleiben zuvor aufgenommene Zeilen eingereiht.

Anwendungsbeispiel

c
result[5]=nes_attr_queue_all(0x2000);result[6]=nes_vram_queue_used;nes_vram_queue_nmi_flush();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Kombinieren Sie Zeilen-, Rechteck-, Füll- und vollständige Tabellenübertragungen. Zwei rote 32×8-Balken erscheinen über einem blauen 16×16-Quadrat und roten 16×24/32×24-Rechtecken. Direkte und eingereihte Übertragungen zeichnen an unterschiedlichen Positionen.

nes_attr_queue_all: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/nametable_asset.h:22

Deklarationshinweise im Original
Copy all shadow attribute bytes into the runtime queue and return its admission result.

kitaqfc/lib/nametable_asset.c:97

c
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

Füllt alle 64 Schattenbytes mit demselben gepackten Wert.

Syntax

c
void nes_attr_shadow_clear(unsigned char value);

Parameter

value

Gepacktes Attributbyte; beispielsweise wählt 0x55 Palette 1 in allen Quadranten, 0xAA wählt Palette 2.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Der gemeinsame 64-Byte-Attributschattenpuffer belegt CPU-RAM $03E0..$041F. Reservieren Sie diesen Bereich. Ein Attributbyte deckt 4×4 Kacheln ab; jedes Zwei-Bit-Feld wählt die Palette für einen 2×2-Kachelquadranten.

Anwendungsbeispiel

c
nes_attr_shadow_clear(0x55);result[2]=nes_attr_shadow[63];

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Kombinieren Sie Zeilen-, Rechteck-, Füll- und vollständige Tabellenübertragungen. Zwei rote 32×8-Balken erscheinen über einem blauen 16×16-Quadrat und roten 16×24/32×24-Rechtecken. Direkte und eingereihte Übertragungen zeichnen an unterschiedlichen Positionen.

nes_attr_shadow_clear: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/nametable_asset.h:13

Deklarationshinweise im Original
Fill all 64 shadow bytes with an already-packed attribute value.

kitaqfc/lib/nametable_asset.c:36

c
void nes_attr_shadow_clear(unsigned char value)
{
    __memset(nes_attr_shadow, value, 64);
}
nes_attr_shadow_copy

Kopiert eine vollständige Attributtabelle als Ausgangspunkt für Bearbeitungen in den RAM.

Syntax

c
void nes_attr_shadow_copy(unsigned char* src64);

Parameter

src64

Lesbare, gepackte 64-Byte-Attributtabelle, kein Array einzelner Paletten-IDs je Kachel.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Der gemeinsame 64-Byte-Attributschattenpuffer belegt CPU-RAM $03E0..$041F. Reservieren Sie diesen Bereich. Ein Attributbyte deckt 4×4 Kacheln ab; jedes Zwei-Bit-Feld wählt die Palette für einen 2×2-Kachelquadranten.

Anwendungsbeispiel

c
for(i=0;i<64;i++)table[i]=0x55;nes_attr_shadow_copy(table);result[3]=nes_attr_shadow[0];

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Kombinieren Sie Zeilen-, Rechteck-, Füll- und vollständige Tabellenübertragungen. Zwei rote 32×8-Balken erscheinen über einem blauen 16×16-Quadrat und roten 16×24/32×24-Rechtecken. Direkte und eingereihte Übertragungen zeichnen an unterschiedlichen Positionen.

nes_attr_shadow_copy: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/nametable_asset.h:15

Deklarationshinweise im Original
Copy an entire packed attribute table into shadow RAM without writing the PPU.

kitaqfc/lib/nametable_asset.c:42

c
void nes_attr_shadow_copy(unsigned char* src64)
{
    __memcpy(nes_attr_shadow, src64, 64);
}
nes_attr_shadow_set_quad

Ersetzt die Palette eines 2×2-Kachelquadranten und erhält die übrigen Felder desselben Bytes.

Syntax

c
void nes_attr_shadow_set_quad(unsigned char tile_x, unsigned char tile_y, unsigned char pal_index);

Parameter

tile_x

Linke Kachelspalte, sichtbarer Bereich 0..31.

tile_y

Obere Kachelzeile, sichtbarer Bereich 0..29.

pal_index

Die unteren zwei Bits des Palettenindex.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Der gemeinsame 64-Byte-Attributschattenpuffer belegt CPU-RAM $03E0..$041F. Reservieren Sie diesen Bereich. Ein Attributbyte deckt 4×4 Kacheln ab; jedes Zwei-Bit-Feld wählt die Palette für einen 2×2-Kachelquadranten.

Halten Sie Koordinaten unter 32. Ungerade Koordinaten wählen den zugehörigen 2×2-Quadranten. Sichtbare Zeilen sind 0..29.

Anwendungsbeispiel

c
nes_attr_shadow_set_quad(4,8,2);result[4]=nes_attr_shadow[17];

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Kombinieren Sie Zeilen-, Rechteck-, Füll- und vollständige Tabellenübertragungen. Zwei rote 32×8-Balken erscheinen über einem blauen 16×16-Quadrat und roten 16×24/32×24-Rechtecken. Direkte und eingereihte Übertragungen zeichnen an unterschiedlichen Positionen.

nes_attr_shadow_set_quad: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/nametable_asset.h:18

Deklarationshinweise im Original
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

c
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

Überträgt 960 Kachel-IDs, gefolgt von einer 64-Byte-Attributtabelle.

Syntax

c
void nes_nametable_apply_now(unsigned short nt_base, unsigned char* nam960, unsigned char* attr64);

Parameter

nt_base

Logische Nametable-Basis $2000/$2400/$2800/$2C00; die Spiegelung bestimmt die physische Unabhängigkeit.

nam960

Zeilenweise angeordnetes 32×30-Kachelarray.

attr64

64 gepackte Attributbytes; müssen nicht aus dem gemeinsamen Schattenpuffer stammen.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Setzen Sie bei direkten Übertragungen das PPUCTRL-Inkrement auf eins und verwenden Sie die Einrichtung bei ausgeschalteter Darstellung oder ein ausreichend langes VBlank-Fenster. Diese Hilfsfunktionen schalten die Darstellung nicht aus und warten nicht.

Eine synchrone Übertragung von 1024 Bytes gehört gewöhnlich in die Einrichtung bei ausgeschalteter Darstellung. Die Hilfsfunktion verteilt sie nicht auf mehrere Frames.

Anwendungsbeispiel

c
nes_nametable_apply_now(0x2000,empty,table);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Kombinieren Sie Zeilen-, Rechteck-, Füll- und vollständige Tabellenübertragungen. Zwei rote 32×8-Balken erscheinen über einem blauen 16×16-Quadrat und roten 16×24/32×24-Rechtecken. Direkte und eingereihte Übertragungen zeichnen an unterschiedlichen Positionen.

nes_nametable_apply_now: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/nametable_asset.h:41

Deklarationshinweise im Original
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

c
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

Berechnet eine logische Nametable-Basis aus den unteren zwei Indexbits.

Syntax

c
unsigned short nes_nt_base_from_index(unsigned char index);

Parameter

index

Index; 0..3 wählen Tabellen, größere Werte werden auf die unteren zwei Bits reduziert.

Rückgabewert

Gibt $2000 + (index & 3)*$400 zurück.

Anwendungsbeispiel

c
result[0]=nes_nt_base_from_index(5);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Kombinieren Sie Zeilen-, Rechteck-, Füll- und vollständige Tabellenübertragungen. Zwei rote 32×8-Balken erscheinen über einem blauen 16×16-Quadrat und roten 16×24/32×24-Rechtecken. Direkte und eingereihte Übertragungen zeichnen an unterschiedlichen Positionen.

nes_nt_base_from_index: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/nametable_asset.h:9

Deklarationshinweise im Original
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

c
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

Reiht für jede Rechteckzeile das Füllen mit einer Kachel-ID ein.

Syntax

c
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);

Parameter

nt_base

Logische Nametable-Basis $2000/$2400/$2800/$2C00; die Spiegelung bestimmt die physische Unabhängigkeit.

tile_x

Linke Kachelspalte, sichtbarer Bereich 0..31.

tile_y

Obere Kachelzeile, sichtbarer Bereich 0..29.

width

Breite in Kacheln.

height

Höhe in Kacheln.

value

Kachel-ID zum Füllen, 0..255.

Rückgabewert

Gibt nach allen Zeilen oder bei Höhe null 1 zurück, bei fehlgeschlagener Aufnahme 0.

Bedingungen und Grenzen

Binden Sie runtime.c ein. Die Warteschlange kopiert Nutzdaten für eine spätere NMI oder eine sichere Übertragung bei ausgeschalteter Darstellung. Serialisieren Sie Erzeugung und Verbrauch. Geht bei mehreren Zeilen die Kapazität aus, bleiben zuvor aufgenommene Zeilen eingereiht.

Halten Sie Koordinaten und Ausdehnungen innerhalb der sichtbaren Nametable; gewöhnlich gilt pitch≥width. Es findet kein Clipping statt. Eingereihte Zeilen dürfen höchstens 127 lang sein; ein gewöhnliches Nametable-Rechteck ist höchstens 32 Kacheln breit.

Anwendungsbeispiel

c
result[10]=nes_nt_queue_fill_rect(0x2000,16,8,4,3,1);result[11]=nes_vram_queue_used;nes_vram_queue_nmi_flush();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Kombinieren Sie Zeilen-, Rechteck-, Füll- und vollständige Tabellenübertragungen. Zwei rote 32×8-Balken erscheinen über einem blauen 16×16-Quadrat und roten 16×24/32×24-Rechtecken. Direkte und eingereihte Übertragungen zeichnen an unterschiedlichen Positionen.

nes_nt_queue_fill_rect: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/nametable_asset.h:38

Deklarationshinweise im Original
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

c
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

Kopiert für jede Rechteckzeile die Quelldaten in die Warteschlange.

Syntax

c
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);

Parameter

nt_base

Logische Nametable-Basis $2000/$2400/$2800/$2C00; die Spiegelung bestimmt die physische Unabhängigkeit.

tile_x

Linke Kachelspalte, sichtbarer Bereich 0..31.

tile_y

Obere Kachelzeile, sichtbarer Bereich 0..29.

width

Breite in Kacheln.

height

Höhe in Kacheln.

pitch

Byte-Abstand zwischen den Quellzeilenanfängen; kann abschließende Füllbytes überspringen.

src

Lesbare Quelle mit mindestens (height−1)*pitch+width Bytes.

Rückgabewert

Gibt nach allen Zeilen oder bei Höhe null 1 zurück, bei fehlgeschlagener Aufnahme 0.

Bedingungen und Grenzen

Binden Sie runtime.c ein. Die Warteschlange kopiert Nutzdaten für eine spätere NMI oder eine sichere Übertragung bei ausgeschalteter Darstellung. Serialisieren Sie Erzeugung und Verbrauch. Geht bei mehreren Zeilen die Kapazität aus, bleiben zuvor aufgenommene Zeilen eingereiht.

Halten Sie Koordinaten und Ausdehnungen innerhalb der sichtbaren Nametable; gewöhnlich gilt pitch≥width. Es findet kein Clipping statt. Eingereihte Zeilen dürfen höchstens 127 lang sein; ein gewöhnliches Nametable-Rechteck ist höchstens 32 Kacheln breit.

Anwendungsbeispiel

c
result[8]=nes_nt_queue_rect(0x2000,10,8,2,3,4,patch);result[9]=nes_vram_queue_used;nes_vram_queue_nmi_flush();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Kombinieren Sie Zeilen-, Rechteck-, Füll- und vollständige Tabellenübertragungen. Zwei rote 32×8-Balken erscheinen über einem blauen 16×16-Quadrat und roten 16×24/32×24-Rechtecken. Direkte und eingereihte Übertragungen zeichnen an unterschiedlichen Positionen.

nes_nt_queue_rect: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/nametable_asset.h:35

Deklarationshinweise im Original
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

c
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

Kopiert eine vollständige Zeile aus 32 Kacheln in die Warteschlange.

Syntax

c
unsigned char nes_nt_queue_row(unsigned short nt_base, unsigned char row, unsigned char* src32);

Parameter

nt_base

Logische Nametable-Basis $2000/$2400/$2800/$2C00; die Spiegelung bestimmt die physische Unabhängigkeit.

row

Zeile 0..29; wird nicht auf Bereichsgrenzen geprüft.

src32

32 lesbare Kachel-IDs.

Rückgabewert

Gibt bei Aufnahme 1 zurück, bei voller Warteschlange 0; benötigt 35 Warteschlangenbytes.

Bedingungen und Grenzen

Binden Sie runtime.c ein. Die Warteschlange kopiert Nutzdaten für eine spätere NMI oder eine sichere Übertragung bei ausgeschalteter Darstellung. Serialisieren Sie Erzeugung und Verbrauch. Geht bei mehreren Zeilen die Kapazität aus, bleiben zuvor aufgenommene Zeilen eingereiht.

Anwendungsbeispiel

c
result[7]=nes_nt_queue_row(0x2000,4,row);nes_vram_queue_nmi_flush();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Kombinieren Sie Zeilen-, Rechteck-, Füll- und vollständige Tabellenübertragungen. Zwei rote 32×8-Balken erscheinen über einem blauen 16×16-Quadrat und roten 16×24/32×24-Rechtecken. Direkte und eingereihte Übertragungen zeichnen an unterschiedlichen Positionen.

nes_nt_queue_row: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/nametable_asset.h:26

Deklarationshinweise im Original
Copy one complete nametable row into the runtime queue.

kitaqfc/lib/nametable_asset.c:111

c
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

Liest jede Rechteckzeile anhand des Quellzeilenabstands und überträgt sie direkt an die PPU.

Syntax

c
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);

Parameter

nt_base

Logische Nametable-Basis $2000/$2400/$2800/$2C00; die Spiegelung bestimmt die physische Unabhängigkeit.

tile_x

Linke Kachelspalte, sichtbarer Bereich 0..31.

tile_y

Obere Kachelzeile, sichtbarer Bereich 0..29.

width

Breite in Kacheln.

height

Höhe in Kacheln.

pitch

Byte-Abstand zwischen den Quellzeilenanfängen; kann abschließende Füllbytes überspringen.

src

Lesbare Quelle mit mindestens (height−1)*pitch+width Bytes.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Setzen Sie bei direkten Übertragungen das PPUCTRL-Inkrement auf eins und verwenden Sie die Einrichtung bei ausgeschalteter Darstellung oder ein ausreichend langes VBlank-Fenster. Diese Hilfsfunktionen schalten die Darstellung nicht aus und warten nicht.

Halten Sie Koordinaten und Ausdehnungen innerhalb der sichtbaren Nametable; gewöhnlich gilt pitch≥width. Es findet kein Clipping statt. Eingereihte Zeilen dürfen höchstens 127 lang sein; ein gewöhnliches Nametable-Rechteck ist höchstens 32 Kacheln breit.

Anwendungsbeispiel

c
// 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);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Kombinieren Sie Zeilen-, Rechteck-, Füll- und vollständige Tabellenübertragungen. Zwei rote 32×8-Balken erscheinen über einem blauen 16×16-Quadrat und roten 16×24/32×24-Rechtecken. Direkte und eingereihte Übertragungen zeichnen an unterschiedlichen Positionen.

nes_nt_stream_rect: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/nametable_asset.h:29

Deklarationshinweise im Original
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

c
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

Kopiert eine vollständige Zeile aus 32 Kacheln direkt in die PPU.

Syntax

c
void nes_nt_stream_row(unsigned short nt_base, unsigned char row, unsigned char* src32);

Parameter

nt_base

Logische Nametable-Basis $2000/$2400/$2800/$2C00; die Spiegelung bestimmt die physische Unabhängigkeit.

row

Zeile 0..29; wird nicht auf Bereichsgrenzen geprüft.

src32

32 lesbare Kachel-IDs.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Setzen Sie bei direkten Übertragungen das PPUCTRL-Inkrement auf eins und verwenden Sie die Einrichtung bei ausgeschalteter Darstellung oder ein ausreichend langes VBlank-Fenster. Diese Hilfsfunktionen schalten die Darstellung nicht aus und warten nicht.

Anwendungsbeispiel

c
nes_nt_stream_row(0x2000,2,row);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Kombinieren Sie Zeilen-, Rechteck-, Füll- und vollständige Tabellenübertragungen. Zwei rote 32×8-Balken erscheinen über einem blauen 16×16-Quadrat und roten 16×24/32×24-Rechtecken. Direkte und eingereihte Übertragungen zeichnen an unterschiedlichen Positionen.

nes_nt_stream_row: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/nametable_asset.h:24

Deklarationshinweise im Original
Write one complete 32-tile row directly. The caller validates the row and PPU timing.

kitaqfc/lib/nametable_asset.c:103

c
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 — Operationsmakros für Spiele

nes_game.h bietet lesbare Makronamen für VRAM-Warteschlangen, OAM und Metasprites, Controller-Abfragen, Mapper-Interrupts, geteiltes Scrolling und FDS-Operationen. Jedes Makro expandiert zu einem Compiler-Intrinsic, sodass Diagnosemeldungen und KUROSAKI-Metadaten die zugrunde liegende Hardwareoperation erfassen. Die Warteschlangenmakros nutzen die Intrinsic-Warteschlange; das OAM-DMA-Makro hat keine Parameter.

Wählen Sie die Header bewusst: nes_game.h und der Sammelheader fc.h definieren die Makros. Für die C-Funktionen binden Sie runtime.h beziehungsweise metasprite.h samt Implementierungen ohne diese Makros ein, oder entfernen Sie die gleichnamigen Makros zuvor mit #undef. Das parameterlose DMA-Makro akzeptiert das Argument page der C-Funktion nicht.

nes_fds_farcall

FDS-Hilfsmakro für bankübergreifende Aufrufe in nes_game.h. Expandiert zu __fds_overlay_farcall((bank), (func)).

Syntax

c
#define nes_fds_farcall(bank, func)        __fds_overlay_farcall((bank), (func))

Parameter

bank

Ausdruck für die Bank. Er wird vor dem Aufruf einmal ausgewertet; die tatsächlich geladene Bank ergibt sich jedoch aus der gelinkten Platzierung von func. Damit wird keine Adresse in einer beliebig zur Laufzeit gewählten Bank aufgerufen. Übergeben Sie einen passenden Wert wie __bankof(func).

func

Name einer deklarierten Funktion ohne Parameter. Das Beispiel übergibt u8 overlay_answer(void). Numerische Adressen, Laufzeit-Funktionszeiger und Funktionen mit erforderlichen Argumenten werden abgewiesen. Verwenden Sie bei benötigten Argumenten einen normalen Aufruf wie target(a, b).

Rückgabewert

Acht-Bit-Ergebnis der Zielfunktion. Schlägt das Laden fehl, lässt sich aber die vorherige Bank wiederherstellen, wird die Zielfunktion nicht aufgerufen; stattdessen kommt das Ladefehlerbyte zurück. Legen Sie die Rückgabekonvention so fest, dass Fehler von normalen Ergebnissen unterscheidbar sind.

Bedingungen und Grenzen

Verwenden Sie dies mit --mapper=fds --fds-layout=fds32. Bank 0 enthält gemeinsamen Code bei $A000–$DFFF. Beim Start belegt Bank 1 den Bereich $6000–$9FFF; Banken ab 2 sind Overlays, die in dasselbe 16-KiB-Fenster geladen werden. Platzieren Sie Overlaycode oder -daten mit Direktiven wie #pragma fixed_bank 2.

Bank 1 wird aus einer separaten Boot-PRG-Datei mit 16.384 Bytes bei $6000 wiederhergestellt. Ohne Manifest sind die Standard-IDs 0 für Bank 1, 1 für gemeinsamen Code und 2 für CHR. Ein eigenes Manifest muss das Boot-PRG in 16.384-Byte-Dateien bei $6000 und $A000 aufteilen. Für Banken ab 2 lautet die Datei-ID --fds-overlay-start-id (standardmäßig 32) + Banknummer − 2.

Bei einem Aufruf in eine andere Bank wird die vorherige Bank gespeichert und vor der Rückkehr wiederhergestellt. Für verschachtelte Aufrufe gilt dasselbe. Auch nach einem teilweise fehlgeschlagenen Transfer wird eine Wiederherstellung versucht. Scheitert diese selbst, hält die Ausführung im gemeinsamen Code an, statt zu überschriebenem Code zurückzukehren. Ziele in der gemeinsamen Bank und Aufrufe innerhalb derselben Bank vermeiden unnötige Transfers.

BIOS-Aufrufe sind synchron. Diese API hält während des Ladens die Spielschleife nicht einmal pro Frame am Laufen. Verwenden Sie sie aus normalem Steuercode in der gemeinsamen Bank, nicht aus einem Interrupt-Handler. Bild- und Audiokontinuität sowie das Zusammenspiel mit dem echten BIOS müssen separat geprüft werden.

Diese Aufnahmen nutzen einen eigens geschriebenen Test für die LoadFiles-Aufrufkonvention, um kompilierten CPU-Code, Speichertransfers und jedes angezeigte Pixel zu prüfen. Echtes BIOS, Diskettentransfer-Timing, CRC und Hardwarestart werden damit nicht geprüft. KUROSAKI bildet den FDS-Controller nur teilweise nach. Eine gewöhnliche Ausführung ohne diesen Testbaustein belegt nicht dieselben Übertragungsergebnisse.

Der erste Compilerbefehl unten baut das herunterladbare Beispiel. Das Python-Prüfprogramm baut alle fünf Lektionen mit und ohne Optimierung und prüft sie anschließend in KUROSAKI. Es erstellt und entfernt einen temporären Testbaustein aus scripts/fds_abi_fixture.py; für diese Prüfungen ist kein externes BIOS nötig. Der Testbaustein ist kein BIOS für normale Spiele.

Anwendungsbeispiel

c
#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();}
}

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Mit dem eigens geschriebenen LoadFiles-ABI-Test ist RETURN VALUE 042; CALLBACK COUNT und BANK EXPR COUNT sind jeweils 001; BANK IN CALLBACK ist 002 und BANK AFTER RETURN 001. Funktion und Bankausdruck liefen jeweils einmal, und Bank 1 wurde nach dem Aufruf von Bank 2 wiederhergestellt. Dies ist keine Aufnahme eines echten Diskettentransfertests.

nes_fds_farcall: CALL_ALIAS-DEFAULT — Mit dem eigens geschriebenen LoadFiles-ABI-Test ist RETURN VALUE 042; CALLBACK COUNT und BANK EXPR COUNT sind jeweils 001; BANK IN CALLBACK ist 002 und BANK AFTER RETURN 001. Funktion und Bankausdruck liefen jeweils einmal, und Bank 1 wurde nach dem Aufruf von Bank 2 wiederhergestellt. Dies ist keine Aufnahme eines echten Diskettentransfertests.
CALL_ALIAS-DEFAULT — Mit dem eigens geschriebenen LoadFiles-ABI-Test ist RETURN VALUE 042; CALLBACK COUNT und BANK EXPR COUNT sind jeweils 001; BANK IN CALLBACK ist 002 und BANK AFTER RETURN 001. Funktion und Bankausdruck liefen jeweils einmal, und Bank 1 wurde nach dem Aufruf von Bank 2 wiederhergestellt. Dies ist keine Aufnahme eines echten Diskettentransfertests.

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.py
Implementierung und Quelltext

kitaqfc/lib/nes_game.h:41

nes_fds_load_bank

Makroschreibweise von __fds_load_bank() in nes_game.h, um über den Spielhilfsheader eine logische Bank ausdrücklich zu laden.

Syntax

c
#define nes_fds_load_bank(bank)            __fds_load_bank((bank))

Parameter

bank

Zu ladende logische Bank, 1 bis 254. Bank 0 ist gemeinsamer Code und kein ladbares Fenster; 255 ist für unbekannte Bankbelegung reserviert. Bei Banken ab 2 muss auch die berechnete Datei-ID in 0 bis 254 liegen.

Rückgabewert

Bei Erfolg null. Gibt 255 für Bank 0 oder 255, einen Datei-ID-Überlauf oder Bank 1 ohne Wiederherstellungsdatei zurück. Ein fehlgeschlagener BIOS-Transfer liefert dessen Fehlerbyte. Argumentfehler vor dem Transfer bewahren den Belegungsvermerk; fehlgeschlagene BIOS-Transfers setzen ihn auf 255 (unbekannt).

Bedingungen und Grenzen

Verwenden Sie dies mit --mapper=fds --fds-layout=fds32. Bank 0 enthält gemeinsamen Code bei $A000–$DFFF. Beim Start belegt Bank 1 den Bereich $6000–$9FFF; Banken ab 2 sind Overlays, die in dasselbe 16-KiB-Fenster geladen werden. Platzieren Sie Overlaycode oder -daten mit Direktiven wie #pragma fixed_bank 2.

Expandiert zu __fds_load_bank((bank)), ohne bank mehrfach auszuwerten. Argumentgrenzen, Belegungsprüfung und Fehlerverhalten entsprechen dem Intrinsic.

Bank 1 wird aus einer separaten Boot-PRG-Datei mit 16.384 Bytes bei $6000 wiederhergestellt. Ohne Manifest sind die Standard-IDs 0 für Bank 1, 1 für gemeinsamen Code und 2 für CHR. Ein eigenes Manifest muss das Boot-PRG in 16.384-Byte-Dateien bei $6000 und $A000 aufteilen. Für Banken ab 2 lautet die Datei-ID --fds-overlay-start-id (standardmäßig 32) + Banknummer − 2.

Mit der standardmäßigen Belegungsprüfung gibt eine bereits vermerkte Bank ohne Diskettenzugriff null zurück. --fds-no-overlay-guard deaktiviert diese Abkürzung in __fds_load_bank(). Ein erfolgreicher Ladevorgang vermerkt die angeforderte Bank. Dieser Vermerk ist keine Prüfung des Speicherinhalts.

Das direkte Laden einer anderen Bank aus Code im Fenster $6000–$9FFF kann die laufende Funktion oder deren Rücksprungadresse überschreiben. Das Beispiel legt Aufrufer und Anzeigecode in #pragma fixed_bank 0 ab. Um eine Funktion in einer anderen Bank aufzurufen und zurückzukehren, verwenden Sie __fds_overlay_farcall() oder einen normalen typisierten Funktionsaufruf.

BIOS-Aufrufe sind synchron. Diese API hält während des Ladens die Spielschleife nicht einmal pro Frame am Laufen. Verwenden Sie sie aus normalem Steuercode in der gemeinsamen Bank, nicht aus einem Interrupt-Handler. Bild- und Audiokontinuität sowie das Zusammenspiel mit dem echten BIOS müssen separat geprüft werden.

Diese Aufnahmen nutzen einen eigens geschriebenen Test für die LoadFiles-Aufrufkonvention, um kompilierten CPU-Code, Speichertransfers und jedes angezeigte Pixel zu prüfen. Echtes BIOS, Diskettentransfer-Timing, CRC und Hardwarestart werden damit nicht geprüft. KUROSAKI bildet den FDS-Controller nur teilweise nach. Eine gewöhnliche Ausführung ohne diesen Testbaustein belegt nicht dieselben Übertragungsergebnisse.

Der erste Compilerbefehl unten baut das herunterladbare Beispiel. Das Python-Prüfprogramm baut alle fünf Lektionen mit und ohne Optimierung und prüft sie anschließend in KUROSAKI. Es erstellt und entfernt einen temporären Testbaustein aus scripts/fds_abi_fixture.py; für diese Prüfungen ist kein externes BIOS nötig. Der Testbaustein ist kein BIOS für normale Spiele.

Anwendungsbeispiel

c
#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();}
}

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Mit dem eigens geschriebenen LoadFiles-ABI-Test sind LOAD BANK 2 STATUS, REQUIRE SAME BANK und RESTORE BANK 1 jeweils 000. FIRST / LAST BYTE zeigt 011 und 044 aus den vier übertragenen Bytes; RESIDENT BANK ist nach der Wiederherstellung 001. Die ungültigen Banken 0 und 255 liefern jeweils 255. Das Anfordern derselben Bank löst keinen weiteren Ladevorgang aus: Die geprüften Dateianforderungen sind 32 und danach 0.

nes_fds_load_bank: BANK_LOAD-DEFAULT — Mit dem eigens geschriebenen LoadFiles-ABI-Test sind LOAD BANK 2 STATUS, REQUIRE SAME BANK und RESTORE BANK 1 jeweils 000. FIRST / LAST BYTE zeigt 011 und 044 aus den vier übertragenen Bytes; RESIDENT BANK ist nach der Wiederherstellung 001. Die ungültigen Banken 0 und 255 liefern jeweils 255. Das Anfordern derselben Bank löst keinen weiteren Ladevorgang aus: Die geprüften Dateianforderungen sind 32 und danach 0.
BANK_LOAD-DEFAULT — Mit dem eigens geschriebenen LoadFiles-ABI-Test sind LOAD BANK 2 STATUS, REQUIRE SAME BANK und RESTORE BANK 1 jeweils 000. FIRST / LAST BYTE zeigt 011 und 044 aus den vier übertragenen Bytes; RESIDENT BANK ist nach der Wiederherstellung 001. Die ungültigen Banken 0 und 255 liefern jeweils 255. Das Anfordern derselben Bank löst keinen weiteren Ladevorgang aus: Die geprüften Dateianforderungen sind 32 und danach 0.

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.py
Implementierung und Quelltext

kitaqfc/lib/nes_game.h:40

nes_fds_wave_load

Makro, das sein Array an __fds_wave_load zum Laden einer 64-Byte-Welle weiterreicht.

Syntax

c
#define nes_fds_wave_load(wave64)          __fds_wave_load((wave64))

Parameter

wave64

Vierundsechzig FDS-Wellenbytes mit je einer Sechsbitamplitude 0..63. NULL wird nicht geprüft.

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Bedingungen und Grenzen

Erstellen Sie mit --mapper=fds ein .fds-Abbild. Diese Lektion verwendet Sound ohne Datenträger-I/O. Die Aufnahme nutzt KUROSAKIs direkten RAM-Start und Audiomodell. Die leere Testfirmware implementiert keine BIOS-Routinen und wird nicht verteilt. Normaler Diskettenstart und echte Hardware benötigen eine passende Startumgebung.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Ein eigenes 64-stufiges Dreieck spielt bei etwa 440 Hz, pausiert, spielt bei etwa 660 Hz und stoppt. Die zweite Note nutzt nes_fds_wave_load und rohe Hüllkurveneinstellungen. Geprüft werden Audiomodell und Direktstart, nicht BIOS-gesteuerter Diskettenstart.

nes_fds_wave_load: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/nes_game.h:39

c
#define nes_fds_wave_load(wave64)          __fds_wave_load((wave64))
nes_mapper_irq_ack

Quittierungsmakro für Handler aus nes_game.h. Expandiert zu __mapper_irq_ack() und löscht sowie deaktiviert die Anforderung zugleich.

Syntax

c
#define nes_mapper_irq_ack()               __mapper_irq_ack()

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Die Intrinsic-Deklarationen stehen in intrinsics.h. Binden Sie für die Makros nes_mapper_irq_* den Header nes_game.h ein. Wählen Sie die Platine beim Build mit --mapper.

Nur MMC3. Erforderlich sind ein __nes_irq-Handler, qualifizierte PPU-A12-Übergänge, Mapper-IRQ-Freigabe und CPU-__irq_enable(). Das Beispiel aktiviert die Darstellung mit Hintergrundmustern bei $0000 und Spritemustern bei $1000. Die Lektion prüft keine Synchronisierung auf eine exakte Zeile echter Hardware.

MMC3-Quittierung und -Deaktivierung schreiben beide nach $E000. Das löscht die aktuelle Anforderung und deaktiviert weitere. Rufen Sie zum gewünschten Zeitpunkt erneut __mapper_irq_enable() auf, um einen weiteren Interrupt freizugeben. Beide Vorgänge ändern weder CPU-Interruptmaske noch NMI-Freigabe.

Der Compiler erzeugt RTI für eigene Interrupt-Handler. Der Handler muss aber alle von ihm geänderten A/X/Y-Register und gemeinsamen temporären Speicher sichern. Das Beispiel sichert A/X/Y und verwendet nur ein Byteinkrement sowie eine argumentlose Quittierung. Prüfen Sie bei zusätzlichen C-Aufrufen auch deren gemeinsam genutzten Speicher.

Anwendungsbeispiel

c
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
    }
}

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das MMC3-Beispiel zeigt CHR-Marker 19/20, 21/22 und 23/24. CIRAM-Lesewerte ergeben A B A B bei vertikaler Spiegelung und A A B B bei horizontaler. Die IRQ-Zählerstände sind 01→02→03→03: Jede der ersten drei ausdrücklichen Freigaben erlaubt einen Interrupt; nach Deaktivierung bleibt der Stand gleich. Jede Stufe wartet sechs Frames.

nes_mapper_irq_ack: MMC3-DEFAULT
MMC3-DEFAULT

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/nes_game.h:36

nes_mapper_irq_disable

Deaktiviert MMC3-IRQ und löscht die ausstehende Anforderung über nes_game.h. Expandiert zu __mapper_irq_disable().

Syntax

c
#define nes_mapper_irq_disable()           __mapper_irq_disable()

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Die Intrinsic-Deklarationen stehen in intrinsics.h. Binden Sie für die Makros nes_mapper_irq_* den Header nes_game.h ein. Wählen Sie die Platine beim Build mit --mapper.

Nur MMC3. Erforderlich sind ein __nes_irq-Handler, qualifizierte PPU-A12-Übergänge, Mapper-IRQ-Freigabe und CPU-__irq_enable(). Das Beispiel aktiviert die Darstellung mit Hintergrundmustern bei $0000 und Spritemustern bei $1000. Die Lektion prüft keine Synchronisierung auf eine exakte Zeile echter Hardware.

MMC3-Quittierung und -Deaktivierung schreiben beide nach $E000. Das löscht die aktuelle Anforderung und deaktiviert weitere. Rufen Sie zum gewünschten Zeitpunkt erneut __mapper_irq_enable() auf, um einen weiteren Interrupt freizugeben. Beide Vorgänge ändern weder CPU-Interruptmaske noch NMI-Freigabe.

Der Compiler erzeugt RTI für eigene Interrupt-Handler. Der Handler muss aber alle von ihm geänderten A/X/Y-Register und gemeinsamen temporären Speicher sichern. Das Beispiel sichert A/X/Y und verwendet nur ein Byteinkrement sowie eine argumentlose Quittierung. Prüfen Sie bei zusätzlichen C-Aufrufen auch deren gemeinsam genutzten Speicher.

Anwendungsbeispiel

c
nes_mapper_irq_disable();
    for (i=0;i<6;i++) { m_wait(); }
    mapper_result[18]=irq_count;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das MMC3-Beispiel zeigt CHR-Marker 19/20, 21/22 und 23/24. CIRAM-Lesewerte ergeben A B A B bei vertikaler Spiegelung und A A B B bei horizontaler. Die IRQ-Zählerstände sind 01→02→03→03: Jede der ersten drei ausdrücklichen Freigaben erlaubt einen Interrupt; nach Deaktivierung bleibt der Stand gleich. Jede Stufe wartet sechs Frames.

nes_mapper_irq_disable: MMC3-DEFAULT
MMC3-DEFAULT

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/nes_game.h:35

nes_mapper_irq_enable

Aktiviert MMC3-IRQ über nes_game.h. Expandiert zu __mapper_irq_enable(), ohne die CPU-Interruptmaske zu ändern.

Syntax

c
#define nes_mapper_irq_enable()            __mapper_irq_enable()

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Die Intrinsic-Deklarationen stehen in intrinsics.h. Binden Sie für die Makros nes_mapper_irq_* den Header nes_game.h ein. Wählen Sie die Platine beim Build mit --mapper.

Nur MMC3. Erforderlich sind ein __nes_irq-Handler, qualifizierte PPU-A12-Übergänge, Mapper-IRQ-Freigabe und CPU-__irq_enable(). Das Beispiel aktiviert die Darstellung mit Hintergrundmustern bei $0000 und Spritemustern bei $1000. Die Lektion prüft keine Synchronisierung auf eine exakte Zeile echter Hardware.

MMC3-Quittierung und -Deaktivierung schreiben beide nach $E000. Das löscht die aktuelle Anforderung und deaktiviert weitere. Rufen Sie zum gewünschten Zeitpunkt erneut __mapper_irq_enable() auf, um einen weiteren Interrupt freizugeben. Beide Vorgänge ändern weder CPU-Interruptmaske noch NMI-Freigabe.

Der Compiler erzeugt RTI für eigene Interrupt-Handler. Der Handler muss aber alle von ihm geänderten A/X/Y-Register und gemeinsamen temporären Speicher sichern. Das Beispiel sichert A/X/Y und verwendet nur ein Byteinkrement sowie eine argumentlose Quittierung. Prüfen Sie bei zusätzlichen C-Aufrufen auch deren gemeinsam genutzten Speicher.

Anwendungsbeispiel

c
nes_mapper_irq_set(15); nes_mapper_irq_enable();
    for (i=0;i<6;i++) { m_wait(); }
    mapper_result[16]=irq_count;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das MMC3-Beispiel zeigt CHR-Marker 19/20, 21/22 und 23/24. CIRAM-Lesewerte ergeben A B A B bei vertikaler Spiegelung und A A B B bei horizontaler. Die IRQ-Zählerstände sind 01→02→03→03: Jede der ersten drei ausdrücklichen Freigaben erlaubt einen Interrupt; nach Deaktivierung bleibt der Stand gleich. Jede Stufe wartet sechs Frames.

nes_mapper_irq_enable: MMC3-DEFAULT
MMC3-DEFAULT

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/nes_game.h:34

nes_mapper_irq_set

MMC3-Latchmakro aus nes_game.h. Übergibt sein Argument einmal an __mapper_irq_set und fordert Nachladen an.

Syntax

c
#define nes_mapper_irq_set(scanline)       __mapper_irq_set((scanline))

Parameter

scanline

Acht-Bit-Latchwert des Zählers von 0 bis 255, keine absolute Bildschirm-Y-Koordinate. Nachladezeitpunkt und qualifizierte PPU-A12-Übergänge bestimmen die Auslösung. Null ist gültig und bedeutet nicht „Interrupts deaktivieren“.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Die Intrinsic-Deklarationen stehen in intrinsics.h. Binden Sie für die Makros nes_mapper_irq_* den Header nes_game.h ein. Wählen Sie die Platine beim Build mit --mapper.

Nur MMC3. Erforderlich sind ein __nes_irq-Handler, qualifizierte PPU-A12-Übergänge, Mapper-IRQ-Freigabe und CPU-__irq_enable(). Das Beispiel aktiviert die Darstellung mit Hintergrundmustern bei $0000 und Spritemustern bei $1000. Die Lektion prüft keine Synchronisierung auf eine exakte Zeile echter Hardware.

MMC3-Quittierung und -Deaktivierung schreiben beide nach $E000. Das löscht die aktuelle Anforderung und deaktiviert weitere. Rufen Sie zum gewünschten Zeitpunkt erneut __mapper_irq_enable() auf, um einen weiteren Interrupt freizugeben. Beide Vorgänge ändern weder CPU-Interruptmaske noch NMI-Freigabe.

Der Compiler erzeugt RTI für eigene Interrupt-Handler. Der Handler muss aber alle von ihm geänderten A/X/Y-Register und gemeinsamen temporären Speicher sichern. Das Beispiel sichert A/X/Y und verwendet nur ein Byteinkrement sowie eine argumentlose Quittierung. Prüfen Sie bei zusätzlichen C-Aufrufen auch deren gemeinsam genutzten Speicher.

Anwendungsbeispiel

c
nes_mapper_irq_set(15); nes_mapper_irq_enable();
    for (i=0;i<6;i++) { m_wait(); }
    mapper_result[16]=irq_count;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das MMC3-Beispiel zeigt CHR-Marker 19/20, 21/22 und 23/24. CIRAM-Lesewerte ergeben A B A B bei vertikaler Spiegelung und A A B B bei horizontaler. Die IRQ-Zählerstände sind 01→02→03→03: Jede der ersten drei ausdrücklichen Freigaben erlaubt einen Interrupt; nach Deaktivierung bleibt der Stand gleich. Jede Stufe wartet sechs Frames.

nes_mapper_irq_set: MMC3-DEFAULT
MMC3-DEFAULT

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/nes_game.h:33

nes_oam_clear

Makro aus nes_game.h: Es wird zum in der Syntax gezeigten Intrinsic expandiert. Binden Sie diesen Header ein; für diese Operation ist keine C-Implementierungsdatei erforderlich.

Blendet alle 64 Sprites im Schattenpuffer der Seite 02 aus, indem jedes Y-Byte auf 0xF0 gesetzt wird. Kachelnummern, Attribute und X-Koordinaten bleiben erhalten.

Syntax

c
#define nes_oam_clear()                    __oam_clear()

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Diese Operationen ändern den CPU-RAM bei 0x0200–0x02FF, nicht sofort das Hardware-OAM. Übertragen Sie die fertige Seite mit __oam_dma. Belegungsflags, Koordinatenfelder und Zähler der Sprite-Bibliothek werden nicht mitgeführt. Interrupt-Routinen dürfen eine noch unvollständige Seite weder ändern noch übertragen.

Anwendungsbeispiel

c
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.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel zeigt jede Operation in einer beschrifteten Zeile. SET und MOVE zeigen 8×8-Pfeile nach rechts bei (144,16) und (144,32), TILE ein grünes Quadrat bei (144,48) und ATTR den in beiden Achsen gespiegelten Pfeil bei (144,64). HIDE bei (144,80) und CLEAR bei (144,112) müssen leer bleiben. META zeigt zwei Pfeile bei (136,96) und (144,96), den zweiten horizontal gespiegelt. NEXT 07 bezeichnet die nächste Position nach den Einträgen 5 und 6. Die Ränder sind rot, der Schaft grün und die Spitzendetails blau. Geprüft werden 8.704 Pixel je Bild und die übertragenen OAM-Bytes; echte Hardware wurde nicht getestet.

Das Programm ALIASES bereitet die beschrifteten Zeilen mit Makros aus nes_game.h vor und sendet Seite 02 mit nes_oam_dma(). TRANSFER zeigt den 8×8-Pfeil bei (144,128). Das Beispiel verwendet die Makros, ohne runtime.c oder metasprite.c einzubinden.

nes_oam_clear: Aliasse
Aliasse

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/nes_game.h:21

c
#define nes_oam_clear()                    __oam_clear()
nes_oam_dma

Diesen Namen gibt es in zwei Formen. Das parameterlose Makro nes_oam_dma() überträgt Seite 02 über __oam_dma(). Die C-Funktion nes_oam_dma(page) überträgt die angegebene 256-Byte-Seite des CPU-Speichers. Beide setzen OAMADDR auf null und übertragen die ganze Seite, ohne die Quelle zu verändern.

Syntax

c
#define nes_oam_dma()                      __oam_dma()

// C function declared in runtime.h:
void nes_oam_dma(unsigned char page);

Parameter

page (C)

Oberes Byte der CPU-Quelladresse: Übergeben Sie für 0x0400–0x04FF den Wert 4, nicht 0x0400. Stellen Sie eine vollständige lesbare Seite mit 256 Byte bereit und halten Sie die nötige Bank eingeblendet. Vermeiden Sie Seiten mit E/A-Registern, deren Lesezugriffe Nebenwirkungen haben können. Die Quelle wird nicht geprüft.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Wählen Sie die Header bewusst: nes_game.h und der Sammelheader fc.h definieren die Makros. Für die C-Funktionen binden Sie runtime.h beziehungsweise metasprite.h samt Implementierungen ohne diese Makros ein, oder entfernen Sie die gleichnamigen Makros zuvor mit #undef. Das parameterlose DMA-Makro akzeptiert das Argument page der C-Funktion nicht.

Die C-Metasprite-Funktionen benötigen nes_oam_shadow[256]. runtime.c definiert diesen Puffer bei 0x0200, reserviert zusätzlich 0x0300–0x03BF für seine VRAM-Warteschlange und stellt __nes_nmi bereit. Binden Sie jede Implementierung nur einmal ein und stimmen Sie die Interruptbehandlung mit dem übrigen Programm ab.

Rufen Sie DMA während VBlank oder bei abgeschalteter Bildausgabe auf. Keine der beiden Formen wartet auf VBlank. Bereiten Sie zuerst die gesamte Quellseite vor und übertragen Sie sie anschließend; Interrupts dürfen die Seite während der Vorbereitung nicht verändern.

Anwendungsbeispiel

c
m_wait();nes_oam_dma(); // Expand to the page-02 compiler intrinsic.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel zeigt jede Operation in einer beschrifteten Zeile. SET und MOVE zeigen 8×8-Pfeile nach rechts bei (144,16) und (144,32), TILE ein grünes Quadrat bei (144,48) und ATTR den in beiden Achsen gespiegelten Pfeil bei (144,64). HIDE bei (144,80) und CLEAR bei (144,112) müssen leer bleiben. META zeigt zwei Pfeile bei (136,96) und (144,96), den zweiten horizontal gespiegelt. NEXT 07 bezeichnet die nächste Position nach den Einträgen 5 und 6. Die Ränder sind rot, der Schaft grün und die Spitzendetails blau. Geprüft werden 8.704 Pixel je Bild und die übertragenen OAM-Bytes; echte Hardware wurde nicht getestet.

Das Programm ALIASES bereitet die beschrifteten Zeilen mit Makros aus nes_game.h vor und sendet Seite 02 mit nes_oam_dma(). TRANSFER zeigt den 8×8-Pfeil bei (144,128). Das Beispiel verwendet die Makros, ohne runtime.c oder metasprite.c einzubinden.

nes_oam_dma: Aliasse
Aliasse

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm

Anwendungsbeispiel

c
m_wait();nes_oam_dma(4); // C function: source address high byte, 0x0400 -> 4.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

C-RUNTIME kombiniert die C-Funktionen. PAIR zeigt zwei 8×8-Pfeile bei (144,32) und (152,32), den zweiten horizontal gespiegelt. Ein weiteres Paar bei y=64 wird ausgeblendet; HIDE RANGE muss daher leer bleiben. Die beiden Zeichenaufrufe verwenden die Slots 4–5 und 6–7 und ergeben NEXT 08. Seite 02 wird nach Seite 04 kopiert; nur Slot 8 wechselt vom Pfeil-Tile 128 zum Quadrat-Tile 129. nes_oam_dma(4) muss neben PAGE 04 bei (144,96) ein grünes Quadrat anzeigen, während Seite 02 Tile 128 behält.

Die Pfeile haben rote Ränder, grüne Schäfte und blaue Details an der Spitze; das Quadrat-Tile 129 ist grün. Die Prüfung vergleicht pro Bild 8.704 Farbpixel, alle 256 übertragenen OAM-Bytes und die Beschriftungen. Physische Hardware wurde nicht getestet.

nes_oam_dma: C-Laufzeit
C-Laufzeit

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/nes_game.h:23

kitaqfc/lib/runtime.c:245

c
void nes_oam_dma(unsigned char page)
{
    OAMADDR = 0;
    OAMDMA = page;
}
nes_pad1

Funktionsähnliches Makro, das exakt zu __pad_read1_safe() expandiert. Liest Controller 1 und liefert dessen rohe NES-Maske; kein Alias für den gespeicherten Zustand von input_current().

Syntax

c
#define nes_pad1()                         __pad_read1_safe()

Rückgabewert

Eine 8-Bit-Haltemaske in roher NES-Reihenfolge. Jedes gesetzte Bit steht für eine gedrückte Taste, 0 für keine. Kein auf 0/1 normalisierter Wahrheitswert.

Bedingungen und Grenzen

Rohes NES-Format: A=0x01, B=0x02, SELECT=0x04, START=0x08, UP=0x10, DOWN=0x20, LEFT=0x40, RIGHT=0x80. Ein gesetztes Bit bedeutet gedrückt. Verwende diese Werte mit nes_pad_* und rohen __pad_*-Ergebnissen, nicht die gemeinsamen BTN_*-Masken aus input.h.

Dieser Aufruf liest einen neuen Hardwarezustand. Er aktualisiert weder den gespeicherten input_*- noch den nes_pad1_*-Zustand und erzeugt keine Druck-, Loslass- oder Wiederholungsereignisse. Speichere das Ergebnis und vergleiche es bei Bedarf mit deiner vorherigen Maske.

Die sichere Abfrage wiederholt Paare vollständiger Lesevorgänge, bis beide Masken übereinstimmen. Jeder Lesevorgang strobt $4016 und setzt die serielle Leseposition beider Controller zurück. Die Zahl der Versuche ist unbegrenzt. Diese Prüfung belegt keine Kompatibilität mit sämtlichen DMC-/Peripheriekombinationen.

Anwendungsbeispiel

c
alias1=nes_pad1(); // Macro for __pad_read1_safe(), using NES raw bits.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieses Programm vergleicht beide Controlleranschlüsse, einfache und auf Übereinstimmung geprüfte Lesevorgänge, Maskenfilter und Kurzmakros. Halten Sie A + Rechts auf Controller 1 und B + Links auf Controller 2 gedrückt. RAW P1, SAFE P1 und ALIAS P1 sind 129; die drei P2-Werte sind 66. BUTTONS P1 ist 1 und DIRS P1 ist 128: Der Richtungsfilter behält die oberen Bitpositionen bei. FAILED CHECKS muss 0 sein. Die erfassten Werte bleiben sichtbar.

nes_pad1: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-cache
Implementierung und Quelltext

kitaqfc/lib/nes_game.h:30

nes_pad2

Funktionsähnliches Makro, das exakt zu __pad_read2_safe() expandiert. Liest Controller 2 und liefert dessen rohe NES-Maske; kein Alias für den gespeicherten Zustand von input_current().

Syntax

c
#define nes_pad2()                         __pad_read2_safe()

Rückgabewert

Eine 8-Bit-Haltemaske in roher NES-Reihenfolge. Jedes gesetzte Bit steht für eine gedrückte Taste, 0 für keine. Kein auf 0/1 normalisierter Wahrheitswert.

Bedingungen und Grenzen

Rohes NES-Format: A=0x01, B=0x02, SELECT=0x04, START=0x08, UP=0x10, DOWN=0x20, LEFT=0x40, RIGHT=0x80. Ein gesetztes Bit bedeutet gedrückt. Verwende diese Werte mit nes_pad_* und rohen __pad_*-Ergebnissen, nicht die gemeinsamen BTN_*-Masken aus input.h.

Dieser Aufruf liest einen neuen Hardwarezustand. Er aktualisiert weder den gespeicherten input_*- noch den nes_pad1_*-Zustand und erzeugt keine Druck-, Loslass- oder Wiederholungsereignisse. Speichere das Ergebnis und vergleiche es bei Bedarf mit deiner vorherigen Maske.

Die sichere Abfrage wiederholt Paare vollständiger Lesevorgänge, bis beide Masken übereinstimmen. Jeder Lesevorgang strobt $4016 und setzt die serielle Leseposition beider Controller zurück. Die Zahl der Versuche ist unbegrenzt. Diese Prüfung belegt keine Kompatibilität mit sämtlichen DMC-/Peripheriekombinationen.

Anwendungsbeispiel

c
alias2=nes_pad2(); // Macro for __pad_read2_safe(), using NES raw bits.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieses Programm vergleicht beide Controlleranschlüsse, einfache und auf Übereinstimmung geprüfte Lesevorgänge, Maskenfilter und Kurzmakros. Halten Sie A + Rechts auf Controller 1 und B + Links auf Controller 2 gedrückt. RAW P1, SAFE P1 und ALIAS P1 sind 129; die drei P2-Werte sind 66. BUTTONS P1 ist 1 und DIRS P1 ist 128: Der Richtungsfilter behält die oberen Bitpositionen bei. FAILED CHECKS muss 0 sein. Die erfassten Werte bleiben sichtbar.

nes_pad2: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-cache
Implementierung und Quelltext

kitaqfc/lib/nes_game.h:31

nes_split_scroll_sprite0

Bildschirmteilungsmakro aus nes_game.h. Übergibt X und Y je einmal an __split_scroll_sprite0 und führt dieselben Warte- und Scrollzugriffe aus.

Syntax

c
#define nes_split_scroll_sprite0(x,y)      __split_scroll_sprite0((x),(y))

Parameter

x

Horizontaler Scrollwert 0..255, keine Objekt-Bildschirm-X-Koordinate. Das Beispiel nutzt 32, um den unteren Teil desselben Hintergrunds 32 Pixel nach links zu verschieben.

y

Vorübergehender vertikaler Scrollwert 0..255; üblicher sichtbarer Bereich 0..239. Die Hilfe schreibt $2005 und ändert daher während der Darstellung die laufende Vertikalposition nicht sofort. Das horizontale Teilungsbeispiel übergibt null.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Überlagern Sie ein deckendes Pixel von OAM-Sprite 0 mit einem deckenden Hintergrundpixel bei aktivierten Ebenen. Die Priorität hinter dem Hintergrund erlaubt weiterhin einen Treffer. Die linken acht Pixel erfordern die jeweiligen Ebenenfreigaben; Überlappung bei X=255 löst keinen Treffer aus.

Fragt PPUSTATUS ($2002), Bit 6 ab, bis es gelöscht und danach gesetzt ist. Bei bereits erfolgtem Treffer wartet der Aufruf auf einen neuen im nächsten Frame. Lesen quittiert das Flag nicht; die PPU löscht es während Pre-Render.

Keine Zeitbegrenzung oder Fehlerrückgabe. Verstecktes Sprite 0, transparenter Hintergrund, deaktivierte Darstellung oder sonst fehlende Überlappung lassen den Aufruf blockieren. Stellen Sie vorher einen Treffer sicher. CPU-IRQ-Freigabe ist nicht nötig, NMI wird nicht aktiviert. Das Beispiel aktiviert NMI für seine separate Framewartefunktion.

Lesen von $2002 beeinflusst auch das gemeinsame PPU-Adress-/Scrollschreiblatch und das VBlank-Flag. Fügen Sie diesen Aufruf nicht zwischen die beiden Schreibzugriffe einer $2005-/$2006-Operation ein. Nutzen Sie Hauptcode, keinen NMI-/IRQ-Handler.

Nach dem Treffer wird $2002 gelesen und X, dann Y nach $2005 geschrieben. Fein-X wirkt sofort, Grob-X beim nächsten horizontalen Nachladen. Y wirkt normalerweise beim nächsten Pre-Render-Nachladen, sofern kein anderer Scrollzugriff es vorher ersetzt. Dies ist keine sofortige beliebige X/Y-Rasterneupositionierung.

Polling und Befehlsausführung verzögern die Schreibzugriffe. KUROSAKI rendert zeilenweise; die Aufnahmen belegen daher keine punktgenaue Hardwaregrenze. Das Beispiel legt den Wechsel in das weiße Band Y=96..103, abseits der blauen und roten Balken.

Der gemeinsame Header fc_sprite0_scene.h bereitet eigene blaue/rote Balken und ein weißes horizontales Band vor. Sprite 0 liegt bei (16,96) hinter dem Hintergrund; sein rohes OAM-Y ist 95, da Anzeige-Y=OAM-Y+1. Jeder Frame setzt während VBlank den oberen Scroll auf null zurück und wartet dann auf den Treffer.

NESdev: PPU-Scrolling

NESdev: PPU-Referenz für Programmierer

Anwendungsbeispiel

c
void main(void) {
    s0_prepare();
    while (1) {
        s0_frame();
        nes_split_scroll_sprite0(32,0);
        s0_completed++;
    }
}

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Über dem weißen Band liegt Blau bei X=64..95 und Rot bei X=160..191. Darunter ab Y=104 liegt Blau bei X=32..63, Rot bei X=128..159; nur der untere Bereich wandert 32 Pixel nach links. Das Band liegt bei Y=96..103, die Balken enden bei Y=207. Geprüft werden ein Abschluss pro Frame sowie Position und Farbe jedes Bildpixels.

nes_split_scroll_sprite0: SPLIT_ALIAS-DEFAULT — Über dem weißen Band liegt Blau bei X=64..95 und Rot bei X=160..191. Darunter ab Y=104 liegt Blau bei X=32..63, Rot bei X=128..159; nur der untere Bereich wandert 32 Pixel nach links. Das Band liegt bei Y=96..103, die Balken enden bei Y=207. Geprüft werden ein Abschluss pro Frame sowie Position und Farbe jedes Bildpixels.
SPLIT_ALIAS-DEFAULT — Über dem weißen Band liegt Blau bei X=64..95 und Rot bei X=160..191. Darunter ab Y=104 liegt Blau bei X=32..63, Rot bei X=128..159; nur der untere Bereich wandert 32 Pixel nach links. Das Band liegt bei Y=96..103, die Balken enden bei Y=207. Geprüft werden ein Abschluss pro Frame sowie Position und Farbe jedes Bildpixels.

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/nes_game.h:37

nes_sprite_hide

Makro aus nes_game.h: Es wird zum in der Syntax gezeigten Intrinsic expandiert. Binden Sie diesen Header ein; für diese Operation ist keine C-Implementierungsdatei erforderlich.

Blendet einen Sprite im Schattenpuffer aus, indem Y auf 0xF0 gesetzt wird. X, Kachel und Attribute bleiben zur Wiederverwendung erhalten. Die Funktion gibt keinen Platz frei und ändert den Belegungszähler der Sprite-Bibliothek nicht.

Syntax

c
#define nes_sprite_hide(i)                 __sprite_hide((i))

Parameter

i

Sprite-Index von 0 bis 63, kein Byte-Offset. Intern wird er mit vier multipliziert und als 8-Bit-Position gespeichert. Werte außerhalb des Bereichs werden modulo 64 umgebrochen und können einen anderen Eintrag überschreiben. Eine Belegungsprüfung findet nicht statt.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Diese Operationen ändern den CPU-RAM bei 0x0200–0x02FF, nicht sofort das Hardware-OAM. Übertragen Sie die fertige Seite mit __oam_dma. Belegungsflags, Koordinatenfelder und Zähler der Sprite-Bibliothek werden nicht mitgeführt. Interrupt-Routinen dürfen eine noch unvollständige Seite weder ändern noch übertragen.

Anwendungsbeispiel

c
nes_sprite_hide(4); // The HIDE row remains empty after DMA.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel zeigt jede Operation in einer beschrifteten Zeile. SET und MOVE zeigen 8×8-Pfeile nach rechts bei (144,16) und (144,32), TILE ein grünes Quadrat bei (144,48) und ATTR den in beiden Achsen gespiegelten Pfeil bei (144,64). HIDE bei (144,80) und CLEAR bei (144,112) müssen leer bleiben. META zeigt zwei Pfeile bei (136,96) und (144,96), den zweiten horizontal gespiegelt. NEXT 07 bezeichnet die nächste Position nach den Einträgen 5 und 6. Die Ränder sind rot, der Schaft grün und die Spitzendetails blau. Geprüft werden 8.704 Pixel je Bild und die übertragenen OAM-Bytes; echte Hardware wurde nicht getestet.

Das Programm ALIASES bereitet die beschrifteten Zeilen mit Makros aus nes_game.h vor und sendet Seite 02 mit nes_oam_dma(). TRANSFER zeigt den 8×8-Pfeil bei (144,128). Das Beispiel verwendet die Makros, ohne runtime.c oder metasprite.c einzubinden.

nes_sprite_hide: Aliasse
Aliasse

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/nes_game.h:26

c
#define nes_sprite_hide(i)                 __sprite_hide((i))
nes_sprite_move

Makro aus nes_game.h: Es wird zum in der Syntax gezeigten Intrinsic expandiert. Binden Sie diesen Header ein; für diese Operation ist keine C-Implementierungsdatei erforderlich.

Ändert nur die X- und Y-Bytes eines Sprites im Schattenpuffer. Kachelnummer und Attribute bleiben erhalten; dieselbe Grafik wird ohne Änderung der Palette oder Spiegelung verschoben.

Syntax

c
#define nes_sprite_move(i,x,y)             __sprite_move((i),(x),(y))

Parameter

i

Sprite-Index von 0 bis 63, kein Byte-Offset. Intern wird er mit vier multipliziert und als 8-Bit-Position gespeichert. Werte außerhalb des Bereichs werden modulo 64 umgebrochen und können einen anderen Eintrag überschreiben. Eine Belegungsprüfung findet nicht statt.

x

Horizontale Position in Pixeln als vorzeichenloses Byte; keine Tile-Koordinate.

y

Y-Byte des OAM. Für eine Oberkante unterhalb der Zeile null wird ihre Position minus eins übergeben; 239..255 liegen außerhalb der 240 sichtbaren Zeilen.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Diese Operationen ändern den CPU-RAM bei 0x0200–0x02FF, nicht sofort das Hardware-OAM. Übertragen Sie die fertige Seite mit __oam_dma. Belegungsflags, Koordinatenfelder und Zähler der Sprite-Bibliothek werden nicht mitgeführt. Interrupt-Routinen dürfen eine noch unvollständige Seite weder ändern noch übertragen.

Anwendungsbeispiel

c
nes_sprite_move(1,144,31); // Move to (144,32), retaining tile 128 and attributes 0.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel zeigt jede Operation in einer beschrifteten Zeile. SET und MOVE zeigen 8×8-Pfeile nach rechts bei (144,16) und (144,32), TILE ein grünes Quadrat bei (144,48) und ATTR den in beiden Achsen gespiegelten Pfeil bei (144,64). HIDE bei (144,80) und CLEAR bei (144,112) müssen leer bleiben. META zeigt zwei Pfeile bei (136,96) und (144,96), den zweiten horizontal gespiegelt. NEXT 07 bezeichnet die nächste Position nach den Einträgen 5 und 6. Die Ränder sind rot, der Schaft grün und die Spitzendetails blau. Geprüft werden 8.704 Pixel je Bild und die übertragenen OAM-Bytes; echte Hardware wurde nicht getestet.

Das Programm ALIASES bereitet die beschrifteten Zeilen mit Makros aus nes_game.h vor und sendet Seite 02 mit nes_oam_dma(). TRANSFER zeigt den 8×8-Pfeil bei (144,128). Das Beispiel verwendet die Makros, ohne runtime.c oder metasprite.c einzubinden.

nes_sprite_move: Aliasse
Aliasse

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/nes_game.h:25

c
#define nes_sprite_move(i,x,y)             __sprite_move((i),(x),(y))
nes_sprite_set

Makro aus nes_game.h: Es wird zum in der Syntax gezeigten Intrinsic expandiert. Binden Sie diesen Header ein; für diese Operation ist keine C-Implementierungsdatei erforderlich.

Schreibt alle vier Felder eines Sprites in den Schattenpuffer der Seite 02. Die Argumente lauten Index, X, Y, Kachel und Attribute; gespeichert wird in der Reihenfolge Y, Kachel, Attribute, X.

Syntax

c
#define nes_sprite_set(i,x,y,t,a)          __sprite_set((i),(x),(y),(t),(a))

Parameter

i

Sprite-Index von 0 bis 63, kein Byte-Offset. Intern wird er mit vier multipliziert und als 8-Bit-Position gespeichert. Werte außerhalb des Bereichs werden modulo 64 umgebrochen und können einen anderen Eintrag überschreiben. Eine Belegungsprüfung findet nicht statt.

x

Horizontale Position in Pixeln als vorzeichenloses Byte; keine Tile-Koordinate.

y

Y-Byte des OAM. Für eine Oberkante unterhalb der Zeile null wird ihre Position minus eins übergeben; 239..255 liegen außerhalb der 240 sichtbaren Zeilen.

t

8-Bit-Tile-Nummer. Die Grafik muss vorher geladen werden. Die Hardware-Regeln für 8×16-Sprites gelten weiterhin; die Nummer wird nicht für Tile-Paare angepasst.

a

Vollständiges Attributbyte: Bits 0–1 wählen Palette 0–3; Bit 5 legt undurchsichtige Sprite-Pixel hinter undurchsichtige Hintergrundpixel; Bits 6 und 7 spiegeln horizontal beziehungsweise vertikal. Bits 2–4 müssen null bleiben. Kombinieren Sie Flags mit bitweisem ODER; das Byte ersetzt sämtliche bisherigen Attribute.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Diese Operationen ändern den CPU-RAM bei 0x0200–0x02FF, nicht sofort das Hardware-OAM. Übertragen Sie die fertige Seite mit __oam_dma. Belegungsflags, Koordinatenfelder und Zähler der Sprite-Bibliothek werden nicht mitgeführt. Interrupt-Routinen dürfen eine noch unvollständige Seite weder ändern noch übertragen.

Anwendungsbeispiel

c
nes_sprite_set(0,144,15,128,0); // An 8x8 arrow at visible position (144,16).

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel zeigt jede Operation in einer beschrifteten Zeile. SET und MOVE zeigen 8×8-Pfeile nach rechts bei (144,16) und (144,32), TILE ein grünes Quadrat bei (144,48) und ATTR den in beiden Achsen gespiegelten Pfeil bei (144,64). HIDE bei (144,80) und CLEAR bei (144,112) müssen leer bleiben. META zeigt zwei Pfeile bei (136,96) und (144,96), den zweiten horizontal gespiegelt. NEXT 07 bezeichnet die nächste Position nach den Einträgen 5 und 6. Die Ränder sind rot, der Schaft grün und die Spitzendetails blau. Geprüft werden 8.704 Pixel je Bild und die übertragenen OAM-Bytes; echte Hardware wurde nicht getestet.

Das Programm ALIASES bereitet die beschrifteten Zeilen mit Makros aus nes_game.h vor und sendet Seite 02 mit nes_oam_dma(). TRANSFER zeigt den 8×8-Pfeil bei (144,128). Das Beispiel verwendet die Makros, ohne runtime.c oder metasprite.c einzubinden.

nes_sprite_set: Aliasse
Aliasse

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/nes_game.h:24

c
#define nes_sprite_set(i,x,y,t,a)          __sprite_set((i),(x),(y),(t),(a))
nes_vram_clear_queue

Makro aus nes_game.h: Es wird zum in der Syntax gezeigten Intrinsic expandiert. Binden Sie diesen Header ein; für diese Operation ist keine C-Implementierungsdatei erforderlich.

Verwirft alle ausstehenden Einträge und setzt Länge sowie Bereit-Flag auf 0. Schreibt nicht ins VRAM und löscht die Überlaufmeldung nicht. Rufen Sie dafür gesondert __vramq_clear_overflow auf.

Syntax

c
#define nes_vram_clear_queue()             __vramq_clear()

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

FC zählt codierte Befehlsbytes in einem festen intrinsischen 128-Byte-Puffer. Ein Tile-Schreibbefehl braucht 4 Bytes, ein Fülleintrag 5 und eine Zeigerkopie 6 einschließlich Metadaten. NMI kann eine bereite Warteschlange verarbeiten; prüfen und befüllen Sie sie vor der Freigabe und koordinieren Sie Erzeuger und Verbraucher.

Diese Makros verwenden die Intrinsic-Befehlswarteschlange des Compilers, die auch lib/vram.c nutzt. Sie wählen nicht den C-Laufzeitpuffer nes_vram_queue_*. Mit __vramq_len() lesen Sie die Zahl ausstehender codierter Bytes, mit __vramq_overflow() erkennen Sie Kapazitätsfehler; __vramq_clear_overflow() löscht das Fehlerflag.

Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.

Anwendungsbeispiel

c
nes_vram_clear_queue();
if (__vramq_len()!=0 || __vramq_overflow()!=1) failures++;
// Clearing queued work deliberately leaves the overflow latch set.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm verwendet Makros aus nes_game.h zum Einreihen einzelner Bytes, Kopieren, Füllen, Freigeben und Leeren der Warteschlange. Zusätzlich prüfen die Abfrage- und Ausführungs-Intrinsics __vramq_* deren Wirkung. Der Titel lautet VRAM QUEUE MACROS. Große Übertragungen laufen bei abgeschalteter Bildausgabe; ihre Freigabe garantiert nicht, dass sie innerhalb von VBlank abgeschlossen werden.

Das Programm zeigt Kapazität, gespeicherte Zeiger, getrennte Rücksetzfunktionen sowie direkte und NMI-Ausführung. Erwartet werden CAPACITY 128, ENCODED BYTES 030, AFTER EXEC 000, OVERFLOW SEEN 001 und FAILED CHECKS 000. Sechs Einträge belegen 30 Bytes und führen 512 Byte-Schreibzugriffe aus. OVERFLOW SEEN speichert die frühere absichtliche Ablehnung; es bedeutet nicht, dass am Ende noch ein Überlauf gemeldet wird.

Die blaue Kopie beginnt bei Pixel (0,16), die grüne Füllung bei (0,88). Jeder Bereich umfasst sieben vollständige Kachelzeilen mit 256 Pixeln Breite und 248 Pixel der achten: insgesamt 255 Kacheln. Das letzte Feld von 8 × 8 bleibt schwarz. Die Kopie wiederholt volle, links halbvolle und dreieckige Muster; das erste ist ein Dreieck, weil die Quelle nach dem Einreihen geändert wird. Die Füllung bleibt trotz geänderter Aufrufervariable voll. Form und Farbe werden geprüft.

Bei y=160 werden ein volles rotes Quadrat bei x=16, eine rote linke Halbkachel bei x=224 und ein volles rotes Quadrat bei x=240 erwartet. Das erste übersteht Einträge mit Länge null, das mittlere belegt die NMI-Verarbeitung, das letzte einen einzelnen Put. Das verworfene Feld bei (248,160) bleibt schwarz. Lange Transfers laufen bei abgeschaltetem Rendering und NMI; nur der letzte kleine Schreibzugriff nutzt NMI. Dies ist ein NROM-Emulatortest, kein Test auf echter Hardware.

nes_vram_clear_queue: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/nes_game.h:19

c
#define nes_vram_clear_queue()             __vramq_clear()
nes_vram_commit

Makro aus nes_game.h: Es wird zum in der Syntax gezeigten Intrinsic expandiert. Binden Sie diesen Header ein; für diese Operation ist keine C-Implementierungsdatei erforderlich.

Setzt das Bereit-Flag auf 1 und erlaubt damit die Verarbeitung. Kopiert keine Nutzdaten, schreibt nicht in die PPU und wartet nicht auf NMI. Halten Sie Warteschlange und gespeicherte Quellen nach der Freigabe bis zum Abschluss unverändert. Bei aktiviertem NMI kann der Standardhandler sie asynchron verarbeiten.

Syntax

c
#define nes_vram_commit()                  __vramq_commit()

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

FC zählt codierte Befehlsbytes in einem festen intrinsischen 128-Byte-Puffer. Ein Tile-Schreibbefehl braucht 4 Bytes, ein Fülleintrag 5 und eine Zeigerkopie 6 einschließlich Metadaten. NMI kann eine bereite Warteschlange verarbeiten; prüfen und befüllen Sie sie vor der Freigabe und koordinieren Sie Erzeuger und Verbraucher.

Diese Makros verwenden die Intrinsic-Befehlswarteschlange des Compilers, die auch lib/vram.c nutzt. Sie wählen nicht den C-Laufzeitpuffer nes_vram_queue_*. Mit __vramq_len() lesen Sie die Zahl ausstehender codierter Bytes, mit __vramq_overflow() erkennen Sie Kapazitätsfehler; __vramq_clear_overflow() löscht das Fehlerflag.

Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.

Anwendungsbeispiel

c
nes_vram_commit(); // NMI is disabled here: this only marks the queue ready.
if (__vramq_len()!=30) failures++;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm verwendet Makros aus nes_game.h zum Einreihen einzelner Bytes, Kopieren, Füllen, Freigeben und Leeren der Warteschlange. Zusätzlich prüfen die Abfrage- und Ausführungs-Intrinsics __vramq_* deren Wirkung. Der Titel lautet VRAM QUEUE MACROS. Große Übertragungen laufen bei abgeschalteter Bildausgabe; ihre Freigabe garantiert nicht, dass sie innerhalb von VBlank abgeschlossen werden.

Das Programm zeigt Kapazität, gespeicherte Zeiger, getrennte Rücksetzfunktionen sowie direkte und NMI-Ausführung. Erwartet werden CAPACITY 128, ENCODED BYTES 030, AFTER EXEC 000, OVERFLOW SEEN 001 und FAILED CHECKS 000. Sechs Einträge belegen 30 Bytes und führen 512 Byte-Schreibzugriffe aus. OVERFLOW SEEN speichert die frühere absichtliche Ablehnung; es bedeutet nicht, dass am Ende noch ein Überlauf gemeldet wird.

Die blaue Kopie beginnt bei Pixel (0,16), die grüne Füllung bei (0,88). Jeder Bereich umfasst sieben vollständige Kachelzeilen mit 256 Pixeln Breite und 248 Pixel der achten: insgesamt 255 Kacheln. Das letzte Feld von 8 × 8 bleibt schwarz. Die Kopie wiederholt volle, links halbvolle und dreieckige Muster; das erste ist ein Dreieck, weil die Quelle nach dem Einreihen geändert wird. Die Füllung bleibt trotz geänderter Aufrufervariable voll. Form und Farbe werden geprüft.

Bei y=160 werden ein volles rotes Quadrat bei x=16, eine rote linke Halbkachel bei x=224 und ein volles rotes Quadrat bei x=240 erwartet. Das erste übersteht Einträge mit Länge null, das mittlere belegt die NMI-Verarbeitung, das letzte einen einzelnen Put. Das verworfene Feld bei (248,160) bleibt schwarz. Lange Transfers laufen bei abgeschaltetem Rendering und NMI; nur der letzte kleine Schreibzugriff nutzt NMI. Dies ist ein NROM-Emulatortest, kein Test auf echter Hardware.

nes_vram_commit: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/nes_game.h:18

c
#define nes_vram_commit()                  __vramq_commit()
nes_vram_copy

Makro aus nes_game.h: Es wird zum in der Syntax gezeigten Intrinsic expandiert. Binden Sie diesen Header ein; für diese Operation ist keine C-Implementierungsdatei erforderlich.

Fügt einen Sechs-Byte-Eintrag an, der bei der Ausführung len Bytes von src nach ppu_addr kopiert. Gespeichert wird der Zeiger, nicht der Inhalt. Selbst eine Kopie von 255 Bytes belegt nur sechs Pufferbytes. Die Quelle wird aufsteigend gelesen; für ein fortlaufendes Ziel wählen Sie PPU-Schrittweite 1.

Syntax

c
#define nes_vram_copy(addr, src, len)      __vramq_copy((addr), (src), (len))

Parameter

addr

PPU-Byteadresse (0x0000–0x3FFF), kein CPU-Zeiger. Das Ziel muss beschreibbar sein: Musteränderungen benötigen CHR-RAM statt CHR-ROM. PPU-Adressabbildung und Spiegelung gelten weiterhin. Wählen Sie für fortlaufendes Kopieren und Füllen die Schrittweite 1 in PPUCTRL. Führen Sie Befehle zu einem sicheren PPU-Zeitpunkt aus und stellen Sie danach den Scrollzustand her; der Ausführer schreibt PPUADDR und PPUDATA, ohne Scrolleinstellungen wiederherzustellen.

src

Nahzeiger auf lesbare Bytes, der bis zur Ausführung gespeichert bleibt. Daten und ihre Speicher- oder ROM-Bank müssen während der gesamten Verarbeitung gültig und eingeblendet bleiben; weder Banknummer noch Kopie werden gespeichert. Nichtleere Übertragungen benötigen eine gültige Quelle. Verwenden Sie kein abgelaufenes lokales Array.

len

Byteanzahl von 0 bis 255. Ein Eintrag verarbeitet die gesamte Anzahl ohne Aufteilung in 127-Byte-Abschnitte. Auch null belegt einen Kopier- oder Fülleintrag. Bei dessen Ausführung wird die PPU-Adresse gesetzt, aber kein Byte nach PPUDATA geschrieben. 256 liegt außerhalb des Argumentbereichs.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Das Einfügen liefert keinen Erfolgswert. Passt der vollständige Eintrag nicht, wird __vramq_overflow() auf 1 gesetzt; vorhandene Einträge und Länge bleiben erhalten. Genau passender Platz wird akzeptiert. Eine frühere Überlaufmeldung verhindert keinen passenden Eintrag; behandeln oder löschen Sie sie vor der Bewertung eines neuen Stapels. Mehrere Einfügevorgänge bilden keine Transaktion.

FC zählt codierte Befehlsbytes in einem festen intrinsischen 128-Byte-Puffer. Ein Tile-Schreibbefehl braucht 4 Bytes, ein Fülleintrag 5 und eine Zeigerkopie 6 einschließlich Metadaten. NMI kann eine bereite Warteschlange verarbeiten; prüfen und befüllen Sie sie vor der Freigabe und koordinieren Sie Erzeuger und Verbraucher.

Diese Makros verwenden die Intrinsic-Befehlswarteschlange des Compilers, die auch lib/vram.c nutzt. Sie wählen nicht den C-Laufzeitpuffer nes_vram_queue_*. Mit __vramq_len() lesen Sie die Zahl ausstehender codierter Bytes, mit __vramq_overflow() erkennen Sie Kapazitätsfehler; __vramq_clear_overflow() löscht das Fehlerflag.

Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.

Anwendungsbeispiel

c
nes_vram_copy(0x2040,source_bytes,255);
source_bytes[0]=3; // The executor must see this change through its retained pointer.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm verwendet Makros aus nes_game.h zum Einreihen einzelner Bytes, Kopieren, Füllen, Freigeben und Leeren der Warteschlange. Zusätzlich prüfen die Abfrage- und Ausführungs-Intrinsics __vramq_* deren Wirkung. Der Titel lautet VRAM QUEUE MACROS. Große Übertragungen laufen bei abgeschalteter Bildausgabe; ihre Freigabe garantiert nicht, dass sie innerhalb von VBlank abgeschlossen werden.

Das Programm zeigt Kapazität, gespeicherte Zeiger, getrennte Rücksetzfunktionen sowie direkte und NMI-Ausführung. Erwartet werden CAPACITY 128, ENCODED BYTES 030, AFTER EXEC 000, OVERFLOW SEEN 001 und FAILED CHECKS 000. Sechs Einträge belegen 30 Bytes und führen 512 Byte-Schreibzugriffe aus. OVERFLOW SEEN speichert die frühere absichtliche Ablehnung; es bedeutet nicht, dass am Ende noch ein Überlauf gemeldet wird.

Die blaue Kopie beginnt bei Pixel (0,16), die grüne Füllung bei (0,88). Jeder Bereich umfasst sieben vollständige Kachelzeilen mit 256 Pixeln Breite und 248 Pixel der achten: insgesamt 255 Kacheln. Das letzte Feld von 8 × 8 bleibt schwarz. Die Kopie wiederholt volle, links halbvolle und dreieckige Muster; das erste ist ein Dreieck, weil die Quelle nach dem Einreihen geändert wird. Die Füllung bleibt trotz geänderter Aufrufervariable voll. Form und Farbe werden geprüft.

Bei y=160 werden ein volles rotes Quadrat bei x=16, eine rote linke Halbkachel bei x=224 und ein volles rotes Quadrat bei x=240 erwartet. Das erste übersteht Einträge mit Länge null, das mittlere belegt die NMI-Verarbeitung, das letzte einen einzelnen Put. Das verworfene Feld bei (248,160) bleibt schwarz. Lange Transfers laufen bei abgeschaltetem Rendering und NMI; nur der letzte kleine Schreibzugriff nutzt NMI. Dies ist ein NROM-Emulatortest, kein Test auf echter Hardware.

nes_vram_copy: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/nes_game.h:16

c
#define nes_vram_copy(addr, src, len)      __vramq_copy((addr), (src), (len))
nes_vram_fill

Makro aus nes_game.h: Es wird zum in der Syntax gezeigten Intrinsic expandiert. Binden Sie diesen Header ein; für diese Operation ist keine C-Implementierungsdatei erforderlich.

Fügt einen Fünf-Byte-Eintrag an, der das Byte value bei len PPU-Schreibzugriffen wiederholt. Der Wert wird gespeichert; spätere Änderungen der Aufrufervariablen ändern den eingereihten Füllwert nicht. Wiederholt wird ein Byte, kein mehrteiliges Kachelmuster.

Syntax

c
#define nes_vram_fill(addr, value, len)    __vramq_fill((addr), (value), (len))

Parameter

addr

PPU-Byteadresse (0x0000–0x3FFF), kein CPU-Zeiger. Das Ziel muss beschreibbar sein: Musteränderungen benötigen CHR-RAM statt CHR-ROM. PPU-Adressabbildung und Spiegelung gelten weiterhin. Wählen Sie für fortlaufendes Kopieren und Füllen die Schrittweite 1 in PPUCTRL. Führen Sie Befehle zu einem sicheren PPU-Zeitpunkt aus und stellen Sie danach den Scrollzustand her; der Ausführer schreibt PPUADDR und PPUDATA, ohne Scrolleinstellungen wiederherzustellen.

value

Ein wiederholtes Byte von 0 bis 255. Seine sichtbare Wirkung hängt davon ab, ob das Ziel Tile-Indizes, Pixelebenen oder eine andere Bytestruktur enthält.

len

Byteanzahl von 0 bis 255. Ein Eintrag verarbeitet die gesamte Anzahl ohne Aufteilung in 127-Byte-Abschnitte. Auch null belegt einen Kopier- oder Fülleintrag. Bei dessen Ausführung wird die PPU-Adresse gesetzt, aber kein Byte nach PPUDATA geschrieben. 256 liegt außerhalb des Argumentbereichs.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Das Einfügen liefert keinen Erfolgswert. Passt der vollständige Eintrag nicht, wird __vramq_overflow() auf 1 gesetzt; vorhandene Einträge und Länge bleiben erhalten. Genau passender Platz wird akzeptiert. Eine frühere Überlaufmeldung verhindert keinen passenden Eintrag; behandeln oder löschen Sie sie vor der Bewertung eines neuen Stapels. Mehrere Einfügevorgänge bilden keine Transaktion.

FC zählt codierte Befehlsbytes in einem festen intrinsischen 128-Byte-Puffer. Ein Tile-Schreibbefehl braucht 4 Bytes, ein Fülleintrag 5 und eine Zeigerkopie 6 einschließlich Metadaten. NMI kann eine bereite Warteschlange verarbeiten; prüfen und befüllen Sie sie vor der Freigabe und koordinieren Sie Erzeuger und Verbraucher.

Diese Makros verwenden die Intrinsic-Befehlswarteschlange des Compilers, die auch lib/vram.c nutzt. Sie wählen nicht den C-Laufzeitpuffer nes_vram_queue_*. Mit __vramq_len() lesen Sie die Zahl ausstehender codierter Bytes, mit __vramq_overflow() erkennen Sie Kapazitätsfehler; __vramq_clear_overflow() löscht das Fehlerflag.

Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.

Anwendungsbeispiel

c
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.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm verwendet Makros aus nes_game.h zum Einreihen einzelner Bytes, Kopieren, Füllen, Freigeben und Leeren der Warteschlange. Zusätzlich prüfen die Abfrage- und Ausführungs-Intrinsics __vramq_* deren Wirkung. Der Titel lautet VRAM QUEUE MACROS. Große Übertragungen laufen bei abgeschalteter Bildausgabe; ihre Freigabe garantiert nicht, dass sie innerhalb von VBlank abgeschlossen werden.

Das Programm zeigt Kapazität, gespeicherte Zeiger, getrennte Rücksetzfunktionen sowie direkte und NMI-Ausführung. Erwartet werden CAPACITY 128, ENCODED BYTES 030, AFTER EXEC 000, OVERFLOW SEEN 001 und FAILED CHECKS 000. Sechs Einträge belegen 30 Bytes und führen 512 Byte-Schreibzugriffe aus. OVERFLOW SEEN speichert die frühere absichtliche Ablehnung; es bedeutet nicht, dass am Ende noch ein Überlauf gemeldet wird.

Die blaue Kopie beginnt bei Pixel (0,16), die grüne Füllung bei (0,88). Jeder Bereich umfasst sieben vollständige Kachelzeilen mit 256 Pixeln Breite und 248 Pixel der achten: insgesamt 255 Kacheln. Das letzte Feld von 8 × 8 bleibt schwarz. Die Kopie wiederholt volle, links halbvolle und dreieckige Muster; das erste ist ein Dreieck, weil die Quelle nach dem Einreihen geändert wird. Die Füllung bleibt trotz geänderter Aufrufervariable voll. Form und Farbe werden geprüft.

Bei y=160 werden ein volles rotes Quadrat bei x=16, eine rote linke Halbkachel bei x=224 und ein volles rotes Quadrat bei x=240 erwartet. Das erste übersteht Einträge mit Länge null, das mittlere belegt die NMI-Verarbeitung, das letzte einen einzelnen Put. Das verworfene Feld bei (248,160) bleibt schwarz. Lange Transfers laufen bei abgeschaltetem Rendering und NMI; nur der letzte kleine Schreibzugriff nutzt NMI. Dies ist ein NROM-Emulatortest, kein Test auf echter Hardware.

nes_vram_fill: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/nes_game.h:17

c
#define nes_vram_fill(addr, value, len)    __vramq_fill((addr), (value), (len))
nes_vram_put

Makro aus nes_game.h: Es wird zum in der Syntax gezeigten Intrinsic expandiert. Binden Sie diesen Header ein; für diese Operation ist keine C-Implementierungsdatei erforderlich.

Fügt eine PPU-Adresse und einen Bytewert als Vier-Byte-Eintrag an. Der Wert wird sofort in die Warteschlange kopiert und erst bei deren Ausführung geschrieben. Dies eignet sich etwa für eine Nametable-Kachel oder ein anderes beschreibbares PPU-Byte.

Syntax

c
#define nes_vram_put(addr, value)          __vramq_put((addr), (value))

Parameter

addr

PPU-Byteadresse (0x0000–0x3FFF), kein CPU-Zeiger. Das Ziel muss beschreibbar sein: Musteränderungen benötigen CHR-RAM statt CHR-ROM. PPU-Adressabbildung und Spiegelung gelten weiterhin. Wählen Sie für fortlaufendes Kopieren und Füllen die Schrittweite 1 in PPUCTRL. Führen Sie Befehle zu einem sicheren PPU-Zeitpunkt aus und stellen Sie danach den Scrollzustand her; der Ausführer schreibt PPUADDR und PPUDATA, ohne Scrolleinstellungen wiederherzustellen.

value

Ein wiederholtes Byte von 0 bis 255. Seine sichtbare Wirkung hängt davon ab, ob das Ziel Tile-Indizes, Pixelebenen oder eine andere Bytestruktur enthält.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Das Einfügen liefert keinen Erfolgswert. Passt der vollständige Eintrag nicht, wird __vramq_overflow() auf 1 gesetzt; vorhandene Einträge und Länge bleiben erhalten. Genau passender Platz wird akzeptiert. Eine frühere Überlaufmeldung verhindert keinen passenden Eintrag; behandeln oder löschen Sie sie vor der Bewertung eines neuen Stapels. Mehrere Einfügevorgänge bilden keine Transaktion.

FC zählt codierte Befehlsbytes in einem festen intrinsischen 128-Byte-Puffer. Ein Tile-Schreibbefehl braucht 4 Bytes, ein Fülleintrag 5 und eine Zeigerkopie 6 einschließlich Metadaten. NMI kann eine bereite Warteschlange verarbeiten; prüfen und befüllen Sie sie vor der Freigabe und koordinieren Sie Erzeuger und Verbraucher.

Diese Makros verwenden die Intrinsic-Befehlswarteschlange des Compilers, die auch lib/vram.c nutzt. Sie wählen nicht den C-Laufzeitpuffer nes_vram_queue_*. Mit __vramq_len() lesen Sie die Zahl ausstehender codierter Bytes, mit __vramq_overflow() erkennen Sie Kapazitätsfehler; __vramq_clear_overflow() löscht das Fehlerflag.

Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.

Anwendungsbeispiel

c
nes_vram_put(0x2282,1); // Red 8x8 sentinel at pixel (16,160).

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm verwendet Makros aus nes_game.h zum Einreihen einzelner Bytes, Kopieren, Füllen, Freigeben und Leeren der Warteschlange. Zusätzlich prüfen die Abfrage- und Ausführungs-Intrinsics __vramq_* deren Wirkung. Der Titel lautet VRAM QUEUE MACROS. Große Übertragungen laufen bei abgeschalteter Bildausgabe; ihre Freigabe garantiert nicht, dass sie innerhalb von VBlank abgeschlossen werden.

Das Programm zeigt Kapazität, gespeicherte Zeiger, getrennte Rücksetzfunktionen sowie direkte und NMI-Ausführung. Erwartet werden CAPACITY 128, ENCODED BYTES 030, AFTER EXEC 000, OVERFLOW SEEN 001 und FAILED CHECKS 000. Sechs Einträge belegen 30 Bytes und führen 512 Byte-Schreibzugriffe aus. OVERFLOW SEEN speichert die frühere absichtliche Ablehnung; es bedeutet nicht, dass am Ende noch ein Überlauf gemeldet wird.

Die blaue Kopie beginnt bei Pixel (0,16), die grüne Füllung bei (0,88). Jeder Bereich umfasst sieben vollständige Kachelzeilen mit 256 Pixeln Breite und 248 Pixel der achten: insgesamt 255 Kacheln. Das letzte Feld von 8 × 8 bleibt schwarz. Die Kopie wiederholt volle, links halbvolle und dreieckige Muster; das erste ist ein Dreieck, weil die Quelle nach dem Einreihen geändert wird. Die Füllung bleibt trotz geänderter Aufrufervariable voll. Form und Farbe werden geprüft.

Bei y=160 werden ein volles rotes Quadrat bei x=16, eine rote linke Halbkachel bei x=224 und ein volles rotes Quadrat bei x=240 erwartet. Das erste übersteht Einträge mit Länge null, das mittlere belegt die NMI-Verarbeitung, das letzte einen einzelnen Put. Das verworfene Feld bei (248,160) bleibt schwarz. Lange Transfers laufen bei abgeschaltetem Rendering und NMI; nur der letzte kleine Schreibzugriff nutzt NMI. Dies ist ein NROM-Emulatortest, kein Test auf echter Hardware.

nes_vram_put: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/nes_game.h:15

c
#define nes_vram_put(addr, value)          __vramq_put((addr), (value))

oam_fair.h — Wechselnder Spritevorrang mit Prioritäten

Hängt aktive Einträge aus einem Software-Pool mit 64 Elementen an den OAM-Schattenpuffer an. Vor jedem Durchlauf wird der Startindex um 13 modulo 64 erhöht. Wiederholte Aufrufe verteilen durch wechselnde OAM-Priorität das Sprite-Flackern; die Hardwaregrenze wird dadurch nicht erhöht.

Definieren Sie die Arrays X, Y, active und shadow sowie den used-Zeiger selbst; binden Sie oam_fair_impl.h einmal in einer festen PRG-Bank ein. Rufen Sie die Routine aus der Hauptschleife im 8×8-Sprite-Modus auf. Koordinaten laufen modulo 256 über, ohne Clipping. Die Routine überträgt kein OAM: Nutzen Sie DMA mit der Seite des shadow-Puffers. Die Hardwaregrenzen bleiben 64 OAM-Sprites und acht Sprites pro Bildzeile.

OAM_FairDraw

Hängt aktive Einträge aus einem Software-Pool mit 64 Elementen an den OAM-Schattenpuffer an. Vor jedem Durchlauf wird der Startindex um 13 modulo 64 erhöht. Wiederholte Aufrufe verteilen durch wechselnde OAM-Priorität das Sprite-Flackern; die Hardwaregrenze wird dadurch nicht erhöht.

Syntax

c
void OAM_FairDraw(void);

Rückgabewert

Kein C-Rückgabewert. oam_fair_drawn enthält die Zahl der angehängten Einträge, oam_fair_used den aktualisierten Bytezeiger und oam_fair_phase den Startindex des Durchlaufs. Die Phase wird auch ohne gezeichneten Eintrag weitergeschaltet; oam_fair_drawn ist dann null.

Bedingungen und Grenzen

Die Funktion hat keine Parameter; konfigurieren Sie die gemeinsamen Variablen. oam_fair_x[64] und oam_fair_y[64] enthalten die Mittelpunkte der 8×8-Sprites in Pixeln: OAM-X ist Mittelpunkt X−4, OAM-Y ist Mittelpunkt Y−5. Einträge mit einem Wert ungleich null in oam_fair_active[64] werden ausgewählt. Alle ausgegebenen Einträge verwenden das gemeinsame Tile und Attributbyte aus oam_fair_tile und oam_fair_attr.

Setzen Sie oam_fair_used auf den nächsten freien Byteoffset in oam_fair_shadow[256], ausgerichtet auf vier Bytes. oam_fair_limit begrenzt die Zahl der in diesem Aufruf angehängten Einträge. Es werden höchstens 64 Pool-Einträge geprüft; ab Byteoffset 252 wird nicht mehr geschrieben, sodass Slot 63 frei bleibt. Frühere Einträge bleiben erhalten; unbenutzte Einträge am Ende müssen separat ausgeblendet werden.

Definieren Sie die Arrays X, Y, active und shadow sowie den used-Zeiger selbst; binden Sie oam_fair_impl.h einmal in einer festen PRG-Bank ein. Rufen Sie die Routine aus der Hauptschleife im 8×8-Sprite-Modus auf. Koordinaten laufen modulo 256 über, ohne Clipping. Die Routine überträgt kein OAM: Nutzen Sie DMA mit der Seite des shadow-Puffers. Die Hardwaregrenzen bleiben 64 OAM-Sprites und acht Sprites pro Bildzeile.

Anwendungsbeispiel

c
oam_fair_used=4; // Byte cursor: reserve the already prepared slot 0.
OAM_FairDraw(); // Phase becomes 13; append pool entries 13, 14 and 15.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

FAIR-POOL erhält ein grünes 8×8-Quadrat bei (144,32) in Slot 0 und hängt drei Pfeile mit den Mittelpunkten (148,68), (164,68) und (180,68) an. Ihre sichtbaren linken oberen Ecken müssen bei (144,64), (160,64) und (176,64) liegen. Mit phase=0 und used=4 entstehen PHASE 13, DRAWN 03 und BYTES 16. Das Standbild prüft Position und Erhaltung; ein separater Zustandstest mit 64 Aufrufen prüft, dass jeder Pool-Eintrag genau einmal Startpunkt ist.

Die Pfeile haben rote Ränder, grüne Schäfte und blaue Details an der Spitze; das Quadrat-Tile 129 ist grün. Die Prüfung vergleicht pro Bild 8.704 Farbpixel, alle 256 übertragenen OAM-Bytes und die Beschriftungen. Physische Hardware wurde nicht getestet.

OAM_FairDraw: FAIR-POOL
FAIR-POOL

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/oam_fair.h:24

Deklarationshinweise im Original
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

c
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 — NES-Controllereingaben

pad.h und pad.c speichern Controller 1 in NES-Bitreihenfolge. Die Abfrage berechnet vorherigen Zustand, Halten, neue Tastendrücke und Loslassen, aber keine Wiederholung. Für einstellbare Wiederholung pro Taste zusätzlich input_repeat.c linken. Controller 2 liest du mit einer Port-2-Intrinsic; den vorherigen Zustand verwaltet dein Spiel.

Rohes NES-Format: A=0x01, B=0x02, SELECT=0x04, START=0x08, UP=0x10, DOWN=0x20, LEFT=0x40, RIGHT=0x80. Ein gesetztes Bit bedeutet gedrückt. Verwende diese Werte mit nes_pad_* und rohen __pad_*-Ergebnissen, nicht die gemeinsamen BTN_*-Masken aus input.h.

Initialisiere die vier nes_pad1_*-Zustandsbytes vor der ersten Abfrage mit 0. Danach einmal pro Eingabetakt abfragen. pressed = current & ~previous und released = previous & ~current beschreiben die letzte Abfrage. Der Wiederholungszustand wird separat durch nes_pad_repeat_step() aktualisiert.

nes_pad_poll

Strobt $4016, liest die acht seriellen D0-Bits von Controller 1 und aktualisiert nes_pad1_prev, nes_pad1_cur, nes_pad1_pressed und nes_pad1_released. Es erfolgt nur ein Lesevorgang, ohne die Wiederholungsprüfung der sicheren Funktionen. Der abschließende Zugriff auf $4017 speichert keinen Zustand für Controller 2.

Syntax

c
void nes_pad_poll(void);

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Rohes NES-Format: A=0x01, B=0x02, SELECT=0x04, START=0x08, UP=0x10, DOWN=0x20, LEFT=0x40, RIGHT=0x80. Ein gesetztes Bit bedeutet gedrückt. Verwende diese Werte mit nes_pad_* und rohen __pad_*-Ergebnissen, nicht die gemeinsamen BTN_*-Masken aus input.h.

Initialisiere die vier nes_pad1_*-Zustandsbytes vor der ersten Abfrage mit 0. Danach einmal pro Eingabetakt abfragen. pressed = current & ~previous und released = previous & ~current beschreiben die letzte Abfrage. Der Wiederholungszustand wird separat durch nes_pad_repeat_step() aktualisiert.

Anwendungsbeispiel

c
nes_pad_poll(); // Read controller 1 and update its held/pressed/released snapshots.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Dieses Programm erklärt die Reihenfolge Einlesen → Wiederholung aktualisieren → Zustand abfragen und zeigt, dass die NES-Abfragen maskierte Bits statt des Wahrheitswerts 1 liefern. Verwenden Sie nes_pad_repeat_config(3, 1), halten Sie B für 40 Aktualisierungen gedrückt und lassen Sie los. FIRST HELD, FIRST TRIGGER und FIRST REPEAT sind 2; HELD TICKS ist 40, PULSE COUNT ist 19 und RELEASE BITS ist 2. Die erste Wiederholung folgt vier Aktualisierungen nach dem ersten Impuls; danach beträgt der Abstand zwei Aktualisierungen. FAILED CHECKS muss 0 sein. Eine andere Haltedauer verändert die Impulszahl.

nes_pad_poll: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-cache
Implementierung und Quelltext

kitaqfc/lib/pad.h:16

Deklarationshinweise im Original
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

c
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 — NES-Paletten

Verwaltet Hintergrund- und Spritefarben mit einem 32-Byte-CPU-Schattenpuffer und sofortigen oder eingereihten Übertragungen. PPU-Palettenadressen enthalten Aliase.

nes_palette_apply_now

Kopiert 32 Farben in den Schattenpuffer und überträgt sie anschließend direkt an die PPU.

Syntax

c
void nes_palette_apply_now(unsigned char* src32);

Parameter

src32

Lesbare 32-Byte-Palette: 16 Hintergrundfarben, gefolgt von 16 Spritefarben; verwenden Sie Farbcodes von 0–63.

Rückgabewert

Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.

Bedingungen und Grenzen

Der Schattenpuffer reserviert die CPU-Adressen 0x03C0–0x03DF. Die PPU-Adressen 0x3F10/14/18/1C sind Aliase von 0x3F00/04/08/0C. Die 32 rohen Schattenbytes müssen daher nicht mit 32 unabhängigen PPU-Lesewerten übereinstimmen. Verwenden Sie PPU-Inkrement eins in einem sicheren VBlank-Zeitfenster oder bei ausgeschalteter Darstellung. Die Hilfsfunktion wartet nicht, maskiert keine Interrupts und stellt das Scrolling nicht wieder her.

Anwendungsbeispiel

c
nes_palette_apply_now(colors);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Zeigen Sie rote, blaue und grüne 32×32-Hintergrundrechtecke bei (16,32), (80,32) und (144,32) sowie 8×8-Spritequadrate bei (16,96), (80,96) und (144,96) in derselben Farbreihenfolge. Getrennte Hintergrund- und Spritepaletten demonstrieren direkte und eingereihte Übertragungen.

nes_palette_apply_now: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/palette.h:11

Deklarationshinweise im Original
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

c
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

Überträgt die aktuellen 32 Farben des Schattenpuffers direkt an die PPU.

Syntax

c
void nes_palette_apply_shadow_now(void);

Rückgabewert

Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.

Bedingungen und Grenzen

Der Schattenpuffer reserviert die CPU-Adressen 0x03C0–0x03DF. Die PPU-Adressen 0x3F10/14/18/1C sind Aliase von 0x3F00/04/08/0C. Die 32 rohen Schattenbytes müssen daher nicht mit 32 unabhängigen PPU-Lesewerten übereinstimmen. Verwenden Sie PPU-Inkrement eins in einem sicheren VBlank-Zeitfenster oder bei ausgeschalteter Darstellung. Die Hilfsfunktion wartet nicht, maskiert keine Interrupts und stellt das Scrolling nicht wieder her.

Anwendungsbeispiel

c
nes_palette_apply_shadow_now();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Zeigen Sie rote, blaue und grüne 32×32-Hintergrundrechtecke bei (16,32), (80,32) und (144,32) sowie 8×8-Spritequadrate bei (16,96), (80,96) und (144,96) in derselben Farbreihenfolge. Getrennte Hintergrund- und Spritepaletten demonstrieren direkte und eingereihte Übertragungen.

nes_palette_apply_shadow_now: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/palette.h:13

Deklarationshinweise im Original
Upload the current palette shadow directly, with timing controlled by the caller.

kitaqfc/lib/palette.c:35

c
void nes_palette_apply_shadow_now(void)
{
    nes_ppu_stream_write(0x3F00, nes_palette_shadow, 32);
}
nes_palette_copy

Kopiert 32 Palettenbytes in den CPU-Schattenpuffer, ohne sie an die PPU zu übertragen.

Syntax

c
void nes_palette_copy(unsigned char* src32);

Parameter

src32

Lesbare 32-Byte-Palette: 16 Hintergrundfarben, gefolgt von 16 Spritefarben; verwenden Sie Farbcodes von 0–63.

Rückgabewert

Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.

Bedingungen und Grenzen

Der Schattenpuffer reserviert die CPU-Adressen 0x03C0–0x03DF. Die PPU-Adressen 0x3F10/14/18/1C sind Aliase von 0x3F00/04/08/0C. Die 32 rohen Schattenbytes müssen daher nicht mit 32 unabhängigen PPU-Lesewerten übereinstimmen.

Anwendungsbeispiel

c
nes_palette_copy(colors);result[0]=nes_palette_shadow[5];

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Zeigen Sie rote, blaue und grüne 32×32-Hintergrundrechtecke bei (16,32), (80,32) und (144,32) sowie 8×8-Spritequadrate bei (16,96), (80,96) und (144,96) in derselben Farbreihenfolge. Getrennte Hintergrund- und Spritepaletten demonstrieren direkte und eingereihte Übertragungen.

nes_palette_copy: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/palette.h:8

Deklarationshinweise im Original
Copy exactly 32 palette bytes to the fixed shadow buffer without writing the PPU.

kitaqfc/lib/palette.c:19

c
void nes_palette_copy(unsigned char* src32)
{
    __memcpy(nes_palette_shadow, src32, 32);
}
nes_palette_queue_all

Ersetzt alle 32 Schattenfarben und kopiert sie in die VRAM-Warteschlange der Laufzeitumgebung.

Syntax

c
unsigned char nes_palette_queue_all(unsigned char* src32);

Parameter

src32

Lesbare 32-Byte-Palette: 16 Hintergrundfarben, gefolgt von 16 Spritefarben; verwenden Sie Farbcodes von 0–63.

Rückgabewert

1 bei erfolgreicher Einreihung, 0 bei unzureichender Kapazität. Die neuen Schattenwerte bleiben auch bei einem Fehlschlag erhalten. Erfolg bedeutet nicht, dass die PPU bereits aktualisiert wurde.

Bedingungen und Grenzen

Der Schattenpuffer reserviert die CPU-Adressen 0x03C0–0x03DF. Die PPU-Adressen 0x3F10/14/18/1C sind Aliase von 0x3F00/04/08/0C. Die 32 rohen Schattenbytes müssen daher nicht mit 32 unabhängigen PPU-Lesewerten übereinstimmen. Die Warteschlange kopiert die Werte; nach erfolgreicher Aufnahme darf die Quelle geändert werden. Verhindern Sie konkurrierende Zugriffe zwischen dem Befüllen der Warteschlange und ihrem NMI-Verbraucher.

Anwendungsbeispiel

c
nes_vram_queue_clear();result[1]=nes_palette_queue_all(colors);result[2]=nes_vram_queue_used;nes_vram_queue_nmi_flush();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Zeigen Sie rote, blaue und grüne 32×32-Hintergrundrechtecke bei (16,32), (80,32) und (144,32) sowie 8×8-Spritequadrate bei (16,96), (80,96) und (144,96) in derselben Farbreihenfolge. Getrennte Hintergrund- und Spritepaletten demonstrieren direkte und eingereihte Übertragungen.

nes_palette_queue_all: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/palette.h:18

Deklarationshinweise im Original
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

c
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

Aktualisiert die vier Farben einer Hintergrundpalette im Schattenpuffer und kopiert sie in die VRAM-Warteschlange.

Syntax

c
unsigned char nes_palette_queue_bg4(unsigned char pal_index, unsigned char* src4);

Parameter

pal_index

Palettenindex 0–3; die Funktion prüft ihn nicht.

src4

Vier Bytes für die gewählte Palette; verwenden Sie Farbcodes von 0–63.

Rückgabewert

1 bei erfolgreicher Einreihung, 0 bei unzureichender Kapazität. Die neuen Schattenwerte bleiben auch bei einem Fehlschlag erhalten. Erfolg bedeutet nicht, dass die PPU bereits aktualisiert wurde.

Bedingungen und Grenzen

Der Schattenpuffer reserviert die CPU-Adressen 0x03C0–0x03DF. Die PPU-Adressen 0x3F10/14/18/1C sind Aliase von 0x3F00/04/08/0C. Die 32 rohen Schattenbytes müssen daher nicht mit 32 unabhängigen PPU-Lesewerten übereinstimmen. Die Warteschlange kopiert die Werte; nach erfolgreicher Aufnahme darf die Quelle geändert werden. Verhindern Sie konkurrierende Zugriffe zwischen dem Befüllen der Warteschlange und ihrem NMI-Verbraucher.

Anwendungsbeispiel

c
result[3]=nes_palette_queue_bg4(3,four);nes_vram_queue_nmi_flush();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Zeigen Sie rote, blaue und grüne 32×32-Hintergrundrechtecke bei (16,32), (80,32) und (144,32) sowie 8×8-Spritequadrate bei (16,96), (80,96) und (144,96) in derselben Farbreihenfolge. Getrennte Hintergrund- und Spritepaletten demonstrieren direkte und eingereihte Übertragungen.

nes_palette_queue_bg4: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/palette.h:21

Deklarationshinweise im Original
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

c
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

Aktualisiert die vier Farben einer Spritepalette im Schattenpuffer und kopiert sie in die VRAM-Warteschlange.

Syntax

c
unsigned char nes_palette_queue_sprite4(unsigned char pal_index, unsigned char* src4);

Parameter

pal_index

Palettenindex 0–3; die Funktion prüft ihn nicht.

src4

Vier Bytes für die gewählte Palette; verwenden Sie Farbcodes von 0–63.

Rückgabewert

1 bei erfolgreicher Einreihung, 0 bei unzureichender Kapazität. Die neuen Schattenwerte bleiben auch bei einem Fehlschlag erhalten. Erfolg bedeutet nicht, dass die PPU bereits aktualisiert wurde.

Bedingungen und Grenzen

Der Schattenpuffer reserviert die CPU-Adressen 0x03C0–0x03DF. Die PPU-Adressen 0x3F10/14/18/1C sind Aliase von 0x3F00/04/08/0C. Die 32 rohen Schattenbytes müssen daher nicht mit 32 unabhängigen PPU-Lesewerten übereinstimmen. Die Warteschlange kopiert die Werte; nach erfolgreicher Aufnahme darf die Quelle geändert werden. Verhindern Sie konkurrierende Zugriffe zwischen dem Befüllen der Warteschlange und ihrem NMI-Verbraucher.

Anwendungsbeispiel

c
result[4]=nes_palette_queue_sprite4(2,four);nes_vram_queue_nmi_flush();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Zeigen Sie rote, blaue und grüne 32×32-Hintergrundrechtecke bei (16,32), (80,32) und (144,32) sowie 8×8-Spritequadrate bei (16,96), (80,96) und (144,96) in derselben Farbreihenfolge. Getrennte Hintergrund- und Spritepaletten demonstrieren direkte und eingereihte Übertragungen.

nes_palette_queue_sprite4: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/palette.h:24

Deklarationshinweise im Original
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

c
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);
}

Eigene Bewegung mit Q5.3-Datentypen

Neben den world/body-Funktionen definiert physics2d.h Typen und Konstanten für eigene Bewegungen mit Nachkommaanteil. Dieses Beispiel implementiert game_step mit der Q5.3-Datenkonvention. Das ist ein anderer Ansatz als die world/body-Integration.

KQ2DPosition speichert die ganzzahlige Pixelposition (0..255), KQ2DFraction den Rest (0..7), KQ2DSpeed den Bewegungsbetrag pro Tick in Achtelpixeln (0..255) und KQ2DDirection die Richtung. Alle vier Typen sind u8. Die Richtung wird getrennt von der Geschwindigkeit gespeichert, nicht als Vorzeichen.

Verwenden Sie KQ2D_SUBPIXEL_BITS=3, ONE=8 und MASK=7, um position*8+fraction in einem 16-Bit-Zwischenwert zusammenzufassen. Richtung NONE=0 bedeutet Stillstand, NEGATIVE=1 Subtraktion und POSITIVE=2 Addition. Das Spiel muss die Grenzen so behandeln, dass die Subtraktion nicht negativ wird und die resultierende Ganzzahlposition im Bereich 0..255 bleibt.

KQ2D_DRAG_BRAKE=1, STUN=2, COAST=3 und THRUST=4 kennzeichnen vom Spiel definierte Verhaltensweisen für Bremsen, Betäubung, Ausrollen und Schub. Die reine Zuweisung eines Wertes wendet keine Beschleunigung oder Reibung an. Definieren Sie jeden Effekt und seine Dauer in Ihrer Aktualisierungsroutine.

Beispiel: Halbpixelbewegungen aufsummieren

Das obere rote 16×16-Pixel-Quadrat beginnt bei X=24; das untere zeigt X=32 nach 16 Ticks. Geschwindigkeit 4 bedeutet 4/8=0.5 Pixel pro Tick, also acht Pixel in 16 Ticks. Unterschiedliche Y-Positionen trennen die beiden Zustände zum Vergleich. Eine anschließende numerische Prüfung geht acht Ticks zurück und erhält X=28 mit Nachkommaanteil 0.

c
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.
Das obere rote 16×16-Pixel-Quadrat beginnt bei X=24; das untere zeigt X=32 nach 16 Ticks. Geschwindigkeit 4 bedeutet 4/8=0.5 Pixel pro Tick, also acht Pixel in 16 Ticks. Unterschiedliche Y-Positionen trennen die beiden Zustände zum Vergleich. Eine anschließende numerische Prüfung geht acht Ticks zurück und erhält X=28 mit Nachkommaanteil 0.
In KUROSAKI geprüft: Anfangsposition und Position nach 16 aufsummierten Halbpixelschritten.

Vollständiges Beispielprogramm

Build

powershell
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-disasm

physics2d

Bietet Boxintegration, AABB-Kontakte und einen optionalen Löser für Oberflächenreaktionen. Körper werden durch Mittelpunkt und halbe Ausdehnungen beschrieben; active=0 schließt einen Arrayplatz aus, inv_mass_q8<=0 macht ihn statisch. KQRect verwendet dagegen linke obere Ecke und Breite/Höhe. Kontakte zwischen Boxen nutzen das restitution-Feld des Körpers nicht; Oberflächenreaktionen verwenden KQSurface2D-Koeffizienten.

Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.

Eine Welt nutzt ein vom aufrufenden Code bereitgestelltes Array. Dieser reserviert und besitzt den Speicher für die Körper und hält ihn gültig. Das Initialisieren der Welt initialisiert nicht die Arrayelemente.

Binden Sie nicht nur Header ein, sondern kompilieren Sie auch die Implementierungsdateien. Für 2D benötigen Sie fixed.c und physics2d.c, für 3D zusätzlich physics3d.c. Die Beispiele nutzen MMC3, CHR-RAM und Zeichenspeicher im PRG-RAM bei $6800–$6FFF. Dieser Zeichenpuffer ist keine Voraussetzung der Physikbibliothek selbst.

kq2d_world_init

Verknüpft ein Array mit einer 2D-Welt und setzt die Schwerkraft auf (0,32), die Kontaktiterationen auf vier und die Geschwindigkeitsgrenze pro Achse auf 512.

Syntax

c
void kq2d_world_init(KQWorld2D* world, KQBody2D* bodies, u8 body_count);

Parameter

world

Zeiger auf die Welt mit dem Körperarray und den Simulationseinstellungen.

bodies

Anfang eines vom aufrufenden Code gehaltenen Körperarrays mit body_count Elementen.

body_count

Anzahl der Arrayplätze von 0 bis 255, einschließlich inaktiver Einträge.

Rückgabewert

Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.

Bedingungen und Grenzen

Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.

Eine Welt nutzt ein vom aufrufenden Code bereitgestelltes Array. Dieser reserviert und besitzt den Speicher für die Körper und hält ihn gültig. Das Initialisieren der Welt initialisiert nicht die Arrayelemente.

Binden Sie nicht nur Header ein, sondern kompilieren Sie auch die Implementierungsdateien. Für 2D benötigen Sie fixed.c und physics2d.c, für 3D zusätzlich physics3d.c. Die Beispiele nutzen MMC3, CHR-RAM und Zeichenspeicher im PRG-RAM bei $6800–$6FFF. Dieser Zeichenpuffer ist keine Voraussetzung der Physikbibliothek selbst.

Anwendungsbeispiel

c
kq2d_world_init(&world,bodies,2);
    result[0]=world.gravity_y; result[1]=world.solver_iterations; result[2]=world.max_speed;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.

kq2d_world_init: NTSC — Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.
NTSC — Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/physics2d.h:36

Deklarationshinweise im Original
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

c
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

Integriert aktive dynamische Körper und löst anschließend Kontakte zwischen aktiven Arrayeinträgen auf.

Syntax

c
void kq2d_step(KQWorld2D* world);

Parameter

world

Zeiger auf die Welt mit dem Körperarray und den Simulationseinstellungen.

Rückgabewert

Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.

Bedingungen und Grenzen

Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.

Eine Welt nutzt ein vom aufrufenden Code bereitgestelltes Array. Dieser reserviert und besitzt den Speicher für die Körper und hält ihn gültig. Das Initialisieren der Welt initialisiert nicht die Arrayelemente.

Summen, Differenzen, addierte halbe Ausdehnungen und Produkte zur Kontaktkorrektur müssen im vorzeichenbehafteten 16-Bit-Bereich bleiben. Geschwindigkeitsgrenzen greifen erst nach der Addition und verhindern keinen Überlauf innerhalb dieser Addition.

Kontakte werden entlang der Achse mit der geringsten Eindringtiefe aufgelöst; bei Gleichstand wird Y gewählt. Die Positionskorrektur nutzt inverse Massen, zwei dynamische Körper erhalten auf dieser Achse jedoch den einfachen Mittelwert ihrer Geschwindigkeiten. Bei einer Kollision mit einem statischen Körper wird die Komponente null. Der Löser nutzt restitution_q8 nicht. Die diskrete Kollisionserkennung kann schnelle Durchquerungen übersehen.

Integration und Kollisionserkennung für Boxen verwenden gemeinsamen Arbeitsspeicher. Rufen Sie diese Physikroutinen nicht während ihrer Ausführung erneut aus einem Interrupt auf.

Eine NULL-Welt oder ein NULL-Array wird ignoriert. Auch bei solver_iterations gleich null wird ein Kontaktdurchlauf ausgeführt.

Binden Sie nicht nur Header ein, sondern kompilieren Sie auch die Implementierungsdateien. Für 2D benötigen Sie fixed.c und physics2d.c, für 3D zusätzlich physics3d.c. Die Beispiele nutzen MMC3, CHR-RAM und Zeichenspeicher im PRG-RAM bei $6800–$6FFF. Dieser Zeichenpuffer ist keine Voraussetzung der Physikbibliothek selbst.

Anwendungsbeispiel

c
kq2d_step(&world);
    result[22]=bodies[0].x; result[23]=bodies[0].y;
    result[24]=bodies[0].vx; result[25]=bodies[0].vy;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.

kq2d_step: NTSC — Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.
NTSC — Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/physics2d.h:41

Deklarationshinweise im Original
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

c
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

Wendet Weltschwerkraft und Geschwindigkeitsgrenzen pro Achse auf einen dynamischen Körper an und addiert anschließend die Geschwindigkeit zur Position.

Syntax

c
void kq2d_integrate_body(KQWorld2D* world, KQBody2D* body);

Parameter

world

Zeiger auf die Welt mit dem Körperarray und den Simulationseinstellungen.

body

Zeiger auf den zu ändernden Körper. Von dieser Operation nicht verwendete Felder bleiben erhalten.

Rückgabewert

Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.

Bedingungen und Grenzen

Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.

Summen, Differenzen, addierte halbe Ausdehnungen und Produkte zur Kontaktkorrektur müssen im vorzeichenbehafteten 16-Bit-Bereich bleiben. Geschwindigkeitsgrenzen greifen erst nach der Addition und verhindern keinen Überlauf innerhalb dieser Addition.

Integration und Kollisionserkennung für Boxen verwenden gemeinsamen Arbeitsspeicher. Rufen Sie diese Physikroutinen nicht während ihrer Ausführung erneut aus einem Interrupt auf.

Ignoriert NULL, inaktive Körper und Körper mit inverser Masse kleiner oder gleich null. Geben Sie eine nichtnegative Geschwindigkeitsgrenze an.

Dieser Aufruf löst keine Kontakte mit anderen Körpern auf. Auch eine NULL-Welt wird ignoriert.

Binden Sie nicht nur Header ein, sondern kompilieren Sie auch die Implementierungsdateien. Für 2D benötigen Sie fixed.c und physics2d.c, für 3D zusätzlich physics3d.c. Die Beispiele nutzen MMC3, CHR-RAM und Zeichenspeicher im PRG-RAM bei $6800–$6FFF. Dieser Zeichenpuffer ist keine Voraussetzung der Physikbibliothek selbst.

Anwendungsbeispiel

c
kq2d_integrate_body(&world,&temp);
    result[18]=temp.x; result[19]=temp.y;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.

kq2d_integrate_body: NTSC — Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.
NTSC — Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/physics2d.h:45

Deklarationshinweise im Original
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

c
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

Prüft zwei über ihren Mittelpunkt definierte Boxen auf echte Überlappung entlang X und Y.

Syntax

c
u8 kq2d_overlap_aabb(const KQBody2D* a, const KQBody2D* b);

Parameter

a

Gültiger Körperzeiger. Die Abfrage ignoriert Aktivität, Masse und Flags.

b

Gültiger Körperzeiger. Die Abfrage ignoriert Aktivität, Masse und Flags.

Rückgabewert

Liefert 1 bei Überlappung der Innenbereiche und 0 bei bloßer Berührung oder getrennten Formen.

Bedingungen und Grenzen

Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.

Summen, Differenzen, addierte halbe Ausdehnungen und Produkte zur Kontaktkorrektur müssen im vorzeichenbehafteten 16-Bit-Bereich bleiben. Geschwindigkeitsgrenzen greifen erst nach der Addition und verhindern keinen Überlauf innerhalb dieser Addition.

Binden Sie nicht nur Header ein, sondern kompilieren Sie auch die Implementierungsdateien. Für 2D benötigen Sie fixed.c und physics2d.c, für 3D zusätzlich physics3d.c. Die Beispiele nutzen MMC3, CHR-RAM und Zeichenspeicher im PRG-RAM bei $6800–$6FFF. Dieser Zeichenpuffer ist keine Voraussetzung der Physikbibliothek selbst.

Anwendungsbeispiel

c
result[20]=kq2d_overlap_aabb(&bodies[0],&bodies[1]);
    bodies[1].x=40; result[21]=kq2d_overlap_aabb(&bodies[0],&bodies[1]);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.

kq2d_overlap_aabb: NTSC — Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.
NTSC — Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/physics2d.h:49

Deklarationshinweise im Original
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

c
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

Initialisiert eine über ihren Mittelpunkt definierte Box mit den angegebenen halben Ausdehnungen, Geschwindigkeit null, inverser Masse 256 und aktivem Zustand.

Syntax

c
void kq2d_body_init(KQBody2D* body, s16 x, s16 y, s16 half_x, s16 half_y);

Parameter

body

Zeiger auf den zu ändernden Körper. Von dieser Operation nicht verwendete Felder bleiben erhalten.

x

X-Koordinate des Mittelpunkts oder Punkts, im Beispiel in Pixeln.

y

Y-Koordinate des Mittelpunkts oder Punkts; im Beispiel zeigen positive Werte nach unten.

half_x

Halbe Ausdehnung entlang X; die gesamte Boxbreite ist doppelt so groß.

half_y

Halbe Ausdehnung entlang Y; die gesamte Boxhöhe ist doppelt so groß.

Rückgabewert

Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.

Bedingungen und Grenzen

Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.

Setzt restitution_q8 auf null. Ein NULL-Körper wird ignoriert. Geben Sie positive halbe Ausdehnungen an.

Binden Sie nicht nur Header ein, sondern kompilieren Sie auch die Implementierungsdateien. Für 2D benötigen Sie fixed.c und physics2d.c, für 3D zusätzlich physics3d.c. Die Beispiele nutzen MMC3, CHR-RAM und Zeichenspeicher im PRG-RAM bei $6800–$6FFF. Dieser Zeichenpuffer ist keine Voraussetzung der Physikbibliothek selbst.

Anwendungsbeispiel

c
kq2d_body_init(&temp,10,20,8,8);
    result[3]=temp.inv_mass_q8; result[4]=temp.active;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.

kq2d_body_init: NTSC — Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.
NTSC — Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/physics2d.h:52

Deklarationshinweise im Original
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

c
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

Ersetzt nur den Körpermittelpunkt; Geschwindigkeit, Ausdehnungen und Aktivitätszustand bleiben erhalten.

Syntax

c
void kq2d_body_set_pos(KQBody2D* body, s16 x, s16 y);

Parameter

body

Zeiger auf den zu ändernden Körper. Von dieser Operation nicht verwendete Felder bleiben erhalten.

x

X-Koordinate des Mittelpunkts oder Punkts, im Beispiel in Pixeln.

y

Y-Koordinate des Mittelpunkts oder Punkts; im Beispiel zeigen positive Werte nach unten.

Rückgabewert

Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.

Bedingungen und Grenzen

Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.

NULL wird ignoriert. Bei gültigem Zeiger werden auch inaktive und statische Körper geändert.

Binden Sie nicht nur Header ein, sondern kompilieren Sie auch die Implementierungsdateien. Für 2D benötigen Sie fixed.c und physics2d.c, für 3D zusätzlich physics3d.c. Die Beispiele nutzen MMC3, CHR-RAM und Zeichenspeicher im PRG-RAM bei $6800–$6FFF. Dieser Zeichenpuffer ist keine Voraussetzung der Physikbibliothek selbst.

Anwendungsbeispiel

c
kq2d_body_set_pos(&temp,-12,20);
    result[5]=temp.x; result[6]=temp.y;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.

kq2d_body_set_pos: NTSC — Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.
NTSC — Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/physics2d.h:54

Deklarationshinweise im Original
Replace the center without altering velocity, extents or activity. Null is ignored.

kitaqfc/lib/physics2d.c:399

c
void kq2d_body_set_pos(KQBody2D* body, s16 x, s16 y)
{
    if (body == 0) return;
    body->x = x;
    body->y = y;
}
kq2d_body_set_velocity

Setzt die Geschwindigkeit direkt, ohne sie zu begrenzen oder die Position zu ändern.

Syntax

c
void kq2d_body_set_velocity(KQBody2D* body, s16 vx, s16 vy);

Parameter

body

Zeiger auf den zu ändernden Körper. Von dieser Operation nicht verwendete Felder bleiben erhalten.

vx

X-Verschiebung pro Simulationstakt, in derselben Einheit wie die Position.

vy

Y-Verschiebung pro Simulationstakt, in derselben Einheit wie die Position.

Rückgabewert

Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.

Bedingungen und Grenzen

Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.

NULL wird ignoriert. Bei gültigem Zeiger werden auch inaktive und statische Körper geändert.

Binden Sie nicht nur Header ein, sondern kompilieren Sie auch die Implementierungsdateien. Für 2D benötigen Sie fixed.c und physics2d.c, für 3D zusätzlich physics3d.c. Die Beispiele nutzen MMC3, CHR-RAM und Zeichenspeicher im PRG-RAM bei $6800–$6FFF. Dieser Zeichenpuffer ist keine Voraussetzung der Physikbibliothek selbst.

Anwendungsbeispiel

c
kq2d_body_set_velocity(&temp,40,-30);
    result[7]=temp.vx; result[8]=temp.vy;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.

kq2d_body_set_velocity: NTSC — Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.
NTSC — Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/physics2d.h:56

Deklarationshinweise im Original
Replace velocity without clamping or checking activity/mass. Null is ignored.

kitaqfc/lib/physics2d.c:407

c
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

Addiert die Schwerkraft zu einem aktiven dynamischen Körper und begrenzt jede Achse auf +/-max_speed, ohne die Position zu ändern.

Syntax

c
void kq2d_body_apply_gravity(KQBody2D* body, s16 gravity_x, s16 gravity_y, s16 max_speed);

Parameter

body

Zeiger auf den zu ändernden Körper. Von dieser Operation nicht verwendete Felder bleiben erhalten.

gravity_x

Beschleunigung, die dieser Aufruf zur X-Geschwindigkeit addiert.

gravity_y

Beschleunigung, die dieser Aufruf zur Y-Geschwindigkeit addiert.

max_speed

Geschwindigkeitsgrenze. Der jeweilige Eintrag erläutert, ob sie für jede Achse einzeln oder den gesamten Vektor gilt.

Rückgabewert

Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.

Bedingungen und Grenzen

Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.

Summen, Differenzen, addierte halbe Ausdehnungen und Produkte zur Kontaktkorrektur müssen im vorzeichenbehafteten 16-Bit-Bereich bleiben. Geschwindigkeitsgrenzen greifen erst nach der Addition und verhindern keinen Überlauf innerhalb dieser Addition.

Integration und Kollisionserkennung für Boxen verwenden gemeinsamen Arbeitsspeicher. Rufen Sie diese Physikroutinen nicht während ihrer Ausführung erneut aus einem Interrupt auf.

Ignoriert NULL, inaktive Körper und Körper mit inverser Masse kleiner oder gleich null. Geben Sie eine nichtnegative Geschwindigkeitsgrenze an.

Binden Sie nicht nur Header ein, sondern kompilieren Sie auch die Implementierungsdateien. Für 2D benötigen Sie fixed.c und physics2d.c, für 3D zusätzlich physics3d.c. Die Beispiele nutzen MMC3, CHR-RAM und Zeichenspeicher im PRG-RAM bei $6800–$6FFF. Dieser Zeichenpuffer ist keine Voraussetzung der Physikbibliothek selbst.

Anwendungsbeispiel

c
kq2d_body_apply_gravity(&temp,5,-10,32);
    result[9]=temp.vx; result[10]=temp.vy;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.

kq2d_body_apply_gravity: NTSC — Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.
NTSC — Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/physics2d.h:60

Deklarationshinweise im Original
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

c
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

Skaliert beide Geschwindigkeitskomponenten mit einem vorzeichenbehafteten Bytekoeffizienten geteilt durch 256, ohne Position oder Aktivität zu prüfen.

Syntax

c
void kq2d_body_apply_friction(KQBody2D* body, u8 friction_q8);

Parameter

body

Zeiger auf den zu ändernden Körper. Von dieser Operation nicht verwendete Felder bleiben erhalten.

friction_q8

Von dieser Funktion verwendeter Geschwindigkeitsfaktor. Er wird in s8 umgewandelt; dadurch werden 128..255 zu negativen Koeffizienten.

Rückgabewert

Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.

Bedingungen und Grenzen

Werte von 0 bis 127 ergeben Faktoren von 0 bis 127/256. Werte von 128 bis 255 werden durch die s8-Umwandlung negativ und kehren die Geschwindigkeit um. Für nichtnegative Dämpfung über den gesamten Bereich 0..255 verwenden Sie kq2d_scale_q8 für jede Komponente. Produkte werden gegen null abgeschnitten. NULL wird ignoriert.

Binden Sie nicht nur Header ein, sondern kompilieren Sie auch die Implementierungsdateien. Für 2D benötigen Sie fixed.c und physics2d.c, für 3D zusätzlich physics3d.c. Die Beispiele nutzen MMC3, CHR-RAM und Zeichenspeicher im PRG-RAM bei $6800–$6FFF. Dieser Zeichenpuffer ist keine Voraussetzung der Physikbibliothek selbst.

Anwendungsbeispiel

c
kq2d_body_apply_friction(&temp,64);
    result[11]=temp.vx; result[12]=temp.vy;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.

kq2d_body_apply_friction: NTSC — Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.
NTSC — Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/physics2d.h:64

Deklarationshinweise im Original
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

c
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

Prüft die Innenbereiche zweier Rechtecke auf Überlappung. Die Rechtecke werden durch linke obere Ecke und Größe angegeben.

Syntax

c
u8 kq2d_rect_intersect(KQRect a, KQRect b);

Parameter

a

KQRect-Wert mit den Koordinaten der linken oberen Ecke sowie positiver Breite und Höhe.

b

KQRect-Wert mit den Koordinaten der linken oberen Ecke sowie positiver Breite und Höhe.

Rückgabewert

Liefert 1 bei Überlappung der Innenbereiche und 0 bei bloßer Berührung oder getrennten Formen.

Bedingungen und Grenzen

Summen, Differenzen, addierte halbe Ausdehnungen und Produkte zur Kontaktkorrektur müssen im vorzeichenbehafteten 16-Bit-Bereich bleiben. Geschwindigkeitsgrenzen greifen erst nach der Addition und verhindern keinen Überlauf innerhalb dieser Addition.

Abmessungen kleiner oder gleich null werden nicht ausdrücklich abgelehnt. Kopieren Sie Mittelpunkt und halbe Ausdehnungen eines Körpers nicht direkt in ein KQRect.

Binden Sie nicht nur Header ein, sondern kompilieren Sie auch die Implementierungsdateien. Für 2D benötigen Sie fixed.c und physics2d.c, für 3D zusätzlich physics3d.c. Die Beispiele nutzen MMC3, CHR-RAM und Zeichenspeicher im PRG-RAM bei $6800–$6FFF. Dieser Zeichenpuffer ist keine Voraussetzung der Physikbibliothek selbst.

Anwendungsbeispiel

c
result[14]=kq2d_rect_intersect(r1,r2);
    r2.x=16; result[15]=kq2d_rect_intersect(r1,r2);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.

kq2d_rect_intersect: NTSC — Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.
NTSC — Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/physics2d.h:67

Deklarationshinweise im Original
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

c
u8 kq2d_rect_intersect(KQRect a, KQRect b)
{
    return kq_rect_intersect(a, b);
}
kq2d_point_in_rect

Prüft, ob ein Punkt im Rechteck liegt. Linker und oberer Rand zählen dazu, rechter und unterer Rand nicht.

Syntax

c
u8 kq2d_point_in_rect(s16 x, s16 y, KQRect r);

Parameter

x

X-Koordinate des Mittelpunkts oder Punkts, im Beispiel in Pixeln.

y

Y-Koordinate des Mittelpunkts oder Punkts; im Beispiel zeigen positive Werte nach unten.

r

KQRect-Wert mit der Position x/y der linken oberen Ecke und Breite/Höhe w/h.

Rückgabewert

Gibt innen 1 und außen 0 zurück.

Bedingungen und Grenzen

Summen, Differenzen, addierte halbe Ausdehnungen und Produkte zur Kontaktkorrektur müssen im vorzeichenbehafteten 16-Bit-Bereich bleiben. Geschwindigkeitsgrenzen greifen erst nach der Addition und verhindern keinen Überlauf innerhalb dieser Addition.

Binden Sie nicht nur Header ein, sondern kompilieren Sie auch die Implementierungsdateien. Für 2D benötigen Sie fixed.c und physics2d.c, für 3D zusätzlich physics3d.c. Die Beispiele nutzen MMC3, CHR-RAM und Zeichenspeicher im PRG-RAM bei $6800–$6FFF. Dieser Zeichenpuffer ist keine Voraussetzung der Physikbibliothek selbst.

Anwendungsbeispiel

c
result[16]=kq2d_point_in_rect(0,0,r1);
    result[17]=kq2d_point_in_rect(16,0,r1);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.

kq2d_point_in_rect: NTSC — Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.
NTSC — Links ist der Anfangszustand zu sehen, rechts der Zustand einen Tick später. Ein rotes 16×16-Quadrat mit Mittelpunkt (24,24) und Geschwindigkeit (4,16) erreicht (28,36); auf dem blauen Boden ist seine Y-Geschwindigkeit null. Die Panelursprünge liegen bei den Bildschirmkoordinaten (8,48) und (88,48). RAM-Prüfungen decken auch Initialisierung, Setzfunktionen, Integration, Rechteck- und Punktabfragen sowie vorzeichenbehaftete Skalierung ab.

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/physics2d.h:70

Deklarationshinweise im Original
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

c
u8 kq2d_point_in_rect(s16 x, s16 y, KQRect r)
{
    return kq_point_in_rect(x, y, r);
}
kq2d_scale_q8

Multipliziert mit einem vorzeichenbehafteten Koeffizienten geteilt durch 256 und schneidet bei beiden Vorzeichen gegen null ab.

Syntax

c
s16 kq2d_scale_q8(s16 value, s16 coefficient);

Parameter

value

Vorzeichenbehafteter 16-Bit-Wert, auf den der Skalierungsfaktor angewendet wird.

coefficient

Vorzeichenbehafteter Koeffizient von -256 bis 256; 256 steht für 1,0.

Rückgabewert

Liefert das gegen null abgeschnittene Ergebnis als vorzeichenbehafteten 16-Bit-Wert.

Bedingungen und Grenzen

Verwenden Sie nur Koeffizienten in -256..256; +/-256 entspricht +/-1. Für value=-32768 und coefficient=-256 lautet das mathematische Ergebnis 32768 und passt nicht in s16.

Binden Sie nicht nur Header ein, sondern kompilieren Sie auch die Implementierungsdateien. Für 2D benötigen Sie fixed.c und physics2d.c, für 3D zusätzlich physics3d.c. Die Beispiele nutzen MMC3, CHR-RAM und Zeichenspeicher im PRG-RAM bei $6800–$6FFF. Dieser Zeichenpuffer ist keine Voraussetzung der Physikbibliothek selbst.

Anwendungsbeispiel

c
result[0]=kq2d_scale_q8(-257,128);
    result[1]=kq2d_scale_q8(300,-256);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Der rote Körper bleibt an seinem Platz. Seine grüne Geschwindigkeitslinie wechselt von (8,16) links zu (2,−8) rechts und zeigt Rückprall und tangentiale Reibung an der blauen Fläche. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48), der Körpermittelpunkt lokal bei (24,40). Die Auftreffgeschwindigkeit beträgt 16; das Beispiel zur Überquerungszeit gibt 192/256 zurück. Ein separater Aufruf zur Geschwindigkeitsbegrenzung reduziert (300,400) auf (147,196).

kq2d_scale_q8: NTSC — Der rote Körper bleibt an seinem Platz. Seine grüne Geschwindigkeitslinie wechselt von (8,16) links zu (2,−8) rechts und zeigt Rückprall und tangentiale Reibung an der blauen Fläche. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48), der Körpermittelpunkt lokal bei (24,40). Die Auftreffgeschwindigkeit beträgt 16; das Beispiel zur Überquerungszeit gibt 192/256 zurück. Ein separater Aufruf zur Geschwindigkeitsbegrenzung reduziert (300,400) auf (147,196).
NTSC — Der rote Körper bleibt an seinem Platz. Seine grüne Geschwindigkeitslinie wechselt von (8,16) links zu (2,−8) rechts und zeigt Rückprall und tangentiale Reibung an der blauen Fläche. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48), der Körpermittelpunkt lokal bei (24,40). Die Auftreffgeschwindigkeit beträgt 16; das Beispiel zur Überquerungszeit gibt 192/256 zurück. Ein separater Aufruf zur Geschwindigkeitsbegrenzung reduziert (300,400) auf (147,196).

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/physics2d.h:86

Deklarationshinweise im Original
Truncates toward zero, including negative values; coefficient is -256..256.

kitaqfc/lib/physics2d.c:8

c
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

Schätzt die Vektorlänge konservativ und skaliert beide Achsen gemeinsam, um die Gesamtgeschwindigkeit zu begrenzen.

Syntax

c
void kq2d_body_limit_speed(KQBody2D* body, s16 max_speed);

Parameter

body

Zeiger auf den zu ändernden Körper. Von dieser Operation nicht verwendete Felder bleiben erhalten.

max_speed

Geschwindigkeitsgrenze. Der jeweilige Eintrag erläutert, ob sie für jede Achse einzeln oder den gesamten Vektor gilt.

Rückgabewert

Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.

Bedingungen und Grenzen

Die Beträge der Geschwindigkeitskomponenten und ein positiver max_speed dürfen höchstens 16383 betragen. Eine Grenze kleiner oder gleich null setzt die Geschwindigkeit auf null. NULL wird ignoriert, Aktivität und Masse verhindern die Änderung jedoch nicht. Ganzzahlige Quantisierung kann das Ergebnis unter die Grenze drücken; sehr kleine Faktoren können null ergeben.

Binden Sie nicht nur Header ein, sondern kompilieren Sie auch die Implementierungsdateien. Für 2D benötigen Sie fixed.c und physics2d.c, für 3D zusätzlich physics3d.c. Die Beispiele nutzen MMC3, CHR-RAM und Zeichenspeicher im PRG-RAM bei $6800–$6FFF. Dieser Zeichenpuffer ist keine Voraussetzung der Physikbibliothek selbst.

Anwendungsbeispiel

c
kq2d_body_limit_speed(&body,250);
    result[2]=body.vx; result[3]=body.vy;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Der rote Körper bleibt an seinem Platz. Seine grüne Geschwindigkeitslinie wechselt von (8,16) links zu (2,−8) rechts und zeigt Rückprall und tangentiale Reibung an der blauen Fläche. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48), der Körpermittelpunkt lokal bei (24,40). Die Auftreffgeschwindigkeit beträgt 16; das Beispiel zur Überquerungszeit gibt 192/256 zurück. Ein separater Aufruf zur Geschwindigkeitsbegrenzung reduziert (300,400) auf (147,196).

kq2d_body_limit_speed: NTSC — Der rote Körper bleibt an seinem Platz. Seine grüne Geschwindigkeitslinie wechselt von (8,16) links zu (2,−8) rechts und zeigt Rückprall und tangentiale Reibung an der blauen Fläche. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48), der Körpermittelpunkt lokal bei (24,40). Die Auftreffgeschwindigkeit beträgt 16; das Beispiel zur Überquerungszeit gibt 192/256 zurück. Ein separater Aufruf zur Geschwindigkeitsbegrenzung reduziert (300,400) auf (147,196).
NTSC — Der rote Körper bleibt an seinem Platz. Seine grüne Geschwindigkeitslinie wechselt von (8,16) links zu (2,−8) rechts und zeigt Rückprall und tangentiale Reibung an der blauen Fläche. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48), der Körpermittelpunkt lokal bei (24,40). Die Auftreffgeschwindigkeit beträgt 16; das Beispiel zur Überquerungszeit gibt 192/256 zurück. Ein separater Aufruf zur Geschwindigkeitsbegrenzung reduziert (300,400) auf (147,196).

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/physics2d.h:90

Deklarationshinweise im Original
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

c
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

Nutzt die Geschwindigkeit relativ zu einer bewegten Oberfläche, um normalen Rückprall, eine minimale Rückprallgeschwindigkeit und tangentiale Reibung anzuwenden.

Syntax

c
s16 kq2d_body_resolve_surface(KQBody2D* body, const KQSurface2D* surface);

Parameter

body

Zeiger auf den zu ändernden Körper. Von dieser Operation nicht verwendete Felder bleiben erhalten.

surface

Zeiger auf eine KQSurface2D mit Normale, Geschwindigkeit sowie Rückprall- und Reibungseinstellungen.

Rückgabewert

Liefert die positive Annäherungsgeschwindigkeit entlang der Normalen oder 0 bei NULL-Eingaben oder einer Trennbewegung.

Bedingungen und Grenzen

Verwenden Sie eine Q8-Einheitsnormale mit Länge 256. Relative Komponenten müssen in +/-8191 liegen, threshold/kick nichtnegativ und Koeffizienten in 0..255 sein. Rückprall wird nur bei striktem Überschreiten des Schwellwerts angewendet; kick gibt die minimale Rückprallgeschwindigkeit vor. Bei NULL-Eingaben oder einer Trennbewegung bleibt die Geschwindigkeit unverändert. Kontakterkennung und Eindringkorrektur erfolgen separat; Aktivität und Masse werden nicht geprüft.

Binden Sie nicht nur Header ein, sondern kompilieren Sie auch die Implementierungsdateien. Für 2D benötigen Sie fixed.c und physics2d.c, für 3D zusätzlich physics3d.c. Die Beispiele nutzen MMC3, CHR-RAM und Zeichenspeicher im PRG-RAM bei $6800–$6FFF. Dieser Zeichenpuffer ist keine Voraussetzung der Physikbibliothek selbst.

Anwendungsbeispiel

c
result[6]=kq2d_body_resolve_surface(&body,&surface);
    result[7]=body.vx; result[8]=body.vy; result[9]=body.y;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Der rote Körper bleibt an seinem Platz. Seine grüne Geschwindigkeitslinie wechselt von (8,16) links zu (2,−8) rechts und zeigt Rückprall und tangentiale Reibung an der blauen Fläche. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48), der Körpermittelpunkt lokal bei (24,40). Die Auftreffgeschwindigkeit beträgt 16; das Beispiel zur Überquerungszeit gibt 192/256 zurück. Ein separater Aufruf zur Geschwindigkeitsbegrenzung reduziert (300,400) auf (147,196).

kq2d_body_resolve_surface: NTSC — Der rote Körper bleibt an seinem Platz. Seine grüne Geschwindigkeitslinie wechselt von (8,16) links zu (2,−8) rechts und zeigt Rückprall und tangentiale Reibung an der blauen Fläche. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48), der Körpermittelpunkt lokal bei (24,40). Die Auftreffgeschwindigkeit beträgt 16; das Beispiel zur Überquerungszeit gibt 192/256 zurück. Ein separater Aufruf zur Geschwindigkeitsbegrenzung reduziert (300,400) auf (147,196).
NTSC — Der rote Körper bleibt an seinem Platz. Seine grüne Geschwindigkeitslinie wechselt von (8,16) links zu (2,−8) rechts und zeigt Rückprall und tangentiale Reibung an der blauen Fläche. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48), der Körpermittelpunkt lokal bei (24,40). Die Auftreffgeschwindigkeit beträgt 16; das Beispiel zur Überquerungszeit gibt 192/256 zurück. Ein separater Aufruf zur Geschwindigkeitsbegrenzung reduziert (300,400) auf (147,196).

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/physics2d.h:93

Deklarationshinweise im Original
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

c
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

Schätzt bei linearer Bewegung den Übertrittszeitpunkt innerhalb des Takts anhand der vorzeichenbehafteten Start- und Endabstände.

Syntax

c
u16 kq2d_surface_toi_q8(s16 start_gap, s16 end_gap);

Parameter

start_gap

Vorzeichenbehafteter Abstand zu Beginn des Takts; positiv bedeutet außerhalb der Oberfläche.

end_gap

Vorzeichenbehafteter Abstand am Ende des Takts; negativ bedeutet, dass die Oberfläche überschritten wurde.

Rückgabewert

Liefert einen Q8-Zeitpunkt in 0..256; 192 entspricht 75 % des Takts.

Bedingungen und Grenzen

Halten Sie Abstände innerhalb von +/-8191. Ein Startwert kleiner oder gleich null liefert 0; ein Endwert größer oder gleich null liefert 256. Anfangsüberlappung und Zeitpunkt null haben denselben Rückgabewert. Ebenso teilen sich fehlender Übertritt und Kontakt genau am Endpunkt einen Rückgabewert. Positionen werden nicht geändert.

Binden Sie nicht nur Header ein, sondern kompilieren Sie auch die Implementierungsdateien. Für 2D benötigen Sie fixed.c und physics2d.c, für 3D zusätzlich physics3d.c. Die Beispiele nutzen MMC3, CHR-RAM und Zeichenspeicher im PRG-RAM bei $6800–$6FFF. Dieser Zeichenpuffer ist keine Voraussetzung der Physikbibliothek selbst.

Anwendungsbeispiel

c
result[4]=kq2d_surface_toi_q8(6,-2);
    result[5]=kq2d_surface_toi_q8(6,0);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Der rote Körper bleibt an seinem Platz. Seine grüne Geschwindigkeitslinie wechselt von (8,16) links zu (2,−8) rechts und zeigt Rückprall und tangentiale Reibung an der blauen Fläche. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48), der Körpermittelpunkt lokal bei (24,40). Die Auftreffgeschwindigkeit beträgt 16; das Beispiel zur Überquerungszeit gibt 192/256 zurück. Ein separater Aufruf zur Geschwindigkeitsbegrenzung reduziert (300,400) auf (147,196).

kq2d_surface_toi_q8: NTSC — Der rote Körper bleibt an seinem Platz. Seine grüne Geschwindigkeitslinie wechselt von (8,16) links zu (2,−8) rechts und zeigt Rückprall und tangentiale Reibung an der blauen Fläche. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48), der Körpermittelpunkt lokal bei (24,40). Die Auftreffgeschwindigkeit beträgt 16; das Beispiel zur Überquerungszeit gibt 192/256 zurück. Ein separater Aufruf zur Geschwindigkeitsbegrenzung reduziert (300,400) auf (147,196).
NTSC — Der rote Körper bleibt an seinem Platz. Seine grüne Geschwindigkeitslinie wechselt von (8,16) links zu (2,−8) rechts und zeigt Rückprall und tangentiale Reibung an der blauen Fläche. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48), der Körpermittelpunkt lokal bei (24,40). Die Auftreffgeschwindigkeit beträgt 16; das Beispiel zur Überquerungszeit gibt 192/256 zurück. Ein separater Aufruf zur Geschwindigkeitsbegrenzung reduziert (300,400) auf (147,196).

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/physics2d.h:96

Deklarationshinweise im Original
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

c
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

Physik für nicht rotierende 3D-Boxen, beschrieben durch Mittelpunkt und halbe Ausdehnung je Achse. Masse und inverse Masse gewichten Kontakte, restitution_q8 steuert den Rückprall und ax/ay/az liefern eine dauerhafte Beschleunigung. Die Darstellung erfolgt separat. Das Beispiel zeichnet Vorder- und Draufsicht desselben Körpers, um Tiefenbewegung und Wandrückprall zu zeigen.

Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.

last_impact_speed speichert die größte Annäherungsgeschwindigkeit entlang einer Kontaktachse. Die Integration setzt sie bei aktiven dynamischen Körpern zurück; statische und inaktive Körper behalten sie bei. Weder break_speed noch KQ3D_BODY_BROKEN löst automatisch eine Zerstörung aus. Das Spiel entscheidet darüber und ändert flags/active selbst.

Binden Sie nicht nur Header ein, sondern kompilieren Sie auch die Implementierungsdateien. Für 2D benötigen Sie fixed.c und physics2d.c, für 3D zusätzlich physics3d.c. Die Beispiele nutzen MMC3, CHR-RAM und Zeichenspeicher im PRG-RAM bei $6800–$6FFF. Dieser Zeichenpuffer ist keine Voraussetzung der Physikbibliothek selbst.

kq3d_world_init

Verknüpft ein Körperarray mit einer 3D-Welt mit Schwerkraft (0,24,0), vier Durchläufen und Geschwindigkeitsgrenze 512 pro Achse.

Syntax

c
void kq3d_world_init(KQWorld3D* world, KQBody3D* bodies, u8 body_count);

Parameter

world

Zeiger auf die Welt mit dem Körperarray und den Simulationseinstellungen.

bodies

Anfang eines vom aufrufenden Code gehaltenen Körperarrays mit body_count Elementen.

body_count

Anzahl der Arrayplätze von 0 bis 255, einschließlich inaktiver Einträge.

Rückgabewert

Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.

Bedingungen und Grenzen

Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.

Eine Welt nutzt ein vom aufrufenden Code bereitgestelltes Array. Dieser reserviert und besitzt den Speicher für die Körper und hält ihn gültig. Das Initialisieren der Welt initialisiert nicht die Arrayelemente.

Binden Sie nicht nur Header ein, sondern kompilieren Sie auch die Implementierungsdateien. Für 2D benötigen Sie fixed.c und physics2d.c, für 3D zusätzlich physics3d.c. Die Beispiele nutzen MMC3, CHR-RAM und Zeichenspeicher im PRG-RAM bei $6800–$6FFF. Dieser Zeichenpuffer ist keine Voraussetzung der Physikbibliothek selbst.

Anwendungsbeispiel

c
kq3d_world_init(&world,bodies,2);
    result[0]=world.gravity_y; result[1]=world.solver_iterations; result[2]=world.max_speed;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Links steht die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Kästen zeigen (36,24,24) nach einem Tick, blaue Bereiche das statische Hindernis. Die X-Geschwindigkeit wechselt von 16 auf −14, während die Z-Geschwindigkeit bei 8 bleibt. Der Aufprallwert beträgt 16, die Flags bleiben aber selbst mit break_speed=1 null. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48).

kq3d_world_init: NTSC — Links steht die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Kästen zeigen (36,24,24) nach einem Tick, blaue Bereiche das statische Hindernis. Die X-Geschwindigkeit wechselt von 16 auf −14, während die Z-Geschwindigkeit bei 8 bleibt. Der Aufprallwert beträgt 16, die Flags bleiben aber selbst mit break_speed=1 null. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48).
NTSC — Links steht die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Kästen zeigen (36,24,24) nach einem Tick, blaue Bereiche das statische Hindernis. Die X-Geschwindigkeit wechselt von 16 auf −14, während die Z-Geschwindigkeit bei 8 bleibt. Der Aufprallwert beträgt 16, die Flags bleiben aber selbst mit break_speed=1 null. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48).

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/physics3d.h:47

Deklarationshinweise im Original
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

c
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

Initialisiert 3D-Mittelpunkt, halbe Ausdehnungen und Masse; setzt Geschwindigkeit, Beschleunigung, Aufprallwert und Flags auf null und aktiviert den Körper.

Syntax

c
void kq3d_body_init(KQBody3D* body, s16 x, s16 y, s16 z, s16 half_x, s16 half_y, s16 half_z, s16 mass_q8);

Parameter

body

Zeiger auf den zu ändernden Körper. Von dieser Operation nicht verwendete Felder bleiben erhalten.

x

X-Koordinate des Mittelpunkts oder Punkts, im Beispiel in Pixeln.

y

Y-Koordinate des Mittelpunkts oder Punkts; im Beispiel zeigen positive Werte nach unten.

z

Z-Koordinate des Mittelpunkts, in der Draufsicht des Beispiels vertikal dargestellt.

half_x

Halbe Ausdehnung entlang X; die gesamte Boxbreite ist doppelt so groß.

half_y

Halbe Ausdehnung entlang Y; die gesamte Boxhöhe ist doppelt so groß.

half_z

Halbe Ausdehnung entlang Z; die gesamte Tiefe ist doppelt so groß.

mass_q8

Massenwert, bei dem 256 für 1,0 steht. Werte kleiner oder gleich null erzeugen einen statischen Körper.

Rückgabewert

Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.

Bedingungen und Grenzen

Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.

Der Rückprallkoeffizient beträgt 224, break_speed ist null. Für die Masse gelten die Regeln von kq3d_body_set_mass. NULL wird ignoriert; gültige halbe Ausdehnungen muss der aufrufende Code bereitstellen.

Binden Sie nicht nur Header ein, sondern kompilieren Sie auch die Implementierungsdateien. Für 2D benötigen Sie fixed.c und physics2d.c, für 3D zusätzlich physics3d.c. Die Beispiele nutzen MMC3, CHR-RAM und Zeichenspeicher im PRG-RAM bei $6800–$6FFF. Dieser Zeichenpuffer ist keine Voraussetzung der Physikbibliothek selbst.

Anwendungsbeispiel

c
kq3d_body_init(&temp,10,20,30,8,8,8,256);
    result[3]=temp.inv_mass_q8; result[4]=temp.restitution_q8; result[5]=temp.active;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Links steht die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Kästen zeigen (36,24,24) nach einem Tick, blaue Bereiche das statische Hindernis. Die X-Geschwindigkeit wechselt von 16 auf −14, während die Z-Geschwindigkeit bei 8 bleibt. Der Aufprallwert beträgt 16, die Flags bleiben aber selbst mit break_speed=1 null. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48).

kq3d_body_init: NTSC — Links steht die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Kästen zeigen (36,24,24) nach einem Tick, blaue Bereiche das statische Hindernis. Die X-Geschwindigkeit wechselt von 16 auf −14, während die Z-Geschwindigkeit bei 8 bleibt. Der Aufprallwert beträgt 16, die Flags bleiben aber selbst mit break_speed=1 null. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48).
NTSC — Links steht die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Kästen zeigen (36,24,24) nach einem Tick, blaue Bereiche das statische Hindernis. Die X-Geschwindigkeit wechselt von 16 auf −14, während die Z-Geschwindigkeit bei 8 bleibt. Der Aufprallwert beträgt 16, die Flags bleiben aber selbst mit break_speed=1 null. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48).

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/physics3d.h:51

Deklarationshinweise im Original
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

c
void kq3d_body_init(KQBody3D* body, s16 x, s16 y, s16 z, s16 half_x, s16 half_y, s16 half_z, s16 mass_q8)
{
    if (body == 0) return;

    body->x = x;
    body->y = y;
    body->z = z;
    body->vx = 0;
    body->vy = 0;
    body->vz = 0;
    body->ax = 0;
    body->ay = 0;
    body->az = 0;
    body->half_x = half_x;
    body->half_y = half_y;
    body->half_z = half_z;
    body->restitution_q8 = 224;
    body->break_speed = 0;
    body->last_impact_speed = 0;
    body->active = 1;
    body->flags = 0;
    kq3d_body_set_mass(body, mass_q8);
}
kq3d_body_set_mass

Speichert die angeforderte Masse und berechnet ein Gewicht aus der inversen Masse für Korrektur und Rückprall.

Syntax

c
void kq3d_body_set_mass(KQBody3D* body, s16 mass_q8);

Parameter

body

Zeiger auf den zu ändernden Körper. Von dieser Operation nicht verwendete Felder bleiben erhalten.

mass_q8

Massenwert, bei dem 256 für 1,0 steht. Werte kleiner oder gleich null erzeugen einen statischen Körper.

Rückgabewert

Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.

Bedingungen und Grenzen

Masse kleiner oder gleich null ergibt inverse Masse null und damit einen statischen Körper. Bei positiver Masse wird ganzzahlig 32767/max(mass,64) berechnet, mindestens jedoch 1. Die gespeicherte Masse behält den angeforderten Wert; das Gewicht ist daher kein exakter Q8-Kehrwert. Masse 256 ergibt inverse Masse 127. Geschwindigkeit und Aktivität bleiben unverändert; NULL wird ignoriert.

Binden Sie nicht nur Header ein, sondern kompilieren Sie auch die Implementierungsdateien. Für 2D benötigen Sie fixed.c und physics2d.c, für 3D zusätzlich physics3d.c. Die Beispiele nutzen MMC3, CHR-RAM und Zeichenspeicher im PRG-RAM bei $6800–$6FFF. Dieser Zeichenpuffer ist keine Voraussetzung der Physikbibliothek selbst.

Anwendungsbeispiel

c
kq3d_body_set_mass(&temp,32); result[6]=temp.mass_q8; result[7]=temp.inv_mass_q8;
    kq3d_body_set_mass(&temp,0); result[8]=temp.inv_mass_q8;
    kq3d_body_set_mass(&temp,256);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Links steht die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Kästen zeigen (36,24,24) nach einem Tick, blaue Bereiche das statische Hindernis. Die X-Geschwindigkeit wechselt von 16 auf −14, während die Z-Geschwindigkeit bei 8 bleibt. Der Aufprallwert beträgt 16, die Flags bleiben aber selbst mit break_speed=1 null. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48).

kq3d_body_set_mass: NTSC — Links steht die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Kästen zeigen (36,24,24) nach einem Tick, blaue Bereiche das statische Hindernis. Die X-Geschwindigkeit wechselt von 16 auf −14, während die Z-Geschwindigkeit bei 8 bleibt. Der Aufprallwert beträgt 16, die Flags bleiben aber selbst mit break_speed=1 null. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48).
NTSC — Links steht die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Kästen zeigen (36,24,24) nach einem Tick, blaue Bereiche das statische Hindernis. Die X-Geschwindigkeit wechselt von 16 auf −14, während die Z-Geschwindigkeit bei 8 bleibt. Der Aufprallwert beträgt 16, die Flags bleiben aber selbst mit break_speed=1 null. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48).

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/physics3d.h:56

Deklarationshinweise im Original
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

c
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

Integriert aktive dynamische Körper und verarbeitet Kontaktkorrektur, Rückprall und Aufprallwerte zwischen aktiven Welteinträgen.

Syntax

c
void kq3d_step(KQWorld3D* world);

Parameter

world

Zeiger auf die Welt mit dem Körperarray und den Simulationseinstellungen.

Rückgabewert

Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.

Bedingungen und Grenzen

Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.

Eine Welt nutzt ein vom aufrufenden Code bereitgestelltes Array. Dieser reserviert und besitzt den Speicher für die Körper und hält ihn gültig. Das Initialisieren der Welt initialisiert nicht die Arrayelemente.

Summen, Differenzen, addierte halbe Ausdehnungen und Produkte zur Kontaktkorrektur müssen im vorzeichenbehafteten 16-Bit-Bereich bleiben. Geschwindigkeitsgrenzen greifen erst nach der Addition und verhindern keinen Überlauf innerhalb dieser Addition.

Integration und Kollisionserkennung für Boxen verwenden gemeinsamen Arbeitsspeicher. Rufen Sie diese Physikroutinen nicht während ihrer Ausführung erneut aus einem Interrupt auf.

Kontakte nutzen die Achse mit der geringsten Eindringtiefe; bei Gleichstand gilt die Reihenfolge X, Y, Z. Nur eine Annäherung führt zum Abprallen. Dafür werden inverse Massen und der auf 0..256 begrenzte mittlere Rückprallkoeffizient verwendet. Schnelles Durchtunneln, Rotation, Drehimpuls und Reibung werden nicht behandelt.

last_impact_speed speichert die größte Annäherungsgeschwindigkeit entlang einer Kontaktachse. Die Integration setzt sie bei aktiven dynamischen Körpern zurück; statische und inaktive Körper behalten sie bei. Weder break_speed noch KQ3D_BODY_BROKEN löst automatisch eine Zerstörung aus. Das Spiel entscheidet darüber und ändert flags/active selbst.

Eine NULL-Welt oder ein NULL-Array wird ignoriert. Auch bei solver_iterations gleich null wird ein Kontaktdurchlauf ausgeführt.

Auch die Zwischenprodukte impact*(256+restitution) und correction*inverse-mass sind s16. Halten Sie die Produkte bei höchstens 32767; bei restitution 256 darf impact beispielsweise höchstens 63 betragen.

Binden Sie nicht nur Header ein, sondern kompilieren Sie auch die Implementierungsdateien. Für 2D benötigen Sie fixed.c und physics2d.c, für 3D zusätzlich physics3d.c. Die Beispiele nutzen MMC3, CHR-RAM und Zeichenspeicher im PRG-RAM bei $6800–$6FFF. Dieser Zeichenpuffer ist keine Voraussetzung der Physikbibliothek selbst.

Anwendungsbeispiel

c
kq3d_step(&world);
    result[16]=bodies[0].x; result[17]=bodies[0].y; result[18]=bodies[0].z;
    result[19]=bodies[0].vx; result[20]=bodies[0].vz;
    result[21]=bodies[0].last_impact_speed; result[22]=bodies[0].flags;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Links steht die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Kästen zeigen (36,24,24) nach einem Tick, blaue Bereiche das statische Hindernis. Die X-Geschwindigkeit wechselt von 16 auf −14, während die Z-Geschwindigkeit bei 8 bleibt. Der Aufprallwert beträgt 16, die Flags bleiben aber selbst mit break_speed=1 null. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48).

kq3d_step: NTSC — Links steht die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Kästen zeigen (36,24,24) nach einem Tick, blaue Bereiche das statische Hindernis. Die X-Geschwindigkeit wechselt von 16 auf −14, während die Z-Geschwindigkeit bei 8 bleibt. Der Aufprallwert beträgt 16, die Flags bleiben aber selbst mit break_speed=1 null. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48).
NTSC — Links steht die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Kästen zeigen (36,24,24) nach einem Tick, blaue Bereiche das statische Hindernis. Die X-Geschwindigkeit wechselt von 16 auf −14, während die Z-Geschwindigkeit bei 8 bleibt. Der Aufprallwert beträgt 16, die Flags bleiben aber selbst mit break_speed=1 null. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48).

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/physics3d.h:62

Deklarationshinweise im Original
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

c
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

Setzt den Aufprallwert eines aktiven dynamischen Körpers zurück, addiert Weltschwerkraft und Körperbeschleunigung, begrenzt jede Geschwindigkeitsachse und aktualisiert die Position.

Syntax

c
void kq3d_integrate_body(KQWorld3D* world, KQBody3D* body);

Parameter

world

Zeiger auf die Welt mit dem Körperarray und den Simulationseinstellungen.

body

Zeiger auf den zu ändernden Körper. Von dieser Operation nicht verwendete Felder bleiben erhalten.

Rückgabewert

Kein Rückgabewert. Dieser Eintrag erläutert die geänderten Felder und den Zeitpunkt, zu dem die Änderungen wirksam werden.

Bedingungen und Grenzen

Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.

Summen, Differenzen, addierte halbe Ausdehnungen und Produkte zur Kontaktkorrektur müssen im vorzeichenbehafteten 16-Bit-Bereich bleiben. Geschwindigkeitsgrenzen greifen erst nach der Addition und verhindern keinen Überlauf innerhalb dieser Addition.

Integration und Kollisionserkennung für Boxen verwenden gemeinsamen Arbeitsspeicher. Rufen Sie diese Physikroutinen nicht während ihrer Ausführung erneut aus einem Interrupt auf.

last_impact_speed speichert die größte Annäherungsgeschwindigkeit entlang einer Kontaktachse. Die Integration setzt sie bei aktiven dynamischen Körpern zurück; statische und inaktive Körper behalten sie bei. Weder break_speed noch KQ3D_BODY_BROKEN löst automatisch eine Zerstörung aus. Das Spiel entscheidet darüber und ändert flags/active selbst.

ax/ay/az bleiben erhalten und wirken erneut bei der nächsten Integration. Diese Funktion allein löst keine Kontakte auf. NULL, inaktive und statische Körper werden nicht verändert.

Binden Sie nicht nur Header ein, sondern kompilieren Sie auch die Implementierungsdateien. Für 2D benötigen Sie fixed.c und physics2d.c, für 3D zusätzlich physics3d.c. Die Beispiele nutzen MMC3, CHR-RAM und Zeichenspeicher im PRG-RAM bei $6800–$6FFF. Dieser Zeichenpuffer ist keine Voraussetzung der Physikbibliothek selbst.

Anwendungsbeispiel

c
kq3d_integrate_body(&world,&temp);
    result[9]=temp.x; result[10]=temp.y; result[11]=temp.z; result[12]=temp.last_impact_speed;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Links steht die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Kästen zeigen (36,24,24) nach einem Tick, blaue Bereiche das statische Hindernis. Die X-Geschwindigkeit wechselt von 16 auf −14, während die Z-Geschwindigkeit bei 8 bleibt. Der Aufprallwert beträgt 16, die Flags bleiben aber selbst mit break_speed=1 null. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48).

kq3d_integrate_body: NTSC — Links steht die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Kästen zeigen (36,24,24) nach einem Tick, blaue Bereiche das statische Hindernis. Die X-Geschwindigkeit wechselt von 16 auf −14, während die Z-Geschwindigkeit bei 8 bleibt. Der Aufprallwert beträgt 16, die Flags bleiben aber selbst mit break_speed=1 null. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48).
NTSC — Links steht die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Kästen zeigen (36,24,24) nach einem Tick, blaue Bereiche das statische Hindernis. Die X-Geschwindigkeit wechselt von 16 auf −14, während die Z-Geschwindigkeit bei 8 bleibt. Der Aufprallwert beträgt 16, die Flags bleiben aber selbst mit break_speed=1 null. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48).

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/physics3d.h:67

Deklarationshinweise im Original
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

c
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

Prüft zwei über ihren Mittelpunkt definierte Boxen auf echte Überlappung entlang aller drei Achsen.

Syntax

c
u8 kq3d_overlap_aabb(const KQBody3D* a, const KQBody3D* b);

Parameter

a

Gültiger Körperzeiger. Die Abfrage ignoriert Aktivität, Masse und Flags.

b

Gültiger Körperzeiger. Die Abfrage ignoriert Aktivität, Masse und Flags.

Rückgabewert

Liefert 1 bei Überlappung der Innenbereiche und 0 bei bloßer Berührung oder getrennten Formen.

Bedingungen und Grenzen

Verwenden Sie einheitliche ganzzahlige Einheiten für Positionen, Radien, halbe Ausdehnungen, Geschwindigkeiten und Schwerkraft. Ein Schritt entspricht einem Simulationstakt. Die Beispiele verwenden eine Einheit pro Pixel. Diese Routinen wandeln Positionen weder automatisch in Q8.8 um noch zeichnen sie diese.

Summen, Differenzen, addierte halbe Ausdehnungen und Produkte zur Kontaktkorrektur müssen im vorzeichenbehafteten 16-Bit-Bereich bleiben. Geschwindigkeitsgrenzen greifen erst nach der Addition und verhindern keinen Überlauf innerhalb dieser Addition.

Binden Sie nicht nur Header ein, sondern kompilieren Sie auch die Implementierungsdateien. Für 2D benötigen Sie fixed.c und physics2d.c, für 3D zusätzlich physics3d.c. Die Beispiele nutzen MMC3, CHR-RAM und Zeichenspeicher im PRG-RAM bei $6800–$6FFF. Dieser Zeichenpuffer ist keine Voraussetzung der Physikbibliothek selbst.

Anwendungsbeispiel

c
result[14]=kq3d_overlap_aabb(&bodies[0],&bodies[1]);
    bodies[1].z=32; result[15]=kq3d_overlap_aabb(&bodies[0],&bodies[1]);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Links steht die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Kästen zeigen (36,24,24) nach einem Tick, blaue Bereiche das statische Hindernis. Die X-Geschwindigkeit wechselt von 16 auf −14, während die Z-Geschwindigkeit bei 8 bleibt. Der Aufprallwert beträgt 16, die Flags bleiben aber selbst mit break_speed=1 null. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48).

kq3d_overlap_aabb: NTSC — Links steht die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Kästen zeigen (36,24,24) nach einem Tick, blaue Bereiche das statische Hindernis. Die X-Geschwindigkeit wechselt von 16 auf −14, während die Z-Geschwindigkeit bei 8 bleibt. Der Aufprallwert beträgt 16, die Flags bleiben aber selbst mit break_speed=1 null. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48).
NTSC — Links steht die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Kästen zeigen (36,24,24) nach einem Tick, blaue Bereiche das statische Hindernis. Die X-Geschwindigkeit wechselt von 16 auf −14, während die Z-Geschwindigkeit bei 8 bleibt. Der Aufprallwert beträgt 16, die Flags bleiben aber selbst mit break_speed=1 null. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48).

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/physics3d.h:71

Deklarationshinweise im Original
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

c
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

Teilt jedes der drei vorzeichenbehafteten Produkte durch 256, schneidet jeden Term gegen null ab und addiert anschließend die Terme.

Syntax

c
s16 kq3d_dot_q8_8(s16 x, s16 y, s16 z, s8 ax, s8 ay, s8 az);

Parameter

x

Vorzeichenbehaftete 16-Bit-Komponente, die mit dem zugehörigen Koeffizienten multipliziert wird; sie kann Position oder Geschwindigkeit darstellen.

y

Vorzeichenbehaftete 16-Bit-Komponente, die mit dem zugehörigen Koeffizienten multipliziert wird; sie kann Position oder Geschwindigkeit darstellen.

z

Vorzeichenbehaftete 16-Bit-Komponente, die mit dem zugehörigen Koeffizienten multipliziert wird; sie kann Position oder Geschwindigkeit darstellen.

ax

Vorzeichenbehafteter Bytekoeffizient für diese Achse (-128..127), mit Faktor 1/256 angewendet.

ay

Vorzeichenbehafteter Bytekoeffizient für diese Achse (-128..127), mit Faktor 1/256 angewendet.

az

Vorzeichenbehafteter Bytekoeffizient für diese Achse (-128..127), mit Faktor 1/256 angewendet.

Rückgabewert

Liefert die Summe dreier quantisierter Terme als s16.

Bedingungen und Grenzen

Jeden Term zuerst gegen null abzuschneiden kann ein anderes Ergebnis liefern als die Gesamtsumme einmal zu schieben. Ein Koeffizient kann 1,0=256 nicht speichern. Die Endsumme wird nicht gesättigt.

Binden Sie nicht nur Header ein, sondern kompilieren Sie auch die Implementierungsdateien. Für 2D benötigen Sie fixed.c und physics2d.c, für 3D zusätzlich physics3d.c. Die Beispiele nutzen MMC3, CHR-RAM und Zeichenspeicher im PRG-RAM bei $6800–$6FFF. Dieser Zeichenpuffer ist keine Voraussetzung der Physikbibliothek selbst.

Anwendungsbeispiel

c
result[13]=kq3d_dot_q8_8(256,128,0,64,-64,127);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Links steht die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Kästen zeigen (36,24,24) nach einem Tick, blaue Bereiche das statische Hindernis. Die X-Geschwindigkeit wechselt von 16 auf −14, während die Z-Geschwindigkeit bei 8 bleibt. Der Aufprallwert beträgt 16, die Flags bleiben aber selbst mit break_speed=1 null. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48).

kq3d_dot_q8_8: NTSC — Links steht die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Kästen zeigen (36,24,24) nach einem Tick, blaue Bereiche das statische Hindernis. Die X-Geschwindigkeit wechselt von 16 auf −14, während die Z-Geschwindigkeit bei 8 bleibt. Der Aufprallwert beträgt 16, die Flags bleiben aber selbst mit break_speed=1 null. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48).
NTSC — Links steht die X/Y-Vorderansicht, rechts die X/Z-Draufsicht. Grüne Umrisse markieren die Anfangsposition (24,24,16), rote Kästen zeigen (36,24,24) nach einem Tick, blaue Bereiche das statische Hindernis. Die X-Geschwindigkeit wechselt von 16 auf −14, während die Z-Geschwindigkeit bei 8 bleibt. Der Aufprallwert beträgt 16, die Flags bleiben aber selbst mit break_speed=1 null. Die Panelursprünge liegen auf dem Bildschirm bei (8,48) und (88,48).

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/physics3d.h:75

Deklarationshinweise im Original
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

c
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 — Deklarationen zur PPU-Anzeige

Binden oder kompilieren Sie ppu.c genau einmal und ohne runtime.c. Rufen Sie vor dessen Funktionen mit zwei Adressbytes __ppu_read_status() auf, um den gemeinsamen Latch zurückzusetzen. ppu.h deklariert diese Funktionen nicht; seine vier Deklarationen für Bildausgabe, Palette und Nametable besitzen in dieser Distribution keine Implementierung. Die hier gezeigten Funktionen stammen aus ppu.c; ppu.h allein reicht nicht aus.

nes_ppu_clear_nt

nes_ppu_clear_nt(nt_base, tile, attr) ist in dieser Distribution nicht implementiert. Das ausführbare Beispiel leert Nametable 0 in zwei Schritten: __nametable_rect_nt(0,0,0,32,30,0) beschreibt die 960 Kachelzellen, __vram_fill(0x23C0,0,64) löscht die 64 gepackten Attributbytes. Beide Aufrufe erfolgen bei ausgeschalteter Bildausgabe und Schrittweite 1. Logische Nametables können durch die Spiegelung der Cartridge denselben Speicher verwenden.

Syntax

c
void nes_ppu_clear_nt(unsigned short nt_base, unsigned char tile, unsigned char attr);

Parameter

nt_base / tile / attr

Der Prototyp deklariert nt_base als vorzeichenlosen 16-Bit-Wert und tile/attr als vorzeichenlose 8-Bit-Werte. Es gibt keinen Funktionskörper für Adresswahl, Füllen oder Prüfung dieser Parameter. Die Alternative wählt ausdrücklich die logische Nametable 0 und übergibt Kachel- und gepackte Attributwerte getrennt.

Rückgabewert

Deklarierter Rückgabetyp: void. Es ist keine Implementierung eingebunden; für diesen Namen gibt es daher kein ausführbares Rückkehrverhalten.

Bedingungen und Grenzen

Das Beispiel zeigt implementierte Alternativen und keinen erfolgreichen Aufruf der Deklaration. Die Prüfung umfasst den erwarteten Buildfehler wegen eines unaufgelösten Symbols für jeden fehlenden Namen sowie separate Emulatorprüfungen der Alternativen. Stellen Sie zum Aufruf des deklarierten Namens eine passende eigene Implementierung bereit; ein weiteres Header-Include liefert keinen Funktionskörper.

Anwendungsbeispiel

c
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;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Die ausführbare Alternative bereitet den Bildschirm bei ausgeschalteter Bildausgabe vor, setzt Paletten, löscht Kacheln und Attribute und zeichnet das Testbild. Bei (0,16) beginnt ein blaues Muster aus vollen Kacheln, linken Halbflächen und Dreiecken, bei (0,96) ein grüner Vollblock. Jeder Bereich ist 256×64 Pixel groß; die letzte 8×8-Zelle bei (248,72) beziehungsweise (248,152) bleibt wegen der Übertragung von 255 Kachelbytes schwarz. Bei y=208 stehen ein rotes 8×8-Quadrat an x=16, ein linker 4×8-Balken an x=224 und ein achtzeiliges Dreieck an x=240. FAILED CHECKS zeigt 0. Separate Zustandsprüfungen bestätigen beide Steuerregister, die 32 Palettenbytes und alle 1.024 gelöschten Nametable-Bytes. Die vier deklarierten Aufrufe müssen beim Linken scheitern.

nes_ppu_clear_nt: Weitere Verwendungen
Weitere Verwendungen

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/ppu.h:14

Deklarationshinweise im Original
Fill 960 tiles and 64 packed attributes; preserve PPUCTRL.
Accept exactly $2000/$2400/$2800/$2C00; invalid bases are ignored.

kitaqfc/lib/ppu.c:60

c
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

Setzt die Adresse mit hi und lo und schreibt value anschließend count-mal nach PPUDATA. Diese Funktion aus ppu.c füllt sofort mit einer 8-Bit-Anzahl; der Aufrufer setzt vorher den Latch zurück. Zeilen- oder Rechteckgrenzen begrenzen die Schreibzugriffe nicht.

Syntax

c
void nes_ppu_fill(unsigned char hi, unsigned char lo, unsigned char value, unsigned char count);

Parameter

hi / lo

hi und lo sind das obere und untere Byte einer PPU-Adresse: 0x23, 0x42 steht beispielsweise für 0x2342. Es sind Adressbytes und keine Kachelkoordinaten. Die üblichen Adressmasken und Spiegelungen der PPU gelten weiterhin.

value

Ein wiederholtes Byte von 0 bis 255. Seine sichtbare Wirkung hängt davon ab, ob das Ziel Tile-Indizes, Pixelebenen oder eine andere Bytestruktur enthält.

count

Byteanzahl 0..255 als vorzeichenloser 8-Bit-Wert. Null setzt die Adresse, ohne Daten zu schreiben. Der gemeinsame Latch wird auch bei null nicht zurückgesetzt; bereiten Sie ihn vor dem Aufruf vor.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Binden oder kompilieren Sie ppu.c genau einmal und ohne runtime.c. Rufen Sie vor dessen Funktionen mit zwei Adressbytes __ppu_read_status() auf, um den gemeinsamen Latch zurückzusetzen. ppu.h deklariert diese Funktionen nicht; seine vier Deklarationen für Bildausgabe, Palette und Nametable besitzen in dieser Distribution keine Implementierung. Die hier gezeigten Funktionen stammen aus ppu.c; ppu.h allein reicht nicht aus.

Direkter PPU-Zugriff erfordert ausgeschaltete Bildausgabe oder einen sicheren VBlank-Zeitraum, in den die gesamte Operation passt. Diese Funktionen warten nicht, legen keine Aufträge an, sperren NMI nicht und stellen den Bildlauf nicht wieder her. Verhindern Sie, dass Interrupts während des Aufrufs den gemeinsamen Latch oder die Adresse verändern. PPUCTRL-Bit 2 wählt eine Zieladressschrittweite von 1 oder 32 pro Byte. Spiegelung und Adressumlauf übernimmt die PPU; CHR-ROM ist nicht beschreibbar. Stellen Sie nach dem Zugriff vor der Bildausgabe den gewünschten Bildlauf ein.

Anwendungsbeispiel

c
__ppu_read_status();nes_ppu_fill(0x21,0x80,1,255);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das separate Beispiel mit zwei Adressbytes zeigt die ausdrückliche Latch-Vorbereitung und 8-Bit-Übertragungsanzahlen. Blauer und grüner Bereich verwenden jeweils 255 Bytes; die letzten 8×8-Zellen bei (248,72) und (248,152) bleiben schwarz. Die roten Markierungen besitzen dieselben Positionen und Formen wie im Laufzeitbeispiel. FAILED CHECKS zeigt 0; dieses Programm prüft die Wartefunktionen der Laufzeitbibliothek nicht.

nes_ppu_fill: Funktionspaar
Funktionspaar

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/ppu.c:27

Deklarationshinweise im Original
Set the address and issue count identical PPUDATA writes without waiting for VBlank.

kitaqfc/lib/ppu.c:27

c
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

Für nes_ppu_load_palette(pal32) existiert nur eine Deklaration, keine implementierte Palettenübertragung. Das lauffähige Beispiel überträgt bei ausgeschalteter Bildausgabe und Adressschrittweite 1 mit __palette_bg_load 16 Hintergrundbytes und mit __palette_sp_load 16 Spritebytes. Die Hardware-Palettenaliase gelten weiterhin; ein Schreibzugriff auf die Spritepalette kann auch einen Hintergrundfarbeintrag ändern.

Syntax

c
void nes_ppu_load_palette(unsigned char* pal32);

Parameter

pal32

pal32 ist als Zeiger auf vorzeichenlose Bytes deklariert. Der Name stellt keine implementierte 32-Byte-Übertragung bereit. Übergeben Sie für die lauffähige Alternative jedem Paletten-Intrinsic 16 lesbare Bytes und halten Sie die Quellbank bis zur Rückkehr eingeblendet.

Rückgabewert

Deklarierter Rückgabetyp: void. Es ist keine Implementierung eingebunden; für diesen Namen gibt es daher kein ausführbares Rückkehrverhalten.

Bedingungen und Grenzen

Das Beispiel zeigt implementierte Alternativen und keinen erfolgreichen Aufruf der Deklaration. Die Prüfung umfasst den erwarteten Buildfehler wegen eines unaufgelösten Symbols für jeden fehlenden Namen sowie separate Emulatorprüfungen der Alternativen. Stellen Sie zum Aufruf des deklarierten Namens eine passende eigene Implementierung bereit; ein weiteres Header-Include liefert keinen Funktionskörper.

Anwendungsbeispiel

c
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;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Die ausführbare Alternative bereitet den Bildschirm bei ausgeschalteter Bildausgabe vor, setzt Paletten, löscht Kacheln und Attribute und zeichnet das Testbild. Bei (0,16) beginnt ein blaues Muster aus vollen Kacheln, linken Halbflächen und Dreiecken, bei (0,96) ein grüner Vollblock. Jeder Bereich ist 256×64 Pixel groß; die letzte 8×8-Zelle bei (248,72) beziehungsweise (248,152) bleibt wegen der Übertragung von 255 Kachelbytes schwarz. Bei y=208 stehen ein rotes 8×8-Quadrat an x=16, ein linker 4×8-Balken an x=224 und ein achtzeiliges Dreieck an x=240. FAILED CHECKS zeigt 0. Separate Zustandsprüfungen bestätigen beide Steuerregister, die 32 Palettenbytes und alle 1.024 gelöschten Nametable-Bytes. Die vier deklarierten Aufrufe müssen beim Linken scheitern.

nes_ppu_load_palette: Weitere Verwendungen
Weitere Verwendungen

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/ppu.h:11

Deklarationshinweise im Original
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

c
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 ist in ppu.h deklariert, besitzt in dieser Distribution aber keinen Funktionskörper. Ein direkter Aufruf lässt sich nicht linken. Das ausführbare Beispiel stoppt die Bildausgabe mit __ppu_off(), das PPUMASK und dessen Softwarekopie auf null setzt. NMI wird dabei nicht deaktiviert; für die umfangreiche Bildschirmvorbereitung setzt das Beispiel PPUCTRL zusätzlich auf null.

Syntax

c
void nes_ppu_screen_off(void);

Rückgabewert

Deklarierter Rückgabetyp: void. Es ist keine Implementierung eingebunden; für diesen Namen gibt es daher kein ausführbares Rückkehrverhalten.

Bedingungen und Grenzen

Das Beispiel zeigt implementierte Alternativen und keinen erfolgreichen Aufruf der Deklaration. Die Prüfung umfasst den erwarteten Buildfehler wegen eines unaufgelösten Symbols für jeden fehlenden Namen sowie separate Emulatorprüfungen der Alternativen. Stellen Sie zum Aufruf des deklarierten Namens eine passende eigene Implementierung bereit; ein weiteres Header-Include liefert keinen Funktionskörper.

Anwendungsbeispiel

c
nes_ppu_screen_off();__ppu_ctrl_set(0); // Disable NMI during this bulk preparation.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Die ausführbare Alternative bereitet den Bildschirm bei ausgeschalteter Bildausgabe vor, setzt Paletten, löscht Kacheln und Attribute und zeichnet das Testbild. Bei (0,16) beginnt ein blaues Muster aus vollen Kacheln, linken Halbflächen und Dreiecken, bei (0,96) ein grüner Vollblock. Jeder Bereich ist 256×64 Pixel groß; die letzte 8×8-Zelle bei (248,72) beziehungsweise (248,152) bleibt wegen der Übertragung von 255 Kachelbytes schwarz. Bei y=208 stehen ein rotes 8×8-Quadrat an x=16, ein linker 4×8-Balken an x=224 und ein achtzeiliges Dreieck an x=240. FAILED CHECKS zeigt 0. Separate Zustandsprüfungen bestätigen beide Steuerregister, die 32 Palettenbytes und alle 1.024 gelöschten Nametable-Bytes. Die vier deklarierten Aufrufe müssen beim Linken scheitern.

nes_ppu_screen_off: Weitere Verwendungen
Weitere Verwendungen

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/ppu.h:6

Deklarationshinweise im Original
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

c
void nes_ppu_screen_off(void) { __ppu_mask_set((u8)(__ppu_mask_get() & 0xE7)); }
nes_ppu_screen_on

nes_ppu_screen_on(ctrl, mask) ist eine Deklaration ohne Implementierung und kann die Bildausgabe nicht selbst einschalten. Das lauffähige Beispiel stellt den Bildlauf ein und ruft __ppu_ctrl_set(0x80) sowie __ppu_mask_set(0x0A) auf. Das aktiviert NMI und den Hintergrund einschließlich der linken acht Pixel, aber keine Sprites. Wählen Sie die Registerwerte passend zu Ihrem Spiel.

Syntax

c
void nes_ppu_screen_on(unsigned char ctrl, unsigned char mask);

Parameter

ctrl / mask

Die Deklaration gibt ctrl und mask vorzeichenlose 8-Bit-Typen. Ein Funktionskörper, der ihr Laufzeitverhalten festlegt, fehlt. Die lauffähige Alternative schreibt die gewünschten PPUCTRL- und PPUMASK-Werte durch getrennte Intrinsic-Aufrufe.

Rückgabewert

Deklarierter Rückgabetyp: void. Es ist keine Implementierung eingebunden; für diesen Namen gibt es daher kein ausführbares Rückkehrverhalten.

Bedingungen und Grenzen

Das Beispiel zeigt implementierte Alternativen und keinen erfolgreichen Aufruf der Deklaration. Die Prüfung umfasst den erwarteten Buildfehler wegen eines unaufgelösten Symbols für jeden fehlenden Namen sowie separate Emulatorprüfungen der Alternativen. Stellen Sie zum Aufruf des deklarierten Namens eine passende eigene Implementierung bereit; ein weiteres Header-Include liefert keinen Funktionskörper.

Anwendungsbeispiel

c
nes_ppu_screen_on(0x80,0x0A);
// NMI and background rendering are now enabled, with left-edge background visible.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Die ausführbare Alternative bereitet den Bildschirm bei ausgeschalteter Bildausgabe vor, setzt Paletten, löscht Kacheln und Attribute und zeichnet das Testbild. Bei (0,16) beginnt ein blaues Muster aus vollen Kacheln, linken Halbflächen und Dreiecken, bei (0,96) ein grüner Vollblock. Jeder Bereich ist 256×64 Pixel groß; die letzte 8×8-Zelle bei (248,72) beziehungsweise (248,152) bleibt wegen der Übertragung von 255 Kachelbytes schwarz. Bei y=208 stehen ein rotes 8×8-Quadrat an x=16, ein linker 4×8-Balken an x=224 und ein achtzeiliges Dreieck an x=240. FAILED CHECKS zeigt 0. Separate Zustandsprüfungen bestätigen beide Steuerregister, die 32 Palettenbytes und alle 1.024 gelöschten Nametable-Bytes. Die vier deklarierten Aufrufe müssen beim Linken scheitern.

nes_ppu_screen_on: Weitere Verwendungen
Weitere Verwendungen

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/ppu.h:8

Deklarationshinweise im Original
Set scroll to (0,0), then apply the requested PPUCTRL and PPUMASK values.

kitaqfc/lib/ppu.c:39

c
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

Setzt durch Lesen von PPUSTATUS das gemeinsame PPU-Adresslatch zurück und setzt anschließend die Adresse aus getrennten hi- und lo-Bytes. Diese Form ist nützlich, wenn das Spiel die Adresse bereits als zwei Bytes speichert.

Syntax

c
void nes_ppu_seek_bytes(unsigned char hi, unsigned char lo);

Parameter

hi / lo

hi und lo sind das obere und untere Byte einer PPU-Adresse: 0x23, 0x42 steht beispielsweise für 0x2342. Es sind Adressbytes und keine Kachelkoordinaten. Die üblichen Adressmasken und Spiegelungen der PPU gelten weiterhin.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Binden oder kompilieren Sie ppu.c genau einmal und ohne runtime.c. Rufen Sie vor dessen Funktionen mit zwei Adressbytes __ppu_read_status() auf, um den gemeinsamen Latch zurückzusetzen. ppu.h deklariert diese Funktionen nicht; seine vier Deklarationen für Bildausgabe, Palette und Nametable besitzen in dieser Distribution keine Implementierung. Die hier gezeigten Funktionen stammen aus ppu.c; ppu.h allein reicht nicht aus.

Direkter PPU-Zugriff erfordert ausgeschaltete Bildausgabe oder einen sicheren VBlank-Zeitraum, in den die gesamte Operation passt. Diese Funktionen warten nicht, legen keine Aufträge an, sperren NMI nicht und stellen den Bildlauf nicht wieder her. Verhindern Sie, dass Interrupts während des Aufrufs den gemeinsamen Latch oder die Adresse verändern. PPUCTRL-Bit 2 wählt eine Zieladressschrittweite von 1 oder 32 pro Byte. Spiegelung und Adressumlauf übernimmt die PPU; CHR-ROM ist nicht beschreibbar. Stellen Sie nach dem Zugriff vor der Bildausgabe den gewünschten Bildlauf ein.

Anwendungsbeispiel

c
nes_ppu_seek_bytes(0x23,0x42);
PPUDATA=1; // Red 8x8 marker at pixel (16,208).

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das separate Beispiel mit zwei Adressbytes zeigt die ausdrückliche Latch-Vorbereitung und 8-Bit-Übertragungsanzahlen. Blauer und grüner Bereich verwenden jeweils 255 Bytes; die letzten 8×8-Zellen bei (248,72) und (248,152) bleiben schwarz. Die roten Markierungen besitzen dieselben Positionen und Formen wie im Laufzeitbeispiel. FAILED CHECKS zeigt 0; dieses Programm prüft die Wartefunktionen der Laufzeitbibliothek nicht.

nes_ppu_seek_bytes: Funktionspaar
Funktionspaar

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/ppu.c:8

Deklarationshinweise im Original
Reset the shared scroll/address latch before writing the address byte pair.

kitaqfc/lib/ppu.c:8

c
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

Schreibt nach dem Setzen der Adresse mit hi und lo direkt count aufeinanderfolgende Quellbytes nach PPUDATA. Diese Funktion aus ppu.c nimmt eine 8-Bit-Anzahl entgegen; der Aufrufer muss den Adress-Latch zurücksetzen. Die Übertragung endet vor der Rückkehr und verwendet keine Warteschlange.

Syntax

c
void nes_ppu_write_bytes(unsigned char hi, unsigned char lo, const unsigned char* src, unsigned char count);

Parameter

hi / lo

hi und lo sind das obere und untere Byte einer PPU-Adresse: 0x23, 0x42 steht beispielsweise für 0x2342. Es sind Adressbytes und keine Kachelkoordinaten. Die üblichen Adressmasken und Spiegelungen der PPU gelten weiterhin.

src

CPU-Zeiger auf mindestens die angeforderte Anzahl lesbarer Bytes. Halten Sie die Quelle bis zur Rückkehr dieser synchronen Übertragung eingeblendet und unverändert. Es gibt keine Bankumschaltung, Speicherung des Zeigers in einer Warteschlange oder Prüfung der Quelllänge. Bei Anzahl null wird der Zeiger nicht dereferenziert.

count

Byteanzahl 0..255 als vorzeichenloser 8-Bit-Wert. Null setzt die Adresse, ohne Daten zu schreiben. Der gemeinsame Latch wird auch bei null nicht zurückgesetzt; bereiten Sie ihn vor dem Aufruf vor.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Binden oder kompilieren Sie ppu.c genau einmal und ohne runtime.c. Rufen Sie vor dessen Funktionen mit zwei Adressbytes __ppu_read_status() auf, um den gemeinsamen Latch zurückzusetzen. ppu.h deklariert diese Funktionen nicht; seine vier Deklarationen für Bildausgabe, Palette und Nametable besitzen in dieser Distribution keine Implementierung. Die hier gezeigten Funktionen stammen aus ppu.c; ppu.h allein reicht nicht aus.

Direkter PPU-Zugriff erfordert ausgeschaltete Bildausgabe oder einen sicheren VBlank-Zeitraum, in den die gesamte Operation passt. Diese Funktionen warten nicht, legen keine Aufträge an, sperren NMI nicht und stellen den Bildlauf nicht wieder her. Verhindern Sie, dass Interrupts während des Aufrufs den gemeinsamen Latch oder die Adresse verändern. PPUCTRL-Bit 2 wählt eine Zieladressschrittweite von 1 oder 32 pro Byte. Spiegelung und Adressumlauf übernimmt die PPU; CHR-ROM ist nicht beschreibbar. Stellen Sie nach dem Zugriff vor der Bildausgabe den gewünschten Bildlauf ein.

Anwendungsbeispiel

c
__ppu_read_status();nes_ppu_write_bytes(0x20,0x40,source_bytes,255);
source_bytes[0]=3; // The completed transfer retains tile 1.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das separate Beispiel mit zwei Adressbytes zeigt die ausdrückliche Latch-Vorbereitung und 8-Bit-Übertragungsanzahlen. Blauer und grüner Bereich verwenden jeweils 255 Bytes; die letzten 8×8-Zellen bei (248,72) und (248,152) bleiben schwarz. Die roten Markierungen besitzen dieselben Positionen und Formen wie im Laufzeitbeispiel. FAILED CHECKS zeigt 0; dieses Programm prüft die Wartefunktionen der Laufzeitbibliothek nicht.

nes_ppu_write_bytes: Funktionspaar
Funktionspaar

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/ppu.c:18

Deklarationshinweise im Original
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

c
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 — C-Hilfsfunktionen für NMI, OAM und PPU-Übertragungen

Verwenden Sie die Deklarationen aus runtime.h und binden oder kompilieren Sie runtime.c genau einmal. Neben dieser Warteschlange stellt die Datei __nes_nmi, den Laufzeit-Bildzähler, direkte PPU-Hilfsfunktionen und OAM-Speicher auf Seite 02 bereit. Stimmen Sie die NMI-Behandlung mit Ihrem Programm ab; eine Funktionsdeklaration allein bindet keine Implementierung ein.

Dies ist eine separate 192-Byte-Warteschlange aus runtime.c an den CPU-Adressen 0x0300–0x03BF. Ein Dateneintrag belegt 3+len Bytes, ein Fülleintrag vier. nes_vram_queue_used zählt codierte Bytes, nicht ausstehende PPU-Schreibzugriffe oder freien VRAM. Die Intrinsic-Warteschlange __vramq_* verwendet ein anderes Format; diese Funktionen leeren, prüfen oder verarbeiten sie nicht.

Trennen Sie Aufbau und Verarbeitung der Pakete; Sperren oder doppelte Puffer sind nicht vorgesehen. Für eine eindeutige Vorbereitung deaktivieren Sie NMI beim Anhängen und verarbeiten die Einträge bei abgeschalteter Bildausgabe, oder aktivieren NMI für ein Paket, das in VBlank passt. runtime.c verarbeitet eine nicht leere Warteschlange automatisch aus __nes_nmi, ohne Freigabeaufruf. Es gibt weder Zeitbudget noch Aufteilung oder Wiederherstellung des Scrollzustands. Freier Warteschlangenplatz garantiert keine sichere VBlank-Dauer.

nes_ppu_seek

Setzt die PPU-Adresse für nachfolgende PPUDATA-Zugriffe. nes_ppu_seek(ppu_addr) aus runtime.c liest PPUSTATUS, setzt damit den gemeinsamen Schreib-Latch zurück und schreibt anschließend das obere und untere Adressbyte. Die separate Funktion nes_ppu_seek(hi, lo) aus ppu.c setzt den Latch nicht zurück. Trotz gleichem Namen unterscheiden sich Parameter und Verhalten; binden Sie nur eine der beiden Implementierungen ein.

Syntax

c
void nes_ppu_seek(unsigned short ppu_addr);

Parameter

ppu_addr

PPU-Byteadresse (0x0000–0x3FFF), kein CPU-Zeiger. Das Ziel muss beschreibbar sein: Musteränderungen benötigen CHR-RAM statt CHR-ROM. PPU-Adressabbildung und Spiegelung gelten weiterhin. Wählen Sie für fortlaufendes Kopieren und Füllen die Schrittweite 1 in PPUCTRL. Führen Sie Befehle zu einem sicheren PPU-Zeitpunkt aus und stellen Sie danach den Scrollzustand her; der Ausführer schreibt PPUADDR und PPUDATA, ohne Scrolleinstellungen wiederherzustellen.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Verwenden Sie die Deklarationen aus runtime.h und binden oder kompilieren Sie runtime.c genau einmal. Neben dieser Warteschlange stellt die Datei __nes_nmi, den Laufzeit-Bildzähler, direkte PPU-Hilfsfunktionen und OAM-Speicher auf Seite 02 bereit. Stimmen Sie die NMI-Behandlung mit Ihrem Programm ab; eine Funktionsdeklaration allein bindet keine Implementierung ein.

Direkter PPU-Zugriff erfordert ausgeschaltete Bildausgabe oder einen sicheren VBlank-Zeitraum, in den die gesamte Operation passt. Diese Funktionen warten nicht, legen keine Aufträge an, sperren NMI nicht und stellen den Bildlauf nicht wieder her. Verhindern Sie, dass Interrupts während des Aufrufs den gemeinsamen Latch oder die Adresse verändern. PPUCTRL-Bit 2 wählt eine Zieladressschrittweite von 1 oder 32 pro Byte. Spiegelung und Adressumlauf übernimmt die PPU; CHR-ROM ist nicht beschreibbar. Stellen Sie nach dem Zugriff vor der Bildausgabe den gewünschten Bildlauf ein.

Anwendungsbeispiel

c
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).

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Laufzeitbeispiel zeigt direkte Übertragung und beide Wartemethoden. Bei (0,16) erscheint ein blaues Muster aus vollen Kacheln, linken Halbflächen und Dreiecken; bei (0,96) ein gefüllter grüner Block. Jeder Block ist 256×64 Pixel groß und entsteht aus 256 Kachelbytes. Die erste blaue Kachel bleibt nach Änderung der Quelle gefüllt. Bei y=208 markieren rote Formen an x=16, 224 und 240 Adresssetzung, Schreiben mit Länge null und Füllen mit Länge null: ein 8×8-Quadrat, ein linker 4×8-Balken und ein achtzeiliges Dreieck. Beide Warteanzeigen zeigen 1, FAILED CHECKS zeigt 0.

nes_ppu_seek: Laufzeit
Laufzeit

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/runtime.h:28

Deklarationshinweise im Original
Reset the PPU address latch with a status read, then write the high/low address bytes.

kitaqfc/lib/runtime.c:207

c
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

Setzt ppu_addr und schreibt anschließend dasselbe Byte value genau len-mal nach PPUDATA. Das direkte Füllen ist bei der Rückkehr abgeschlossen. Kachelmaße, Attribute und Rechteckgrenzen werden dabei nicht ausgewertet.

Syntax

c
void nes_ppu_stream_fill(unsigned short ppu_addr, unsigned char value, unsigned short len);

Parameter

ppu_addr

PPU-Byteadresse (0x0000–0x3FFF), kein CPU-Zeiger. Das Ziel muss beschreibbar sein: Musteränderungen benötigen CHR-RAM statt CHR-ROM. PPU-Adressabbildung und Spiegelung gelten weiterhin. Wählen Sie für fortlaufendes Kopieren und Füllen die Schrittweite 1 in PPUCTRL. Führen Sie Befehle zu einem sicheren PPU-Zeitpunkt aus und stellen Sie danach den Scrollzustand her; der Ausführer schreibt PPUADDR und PPUDATA, ohne Scrolleinstellungen wiederherzustellen.

value

Ein wiederholtes Byte von 0 bis 255. Seine sichtbare Wirkung hängt davon ab, ob das Ziel Tile-Indizes, Pixelebenen oder eine andere Bytestruktur enthält.

len

Byteanzahl von 0..65535 als vorzeichenloser 16-Bit-Wert. Auch null setzt die PPU-Adresse und den Latch zurück, schreibt aber nicht nach PPUDATA. Zielgröße und Aufteilung der Übertragung werden nicht geprüft; große Werte können den PPU-Adressraum umlaufen.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Verwenden Sie die Deklarationen aus runtime.h und binden oder kompilieren Sie runtime.c genau einmal. Neben dieser Warteschlange stellt die Datei __nes_nmi, den Laufzeit-Bildzähler, direkte PPU-Hilfsfunktionen und OAM-Speicher auf Seite 02 bereit. Stimmen Sie die NMI-Behandlung mit Ihrem Programm ab; eine Funktionsdeklaration allein bindet keine Implementierung ein.

Direkter PPU-Zugriff erfordert ausgeschaltete Bildausgabe oder einen sicheren VBlank-Zeitraum, in den die gesamte Operation passt. Diese Funktionen warten nicht, legen keine Aufträge an, sperren NMI nicht und stellen den Bildlauf nicht wieder her. Verhindern Sie, dass Interrupts während des Aufrufs den gemeinsamen Latch oder die Adresse verändern. PPUCTRL-Bit 2 wählt eine Zieladressschrittweite von 1 oder 32 pro Byte. Spiegelung und Adressumlauf übernimmt die PPU; CHR-ROM ist nicht beschreibbar. Stellen Sie nach dem Zugriff vor der Bildausgabe den gewünschten Bildlauf ein.

Anwendungsbeispiel

c
nes_ppu_stream_fill(0x2180,1,256); // Eight complete rows of solid green tiles.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Laufzeitbeispiel zeigt direkte Übertragung und beide Wartemethoden. Bei (0,16) erscheint ein blaues Muster aus vollen Kacheln, linken Halbflächen und Dreiecken; bei (0,96) ein gefüllter grüner Block. Jeder Block ist 256×64 Pixel groß und entsteht aus 256 Kachelbytes. Die erste blaue Kachel bleibt nach Änderung der Quelle gefüllt. Bei y=208 markieren rote Formen an x=16, 224 und 240 Adresssetzung, Schreiben mit Länge null und Füllen mit Länge null: ein 8×8-Quadrat, ein linker 4×8-Balken und ein achtzeiliges Dreieck. Beide Warteanzeigen zeigen 1, FAILED CHECKS zeigt 0.

nes_ppu_stream_fill: Laufzeit
Laufzeit

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/runtime.h:34

Deklarationshinweise im Original
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

c
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

Schreibt ab ppu_addr direkt len aufeinanderfolgende Quellbytes nach PPUDATA. Die Adresse wird einmal gesetzt; nach jedem Schreibzugriff wird die lokale Kopie des Quellzeigers erhöht. Bei der Rückkehr ist die Übertragung abgeschlossen. Spätere Änderungen der Quelle verändern die VRAM-Daten nicht. Die Zeigervariable des Aufrufers bleibt unverändert.

Syntax

c
void nes_ppu_stream_write(unsigned short ppu_addr, unsigned char* src, unsigned short len);

Parameter

ppu_addr

PPU-Byteadresse (0x0000–0x3FFF), kein CPU-Zeiger. Das Ziel muss beschreibbar sein: Musteränderungen benötigen CHR-RAM statt CHR-ROM. PPU-Adressabbildung und Spiegelung gelten weiterhin. Wählen Sie für fortlaufendes Kopieren und Füllen die Schrittweite 1 in PPUCTRL. Führen Sie Befehle zu einem sicheren PPU-Zeitpunkt aus und stellen Sie danach den Scrollzustand her; der Ausführer schreibt PPUADDR und PPUDATA, ohne Scrolleinstellungen wiederherzustellen.

src

CPU-Zeiger auf mindestens die angeforderte Anzahl lesbarer Bytes. Halten Sie die Quelle bis zur Rückkehr dieser synchronen Übertragung eingeblendet und unverändert. Es gibt keine Bankumschaltung, Speicherung des Zeigers in einer Warteschlange oder Prüfung der Quelllänge. Bei Anzahl null wird der Zeiger nicht dereferenziert.

len

Byteanzahl von 0..65535 als vorzeichenloser 16-Bit-Wert. Auch null setzt die PPU-Adresse und den Latch zurück, schreibt aber nicht nach PPUDATA. Zielgröße und Aufteilung der Übertragung werden nicht geprüft; große Werte können den PPU-Adressraum umlaufen.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Verwenden Sie die Deklarationen aus runtime.h und binden oder kompilieren Sie runtime.c genau einmal. Neben dieser Warteschlange stellt die Datei __nes_nmi, den Laufzeit-Bildzähler, direkte PPU-Hilfsfunktionen und OAM-Speicher auf Seite 02 bereit. Stimmen Sie die NMI-Behandlung mit Ihrem Programm ab; eine Funktionsdeklaration allein bindet keine Implementierung ein.

Direkter PPU-Zugriff erfordert ausgeschaltete Bildausgabe oder einen sicheren VBlank-Zeitraum, in den die gesamte Operation passt. Diese Funktionen warten nicht, legen keine Aufträge an, sperren NMI nicht und stellen den Bildlauf nicht wieder her. Verhindern Sie, dass Interrupts während des Aufrufs den gemeinsamen Latch oder die Adresse verändern. PPUCTRL-Bit 2 wählt eine Zieladressschrittweite von 1 oder 32 pro Byte. Spiegelung und Adressumlauf übernimmt die PPU; CHR-ROM ist nicht beschreibbar. Stellen Sie nach dem Zugriff vor der Bildausgabe den gewünschten Bildlauf ein.

Anwendungsbeispiel

c
// 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.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Laufzeitbeispiel zeigt direkte Übertragung und beide Wartemethoden. Bei (0,16) erscheint ein blaues Muster aus vollen Kacheln, linken Halbflächen und Dreiecken; bei (0,96) ein gefüllter grüner Block. Jeder Block ist 256×64 Pixel groß und entsteht aus 256 Kachelbytes. Die erste blaue Kachel bleibt nach Änderung der Quelle gefüllt. Bei y=208 markieren rote Formen an x=16, 224 und 240 Adresssetzung, Schreiben mit Länge null und Füllen mit Länge null: ein 8×8-Quadrat, ein linker 4×8-Balken und ein achtzeiliges Dreieck. Beide Warteanzeigen zeigen 1, FAILED CHECKS zeigt 0.

nes_ppu_stream_write: Laufzeit
Laufzeit

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/runtime.h:31

Deklarationshinweise im Original
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

c
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

Fragt Bit 7 von PPUSTATUS ab, verbraucht zunächst eine bereits gesetzte Meldung und wartet dann auf eine neue VBlank-Meldung. Funktioniert auch bei deaktiviertem NMI, führt aber keine Warteschlange aus und ändert den NMI-Zähler der Laufzeitbibliothek nicht. Jeder Statuslesezugriff löscht das VBlank-Flag und setzt den gemeinsamen Schreib-Latch für Bildlauf und Adresse zurück. Verwenden Sie diese Abfrage getrennt von der NMI-gesteuerten Ablaufplanung, da Statuszugriffe das NMI-Timing beeinflussen können. Zeitlimit, Datenübertragung und Wiederherstellung des Bildlaufs sind nicht enthalten.

Syntax

c
void nes_vblank_wait(void);

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Verwenden Sie die Deklarationen aus runtime.h und binden oder kompilieren Sie runtime.c genau einmal. Neben dieser Warteschlange stellt die Datei __nes_nmi, den Laufzeit-Bildzähler, direkte PPU-Hilfsfunktionen und OAM-Speicher auf Seite 02 bereit. Stimmen Sie die NMI-Behandlung mit Ihrem Programm ab; eine Funktionsdeklaration allein bindet keine Implementierung ein.

Anwendungsbeispiel

c
// 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.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Laufzeitbeispiel zeigt direkte Übertragung und beide Wartemethoden. Bei (0,16) erscheint ein blaues Muster aus vollen Kacheln, linken Halbflächen und Dreiecken; bei (0,96) ein gefüllter grüner Block. Jeder Block ist 256×64 Pixel groß und entsteht aus 256 Kachelbytes. Die erste blaue Kachel bleibt nach Änderung der Quelle gefüllt. Bei y=208 markieren rote Formen an x=16, 224 und 240 Adresssetzung, Schreiben mit Länge null und Füllen mit Länge null: ein 8×8-Quadrat, ein linker 4×8-Balken und ein achtzeiliges Dreieck. Beide Warteanzeigen zeigen 1, FAILED CHECKS zeigt 0.

nes_vblank_wait: Laufzeit
Laufzeit

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/runtime.h:26

Deklarationshinweise im Original
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

c
void nes_vblank_wait(void)
{
    while ((PPUSTATUS & 0x80) != 0)
    {
    }
    while ((PPUSTATUS & 0x80) == 0)
    {
    }
}
nes_vram_queue_clear

Verwirft alle ausstehenden Einträge der C-Laufzeitwarteschlange und setzt nes_vram_queue_used sowie nes_vram_queue_overflow auf null. Es erfolgen keine PPU-Schreibzugriffe; die gespeicherten Nutzdatenbytes werden nicht gelöscht. Die Intrinsic-Warteschlange des Compilers bleibt unverändert.

Syntax

c
void nes_vram_queue_clear(void);

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Dies ist eine separate 192-Byte-Warteschlange aus runtime.c an den CPU-Adressen 0x0300–0x03BF. Ein Dateneintrag belegt 3+len Bytes, ein Fülleintrag vier. nes_vram_queue_used zählt codierte Bytes, nicht ausstehende PPU-Schreibzugriffe oder freien VRAM. Die Intrinsic-Warteschlange __vramq_* verwendet ein anderes Format; diese Funktionen leeren, prüfen oder verarbeiten sie nicht.

Verwenden Sie die Deklarationen aus runtime.h und binden oder kompilieren Sie runtime.c genau einmal. Neben dieser Warteschlange stellt die Datei __nes_nmi, den Laufzeit-Bildzähler, direkte PPU-Hilfsfunktionen und OAM-Speicher auf Seite 02 bereit. Stimmen Sie die NMI-Behandlung mit Ihrem Programm ab; eine Funktionsdeklaration allein bindet keine Implementierung ein.

Trennen Sie Aufbau und Verarbeitung der Pakete; Sperren oder doppelte Puffer sind nicht vorgesehen. Für eine eindeutige Vorbereitung deaktivieren Sie NMI beim Anhängen und verarbeiten die Einträge bei abgeschalteter Bildausgabe, oder aktivieren NMI für ein Paket, das in VBlank passt. runtime.c verarbeitet eine nicht leere Warteschlange automatisch aus __nes_nmi, ohne Freigabeaufruf. Es gibt weder Zeitbudget noch Aufteilung oder Wiederherstellung des Scrollzustands. Freier Warteschlangenplatz garantiert keine sichere VBlank-Dauer.

Anwendungsbeispiel

c
nes_vram_queue_clear(); // Discard all records AND clear the overflow latch.
if(nes_vram_queue_used!=0 || nes_vram_queue_overflow!=0)failures++;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel füllt zunächst alle 192 Warteschlangenbytes und lässt einen weiteren Eintrag absichtlich ablehnen. Es verwirft dieses Paket, prüft die Ablehnung von Länge 128 und reiht dann fünf Einträge ein: 145 Bytes für 255 PPU-Schreibzugriffe. Erwartet werden CAPACITY 192, ENCODED BYTES 145, AFTER FLUSH 000, REJECTED LENGTH 001, OVERFLOW SEEN 001 und FAILED CHECKS 000. Die Ablehnungsanzeigen speichern Beobachtungen aus vorherigen Programmschritten, nicht den abschließenden Flagzustand.

Die blau kopierten Tiles beginnen bei (0,16), die grüne Füllung bei (0,64). Jeder Bereich enthält 127 Tiles: drei volle Reihen und 31 Tiles in der vierten; die letzte 8×8-Zelle bleibt schwarz. Die blaue Folge wiederholt volle, halbbreite und dreieckige Tiles; das erste bleibt trotz geänderter Quelle voll. Bei y=112 bleibt das rote Quadrat bei x=16 nach Aufträgen der Länge null erhalten, das rote halbe Tile bei x=224 belegt die automatische NMI-Verarbeitung, und die verworfene Zelle bei x=248 bleibt schwarz. Geprüft werden 18.432 Pixel sowie das Ausbleiben von VRAM-Schreibzugriffen während aktiver Bildausgabe. Physische Hardware wurde nicht getestet.

nes_vram_queue_clear: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/runtime.h:40

Deklarationshinweise im Original
Discard pending VRAM commands and clear the overflow latch; no PPU writes occur.

kitaqfc/lib/runtime.c:31

c
void nes_vram_queue_clear(void)
{
    nes_vram_queue_used = 0;
    nes_vram_queue_overflow = 0;
}
nes_vram_queue_nmi_flush

Arbeitet alle ausstehenden Einträge der C-Laufzeitwarteschlange der Reihe nach ab, ohne Freigabeflag. Setzt für jeden Eintrag die PPU-Adresse und überträgt die gespeicherten Daten oder wiederholt das Füllbyte. Danach wird nes_vram_queue_used auf null gesetzt; das Überlaufflag bleibt erhalten. Bei leerer Warteschlange erfolgt kein PPU-Zugriff.

Syntax

c
void nes_vram_queue_nmi_flush(void);

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Dies ist eine separate 192-Byte-Warteschlange aus runtime.c an den CPU-Adressen 0x0300–0x03BF. Ein Dateneintrag belegt 3+len Bytes, ein Fülleintrag vier. nes_vram_queue_used zählt codierte Bytes, nicht ausstehende PPU-Schreibzugriffe oder freien VRAM. Die Intrinsic-Warteschlange __vramq_* verwendet ein anderes Format; diese Funktionen leeren, prüfen oder verarbeiten sie nicht.

Verwenden Sie die Deklarationen aus runtime.h und binden oder kompilieren Sie runtime.c genau einmal. Neben dieser Warteschlange stellt die Datei __nes_nmi, den Laufzeit-Bildzähler, direkte PPU-Hilfsfunktionen und OAM-Speicher auf Seite 02 bereit. Stimmen Sie die NMI-Behandlung mit Ihrem Programm ab; eine Funktionsdeklaration allein bindet keine Implementierung ein.

Trennen Sie Aufbau und Verarbeitung der Pakete; Sperren oder doppelte Puffer sind nicht vorgesehen. Für eine eindeutige Vorbereitung deaktivieren Sie NMI beim Anhängen und verarbeiten die Einträge bei abgeschalteter Bildausgabe, oder aktivieren NMI für ein Paket, das in VBlank passt. runtime.c verarbeitet eine nicht leere Warteschlange automatisch aus __nes_nmi, ohne Freigabeaufruf. Es gibt weder Zeitbudget noch Aufteilung oder Wiederherstellung des Scrollzustands. Freier Warteschlangenplatz garantiert keine sichere VBlank-Dauer.

PPU-Byteadresse (0x0000–0x3FFF), kein CPU-Zeiger. Das Ziel muss beschreibbar sein: Musteränderungen benötigen CHR-RAM statt CHR-ROM. PPU-Adressabbildung und Spiegelung gelten weiterhin. Wählen Sie für fortlaufendes Kopieren und Füllen die Schrittweite 1 in PPUCTRL. Führen Sie Befehle zu einem sicheren PPU-Zeitpunkt aus und stellen Sie danach den Scrollzustand her; der Ausführer schreibt PPUADDR und PPUDATA, ohne Scrolleinstellungen wiederherzustellen.

Anwendungsbeispiel

c
// 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++;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel füllt zunächst alle 192 Warteschlangenbytes und lässt einen weiteren Eintrag absichtlich ablehnen. Es verwirft dieses Paket, prüft die Ablehnung von Länge 128 und reiht dann fünf Einträge ein: 145 Bytes für 255 PPU-Schreibzugriffe. Erwartet werden CAPACITY 192, ENCODED BYTES 145, AFTER FLUSH 000, REJECTED LENGTH 001, OVERFLOW SEEN 001 und FAILED CHECKS 000. Die Ablehnungsanzeigen speichern Beobachtungen aus vorherigen Programmschritten, nicht den abschließenden Flagzustand.

Die blau kopierten Tiles beginnen bei (0,16), die grüne Füllung bei (0,64). Jeder Bereich enthält 127 Tiles: drei volle Reihen und 31 Tiles in der vierten; die letzte 8×8-Zelle bleibt schwarz. Die blaue Folge wiederholt volle, halbbreite und dreieckige Tiles; das erste bleibt trotz geänderter Quelle voll. Bei y=112 bleibt das rote Quadrat bei x=16 nach Aufträgen der Länge null erhalten, das rote halbe Tile bei x=224 belegt die automatische NMI-Verarbeitung, und die verworfene Zelle bei x=248 bleibt schwarz. Geprüft werden 18.432 Pixel sowie das Ausbleiben von VRAM-Schreibzugriffen während aktiver Bildausgabe. Physische Hardware wurde nicht getestet.

nes_vram_queue_nmi_flush: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/runtime.h:51

Deklarationshinweise im Original
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

c
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

Hängt einen Fülleintrag aus vier Bytes an die C-Laufzeitwarteschlange an. Bei der Ausführung wird value genau len-mal in PPUDATA geschrieben. Das Byte wird sofort gespeichert; spätere Änderungen der aufrufenden Variablen beeinflussen die Füllung nicht. Wiederholt wird ein Byte, kein Tile-Muster.

Syntax

c
unsigned char nes_vram_queue_try_fill(unsigned short ppu_addr, unsigned char value, unsigned char len);

Parameter

ppu_addr

PPU-Byteadresse (0x0000–0x3FFF), kein CPU-Zeiger. Das Ziel muss beschreibbar sein: Musteränderungen benötigen CHR-RAM statt CHR-ROM. PPU-Adressabbildung und Spiegelung gelten weiterhin. Wählen Sie für fortlaufendes Kopieren und Füllen die Schrittweite 1 in PPUCTRL. Führen Sie Befehle zu einem sicheren PPU-Zeitpunkt aus und stellen Sie danach den Scrollzustand her; der Ausführer schreibt PPUADDR und PPUDATA, ohne Scrolleinstellungen wiederherzustellen.

value

Ein wiederholtes Byte von 0 bis 255. Seine sichtbare Wirkung hängt davon ab, ob das Ziel Tile-Indizes, Pixelebenen oder eine andere Bytestruktur enthält.

len

Anzahl der PPU-Bytes von 0 bis 127. Bit 7 des Längenbytes kennzeichnet Fülleinträge, daher werden 128–255 abgewiesen. Ein Schreibauftrag der Länge null belegt drei Warteschlangenbytes, ein leerer Füllauftrag vier. Beide setzen beim Abarbeiten die PPU-Adresse, schreiben aber nicht in PPUDATA.

Rückgabewert

Gibt 1 zurück, wenn der vollständige Eintrag angenommen wurde, sonst 0 bei ungültiger Länge oder Platzmangel. Eine Ablehnung setzt nes_vram_queue_overflow auf 1; vorhandene Einträge und belegte Länge bleiben unverändert. Das Fehlerflag bleibt bis zum Löschen gesetzt, verhindert aber keinen späteren Eintrag, der noch hineinpasst. Prüfen Sie jeden Rückgabewert.

Bedingungen und Grenzen

Dies ist eine separate 192-Byte-Warteschlange aus runtime.c an den CPU-Adressen 0x0300–0x03BF. Ein Dateneintrag belegt 3+len Bytes, ein Fülleintrag vier. nes_vram_queue_used zählt codierte Bytes, nicht ausstehende PPU-Schreibzugriffe oder freien VRAM. Die Intrinsic-Warteschlange __vramq_* verwendet ein anderes Format; diese Funktionen leeren, prüfen oder verarbeiten sie nicht.

Verwenden Sie die Deklarationen aus runtime.h und binden oder kompilieren Sie runtime.c genau einmal. Neben dieser Warteschlange stellt die Datei __nes_nmi, den Laufzeit-Bildzähler, direkte PPU-Hilfsfunktionen und OAM-Speicher auf Seite 02 bereit. Stimmen Sie die NMI-Behandlung mit Ihrem Programm ab; eine Funktionsdeklaration allein bindet keine Implementierung ein.

Trennen Sie Aufbau und Verarbeitung der Pakete; Sperren oder doppelte Puffer sind nicht vorgesehen. Für eine eindeutige Vorbereitung deaktivieren Sie NMI beim Anhängen und verarbeiten die Einträge bei abgeschalteter Bildausgabe, oder aktivieren NMI für ein Paket, das in VBlank passt. runtime.c verarbeitet eine nicht leere Warteschlange automatisch aus __nes_nmi, ohne Freigabeaufruf. Es gibt weder Zeitbudget noch Aufteilung oder Wiederherstellung des Scrollzustands. Freier Warteschlangenplatz garantiert keine sichere VBlank-Dauer.

Anwendungsbeispiel

c
if(nes_vram_queue_try_fill(0x2100,fill_value,127)!=1)failures++;
fill_value=3; // The queued fill remains the solid tile 1.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel füllt zunächst alle 192 Warteschlangenbytes und lässt einen weiteren Eintrag absichtlich ablehnen. Es verwirft dieses Paket, prüft die Ablehnung von Länge 128 und reiht dann fünf Einträge ein: 145 Bytes für 255 PPU-Schreibzugriffe. Erwartet werden CAPACITY 192, ENCODED BYTES 145, AFTER FLUSH 000, REJECTED LENGTH 001, OVERFLOW SEEN 001 und FAILED CHECKS 000. Die Ablehnungsanzeigen speichern Beobachtungen aus vorherigen Programmschritten, nicht den abschließenden Flagzustand.

Die blau kopierten Tiles beginnen bei (0,16), die grüne Füllung bei (0,64). Jeder Bereich enthält 127 Tiles: drei volle Reihen und 31 Tiles in der vierten; die letzte 8×8-Zelle bleibt schwarz. Die blaue Folge wiederholt volle, halbbreite und dreieckige Tiles; das erste bleibt trotz geänderter Quelle voll. Bei y=112 bleibt das rote Quadrat bei x=16 nach Aufträgen der Länge null erhalten, das rote halbe Tile bei x=224 belegt die automatische NMI-Verarbeitung, und die verworfene Zelle bei x=248 bleibt schwarz. Geprüft werden 18.432 Pixel sowie das Ausbleiben von VRAM-Schreibzugriffen während aktiver Bildausgabe. Physische Hardware wurde nicht getestet.

nes_vram_queue_try_fill: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/runtime.h:47

Deklarationshinweise im Original
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

c
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

Hängt einen Eintrag mit Nutzdaten an die C-Laufzeitwarteschlange an. Kopiert während dieses Aufrufs len Quellbytes in den Puffer und veröffentlicht anschließend die neue belegte Länge. Die PPU-Übertragung erfolgt beim Abarbeiten der Warteschlange. Änderungen oder Wiederverwendung der Quelle nach einem erfolgreichen Aufruf verändern die eingereihten Daten nicht.

Syntax

c
unsigned char nes_vram_queue_try_write(unsigned short ppu_addr, unsigned char* src, unsigned char len);

Parameter

ppu_addr

PPU-Byteadresse (0x0000–0x3FFF), kein CPU-Zeiger. Das Ziel muss beschreibbar sein: Musteränderungen benötigen CHR-RAM statt CHR-ROM. PPU-Adressabbildung und Spiegelung gelten weiterhin. Wählen Sie für fortlaufendes Kopieren und Füllen die Schrittweite 1 in PPUCTRL. Führen Sie Befehle zu einem sicheren PPU-Zeitpunkt aus und stellen Sie danach den Scrollzustand her; der Ausführer schreibt PPUADDR und PPUDATA, ohne Scrolleinstellungen wiederherzustellen.

src

Zeiger auf mindestens len lesbare Bytes im aktuell eingeblendeten Speicher. Die Quelle muss nur während dieses Aufrufs gültig bleiben: Der Inhalt wird kopiert, niemals verändert. Bei Länge null werden keine Quellbytes gelesen.

len

Anzahl der PPU-Bytes von 0 bis 127. Bit 7 des Längenbytes kennzeichnet Fülleinträge, daher werden 128–255 abgewiesen. Ein Schreibauftrag der Länge null belegt drei Warteschlangenbytes, ein leerer Füllauftrag vier. Beide setzen beim Abarbeiten die PPU-Adresse, schreiben aber nicht in PPUDATA.

Rückgabewert

Gibt 1 zurück, wenn der vollständige Eintrag angenommen wurde, sonst 0 bei ungültiger Länge oder Platzmangel. Eine Ablehnung setzt nes_vram_queue_overflow auf 1; vorhandene Einträge und belegte Länge bleiben unverändert. Das Fehlerflag bleibt bis zum Löschen gesetzt, verhindert aber keinen späteren Eintrag, der noch hineinpasst. Prüfen Sie jeden Rückgabewert.

Bedingungen und Grenzen

Dies ist eine separate 192-Byte-Warteschlange aus runtime.c an den CPU-Adressen 0x0300–0x03BF. Ein Dateneintrag belegt 3+len Bytes, ein Fülleintrag vier. nes_vram_queue_used zählt codierte Bytes, nicht ausstehende PPU-Schreibzugriffe oder freien VRAM. Die Intrinsic-Warteschlange __vramq_* verwendet ein anderes Format; diese Funktionen leeren, prüfen oder verarbeiten sie nicht.

Verwenden Sie die Deklarationen aus runtime.h und binden oder kompilieren Sie runtime.c genau einmal. Neben dieser Warteschlange stellt die Datei __nes_nmi, den Laufzeit-Bildzähler, direkte PPU-Hilfsfunktionen und OAM-Speicher auf Seite 02 bereit. Stimmen Sie die NMI-Behandlung mit Ihrem Programm ab; eine Funktionsdeklaration allein bindet keine Implementierung ein.

Trennen Sie Aufbau und Verarbeitung der Pakete; Sperren oder doppelte Puffer sind nicht vorgesehen. Für eine eindeutige Vorbereitung deaktivieren Sie NMI beim Anhängen und verarbeiten die Einträge bei abgeschalteter Bildausgabe, oder aktivieren NMI für ein Paket, das in VBlank passt. runtime.c verarbeitet eine nicht leere Warteschlange automatisch aus __nes_nmi, ohne Freigabeaufruf. Es gibt weder Zeitbudget noch Aufteilung oder Wiederherstellung des Scrollzustands. Freier Warteschlangenplatz garantiert keine sichere VBlank-Dauer.

Anwendungsbeispiel

c
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.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel füllt zunächst alle 192 Warteschlangenbytes und lässt einen weiteren Eintrag absichtlich ablehnen. Es verwirft dieses Paket, prüft die Ablehnung von Länge 128 und reiht dann fünf Einträge ein: 145 Bytes für 255 PPU-Schreibzugriffe. Erwartet werden CAPACITY 192, ENCODED BYTES 145, AFTER FLUSH 000, REJECTED LENGTH 001, OVERFLOW SEEN 001 und FAILED CHECKS 000. Die Ablehnungsanzeigen speichern Beobachtungen aus vorherigen Programmschritten, nicht den abschließenden Flagzustand.

Die blau kopierten Tiles beginnen bei (0,16), die grüne Füllung bei (0,64). Jeder Bereich enthält 127 Tiles: drei volle Reihen und 31 Tiles in der vierten; die letzte 8×8-Zelle bleibt schwarz. Die blaue Folge wiederholt volle, halbbreite und dreieckige Tiles; das erste bleibt trotz geänderter Quelle voll. Bei y=112 bleibt das rote Quadrat bei x=16 nach Aufträgen der Länge null erhalten, das rote halbe Tile bei x=224 belegt die automatische NMI-Verarbeitung, und die verworfene Zelle bei x=248 bleibt schwarz. Geprüft werden 18.432 Pixel sowie das Ausbleiben von VRAM-Schreibzugriffen während aktiver Bildausgabe. Physische Hardware wurde nicht getestet.

nes_vram_queue_try_write: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/runtime.h:44

Deklarationshinweise im Original
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

c
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

Wartet, bis nes_nmi_counter vom beim Eintritt gespeicherten Wert abweicht. __nes_nmi aus runtime.c erhöht diesen 8-Bit-Zähler nach dem Abarbeiten seiner Warteschlange. Der Ungleichheitsvergleich erfasst auch den Überlauf von 255 auf 0. Aktivieren Sie NMI und verwenden Sie diesen Handler oder eine gleichwertige Zähleraktualisierung. Die Schleife hat kein Zeitlimit, aktiviert NMI nicht, stellt den Bildlauf nicht wieder her und garantiert keine exakt eine Bildperiode lange Wartezeit.

Syntax

c
void nes_wait_nmi(void);

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Verwenden Sie die Deklarationen aus runtime.h und binden oder kompilieren Sie runtime.c genau einmal. Neben dieser Warteschlange stellt die Datei __nes_nmi, den Laufzeit-Bildzähler, direkte PPU-Hilfsfunktionen und OAM-Speicher auf Seite 02 bereit. Stimmen Sie die NMI-Behandlung mit Ihrem Programm ab; eine Funktionsdeklaration allein bindet keine Implementierung ein.

Anwendungsbeispiel

c
__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++;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Laufzeitbeispiel zeigt direkte Übertragung und beide Wartemethoden. Bei (0,16) erscheint ein blaues Muster aus vollen Kacheln, linken Halbflächen und Dreiecken; bei (0,96) ein gefüllter grüner Block. Jeder Block ist 256×64 Pixel groß und entsteht aus 256 Kachelbytes. Die erste blaue Kachel bleibt nach Änderung der Quelle gefüllt. Bei y=208 markieren rote Formen an x=16, 224 und 240 Adresssetzung, Schreiben mit Länge null und Füllen mit Länge null: ein 8×8-Quadrat, ein linker 4×8-Balken und ein achtzeiliges Dreieck. Beide Warteanzeigen zeigen 1, FAILED CHECKS zeigt 0.

nes_wait_nmi: Laufzeit
Laufzeit

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/runtime.h:23

Deklarationshinweise im Original
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

c
void nes_wait_nmi(void)
{
    unsigned char start;
    start = nes_nmi_counter;
    while (nes_nmi_counter == start)
    {
    }
}

scene.h — Szenenregistrierung, -wechsel und -aktualisierung

Überträgt Szenengrafik über einen gemeinsamen Übertragungszustand in die VRAM-Warteschlange. Unterscheiden Sie das Ende von step vom Abschluss der PPU-Schreibzugriffe des Warteschlangenverbrauchers.

Ruft die Handler enter, update, draw und exit einer Szenentabelle auf, um zwischen Bildschirmen wie Titelanzeige und Spiel zu wechseln.

nes_scene_stream_begin

Speichert Ziel, Quelle, Länge und Blockgröße und markiert den gemeinsamen Datenstrom als aktiv.

Syntax

c
void nes_scene_stream_begin(unsigned short ppu_addr, unsigned char* src, unsigned short len, unsigned char chunk);

Parameter

ppu_addr

PPU-Zieladresse, keine CPU-Adresse.

src

Quelle mit len Bytes; halten Sie sie lesbar, bis alle Bytes eingereiht wurden.

len

Byte-Anzahl, 0–65535; der aufrufende Code prüft auch die Grenzen des Zielbereichs.

chunk

Maximale Nutzdatenmenge je Warteschlangeneintrag: Null bedeutet 32; Werte über 127 werden auf 127 begrenzt. Dies ist keine Gesamtgrenze für einen step-Aufruf.

Rückgabewert

Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.

Bedingungen und Grenzen

Es wird nur ein Datenstrom verwaltet. Ein begin-Aufruf ersetzt ihn, storniert aber keine bereits in die Warteschlange kopierten Daten. Halten Sie Quellspeicher und ROM-Zuordnung gültig und steuern Sie step-Aufrufe sowie Warteschlangenverbrauch im aufrufenden Code.

Anwendungsbeispiel

c
nes_scene_stream_begin(0x2100,small,4,2);result[0]=nes_scene_stream_state.remaining;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel zeigt, wie ein Datenstrom in Warteschlangenblöcke kopiert und anschließend an die PPU übertragen wird. Übertragen Sie 960 Kachelbytes, 64 Attributbytes und 32 Palettenbytes für ein rotes 64×32-Rechteck bei (16,32). Ein begin-Aufruf allein aktualisiert die Anzeige nicht.

nes_scene_stream_begin: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/scene.h:47

Deklarationshinweise im Original
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

c
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

Bereitet 64 Attributbytes für Nametable-Basis+0x03C0 mit Warteschlangeneinträgen zu je 16 Bytes vor.

Syntax

c
void nes_scene_stream_begin_attr(unsigned short nt_base, unsigned char* src64);

Parameter

nt_base

PPU-Basisadresse der Nametable, beispielsweise 0x2000.

src64

64 Attributbytes; bewahren Sie sie bis zur vollständigen Einreihung auf.

Rückgabewert

Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.

Bedingungen und Grenzen

Es wird nur ein Datenstrom verwaltet. Ein begin-Aufruf ersetzt ihn, storniert aber keine bereits in die Warteschlange kopierten Daten. Halten Sie Quellspeicher und ROM-Zuordnung gültig und steuern Sie step-Aufrufe sowie Warteschlangenverbrauch im aufrufenden Code.

Anwendungsbeispiel

c
nes_scene_stream_begin_attr(0x2000,attrs);while(nes_scene_stream_step()!=0){nes_vram_queue_nmi_flush();}nes_vram_queue_nmi_flush();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel zeigt, wie ein Datenstrom in Warteschlangenblöcke kopiert und anschließend an die PPU übertragen wird. Übertragen Sie 960 Kachelbytes, 64 Attributbytes und 32 Palettenbytes für ein rotes 64×32-Rechteck bei (16,32). Ein begin-Aufruf allein aktualisiert die Anzeige nicht.

nes_scene_stream_begin_attr: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/scene.h:51

Deklarationshinweise im Original
Prepare the 64-byte attribute table at nametable base + 0x03C0.

kitaqfc/lib/scene.c:102

c
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

Bereitet die Übertragung von 960 Nametable-Kachelbytes mit Warteschlangeneinträgen zu je 32 Bytes vor.

Syntax

c
void nes_scene_stream_begin_nametable(unsigned short nt_base, unsigned char* src960);

Parameter

nt_base

PPU-Basisadresse der Nametable, beispielsweise 0x2000.

src960

960 Kachelbytes einer Nametable ohne ihre 64 Attributbytes.

Rückgabewert

Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.

Bedingungen und Grenzen

Es wird nur ein Datenstrom verwaltet. Ein begin-Aufruf ersetzt ihn, storniert aber keine bereits in die Warteschlange kopierten Daten. Halten Sie Quellspeicher und ROM-Zuordnung gültig und steuern Sie step-Aufrufe sowie Warteschlangenverbrauch im aufrufenden Code.

Anwendungsbeispiel

c
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;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel zeigt, wie ein Datenstrom in Warteschlangenblöcke kopiert und anschließend an die PPU übertragen wird. Übertragen Sie 960 Kachelbytes, 64 Attributbytes und 32 Palettenbytes für ein rotes 64×32-Rechteck bei (16,32). Ein begin-Aufruf allein aktualisiert die Anzeige nicht.

nes_scene_stream_begin_nametable: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/scene.h:49

Deklarationshinweise im Original
Prepare the 960-byte tile portion of a nametable using 32-byte queue records.

kitaqfc/lib/scene.c:96

c
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

Bereitet 32 Palettenbytes für PPU-Adresse 0x3F00 mit Warteschlangeneinträgen zu je 16 Bytes vor.

Syntax

c
void nes_scene_stream_begin_palette(unsigned char* src32);

Parameter

src32

32 Palettenbytes: 16 Hintergrund- und 16 Spritefarben; beachten Sie Farbcodegrenzen und PPU-Spiegelung.

Rückgabewert

Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.

Bedingungen und Grenzen

Es wird nur ein Datenstrom verwaltet. Ein begin-Aufruf ersetzt ihn, storniert aber keine bereits in die Warteschlange kopierten Daten. Halten Sie Quellspeicher und ROM-Zuordnung gültig und steuern Sie step-Aufrufe sowie Warteschlangenverbrauch im aufrufenden Code.

Anwendungsbeispiel

c
nes_scene_stream_begin_palette(colors);while(nes_scene_stream_step()!=0){nes_vram_queue_nmi_flush();}nes_vram_queue_nmi_flush();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel zeigt, wie ein Datenstrom in Warteschlangenblöcke kopiert und anschließend an die PPU übertragen wird. Übertragen Sie 960 Kachelbytes, 64 Attributbytes und 32 Palettenbytes für ein rotes 64×32-Rechteck bei (16,32). Ein begin-Aufruf allein aktualisiert die Anzeige nicht.

nes_scene_stream_begin_palette: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/scene.h:53

Deklarationshinweise im Original
Prepare a 32-byte palette transfer to PPU address 0x3F00.

kitaqfc/lib/scene.c:108

c
void nes_scene_stream_begin_palette(unsigned char* src32)
{
    nes_scene_stream_begin(0x3F00, src32, 32, 16);
}
nes_scene_stream_step

Kopiert die verbleibenden Daten in so viele Blöcke, wie die VRAM-Warteschlange der Laufzeitumgebung aufnehmen kann.

Syntax

c
unsigned char nes_scene_stream_step(void);

Rückgabewert

1, wenn wegen begrenzter Kapazität Daten übrig bleiben; 0, wenn alles eingereiht oder der Datenstrom inaktiv ist. Ein abgelehnter Block verschiebt weder Quelle noch Ziel, sodass ein erneuter Versuch möglich ist. Auch bei Rückgabe null können PPU-Übertragungen noch ausstehen.

Bedingungen und Grenzen

Es wird nur ein Datenstrom verwaltet. Ein begin-Aufruf ersetzt ihn, storniert aber keine bereits in die Warteschlange kopierten Daten. Halten Sie Quellspeicher und ROM-Zuordnung gültig und steuern Sie step-Aufrufe sowie Warteschlangenverbrauch im aufrufenden Code.

Anwendungsbeispiel

c
result[1]=nes_scene_stream_step();result[2]=nes_scene_stream_state.active;result[3]=nes_vram_queue_used;nes_vram_queue_nmi_flush();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel zeigt, wie ein Datenstrom in Warteschlangenblöcke kopiert und anschließend an die PPU übertragen wird. Übertragen Sie 960 Kachelbytes, 64 Attributbytes und 32 Palettenbytes für ein rotes 64×32-Rechteck bei (16,32). Ein begin-Aufruf allein aktualisiert die Anzeige nicht.

nes_scene_stream_step: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/scene.h:57

Deklarationshinweise im Original
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

c
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

Verlässt die aktive Szene, sofern vorhanden, und betritt die angeforderte Szene.

Syntax

c
void scene_change(u8 scene_id);

Parameter

scene_id

Index der zu betretenden Szene, von 0 bis count−1.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

IDs außerhalb des gültigen Bereichs werden ignoriert. Ein gültiger Wechsel führt exit aus, speichert die neue ID und das Wechselflag und führt dann enter aus. Auch die Wahl derselben ID führt exit und enter aus. Die Szenentabelle gehört dem aufrufenden Code. Halten Sie die Tabelle und die Ziele ihrer gewöhnlichen Funktionszeiger während der gesamten Verwendung gültig. Null-Callbacks werden übersprungen. Wechseln Sie innerhalb von enter- oder exit-Callbacks nicht rekursiv die Szene und ersetzen Sie dort nicht die Tabelle.

Anwendungsbeispiel

c
scene_change(0);scene_change(9);result[11]=events;result[12]=scene_was_changed();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Programm aktiviert Szene 0, ignoriert die ungültige ID 9, wechselt von 0→1 und betritt mit 1→1 dieselbe Szene erneut. Dabei prüft es die Reihenfolge der Callbacks.

scene_change: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/scene.h:33

Deklarationshinweise im Original
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

c
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

Ruft den draw-Callback der aktiven Szene einmal auf.

Syntax

c
void scene_draw();

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Ohne aktive Szene oder bei einem Null-Callback für draw bleibt der Aufruf ohne Wirkung. Das Wechselflag wird nicht gelöscht. Planen Sie Bildschirmübertragungen und Frame-Timing im Callback oder in der umgebenden Spielschleife. Die Szenentabelle gehört dem aufrufenden Code. Halten Sie die Tabelle und die Ziele ihrer gewöhnlichen Funktionszeiger während der gesamten Verwendung gültig. Null-Callbacks werden übersprungen. Wechseln Sie innerhalb von enter- oder exit-Callbacks nicht rekursiv die Szene und ersetzen Sie dort nicht die Tabelle.

Anwendungsbeispiel

c
scene_draw();result[15]=events;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Die Ereignisfolge enthält die 12 aus dem draw-Aufruf von Szene 0 und die 22 aus dem draw-Aufruf von Szene 1.

scene_draw: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/scene.h:38

Deklarationshinweise im Original
Call the active scene's draw handler if one exists; no current scene is a no-op.

kitaqfc/lib/scene.c:61

c
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

Liest die gespeicherte aktuelle Szenen-ID.

Syntax

c
u8 scene_get_current();

Rückgabewert

Gibt die gespeicherte 8-Bit-ID zurück; auch nach der Initialisierung ist sie null.

Bedingungen und Grenzen

Der Rückgabewert null allein belegt nicht, dass Szene 0 aktiv ist. Halten Sie fest, ob seit der Initialisierung bereits der erste Aufruf von scene_change() erfolgt ist.

Anwendungsbeispiel

c
result[16]=scene_get_current();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel liest nach der Aktivierung von Szene 0 den Wert null und nach dem Wechsel zu Szene 1 den Wert eins.

scene_get_current: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/scene.h:40

Deklarationshinweise im Original
Return the stored scene ID; zero is also returned before the first transition.

kitaqfc/lib/scene.c:71

c
u8 scene_get_current()
{
    return kq_scene_current;
}
scene_init

Registriert eine Szenentabelle, ohne eine Szene zu aktivieren.

Syntax

c
void scene_init(const SceneDef* scenes, u8 count);

Parameter

scenes

Array aus SceneDef-Einträgen mit den Callbacks enter, update, draw und exit.

count

Anzahl der Einträge; bei null gibt es keine gültigen Szenen-IDs.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Setzt die gespeicherte ID und das Wechselflag auf null zurück. enter wird nicht aufgerufen; aktivieren Sie eine Szene mit scene_change(). Die Szenentabelle gehört dem aufrufenden Code. Halten Sie die Tabelle und die Ziele ihrer gewöhnlichen Funktionszeiger während der gesamten Verwendung gültig. Null-Callbacks werden übersprungen. Wechseln Sie innerhalb von enter- oder exit-Callbacks nicht rekursiv die Szene und ersetzen Sie dort nicht die Tabelle.

Anwendungsbeispiel

c
scene_init(scenes,2);scene_update();scene_draw();result[9]=events;result[10]=scene_was_changed();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel registriert zwei Szenen und prüft, dass Aufrufe von update und draw vor der Aktivierung keine Ereignisse auslösen.

scene_init: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/scene.h:28

Deklarationshinweise im Original
Attach the caller-owned scene table and clear current-scene state without invoking callbacks.

kitaqfc/lib/scene.c:11

c
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

Ersetzt die Szenentabelle und lässt keine Szene aktiv.

Syntax

c
void scene_set_table(const SceneDef* scenes, u8 count);

Parameter

scenes

Array aus SceneDef-Einträgen mit den Callbacks enter, update, draw und exit.

count

Anzahl der Einträge; bei null gibt es keine gültigen Szenen-IDs.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Setzt den Zustand wie scene_init() zurück, ohne den bisherigen exit-Callback oder einen neuen enter-Callback aufzurufen. Die Szenentabelle gehört dem aufrufenden Code. Halten Sie die Tabelle und die Ziele ihrer gewöhnlichen Funktionszeiger während der gesamten Verwendung gültig. Null-Callbacks werden übersprungen. Wechseln Sie innerhalb von enter- oder exit-Callbacks nicht rekursiv die Szene und ersetzen Sie dort nicht die Tabelle.

Anwendungsbeispiel

c
scene_set_table(scenes,2);result[23]=events;result[24]=scene_was_changed();scene_draw();result[25]=events;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Nach neun Ereignissen wird die Tabelle ersetzt: Der Zähler bleibt bei neun, das Wechselflag wird null, und der folgende draw-Aufruf bleibt ohne Wirkung.

scene_set_table: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/scene.h:30

Deklarationshinweise im Original
Replace the table by resetting scene state; this does not call the old scene's exit handler.

kitaqfc/lib/scene.c:21

c
void scene_set_table(const SceneDef* scenes, u8 count)
{
    scene_init(scenes, count);
}
scene_update

Ruft den update-Callback der aktiven Szene einmal auf.

Syntax

c
void scene_update();

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Ohne aktive Szene bleibt der Aufruf ohne Wirkung. Andernfalls wird das Wechselflag vor dem Callback gelöscht, sodass ein innerhalb von update ausgelöster Wechsel anschließend weiterhin erkennbar ist. Die Szenentabelle gehört dem aufrufenden Code. Halten Sie die Tabelle und die Ziele ihrer gewöhnlichen Funktionszeiger während der gesamten Verwendung gültig. Null-Callbacks werden übersprungen. Wechseln Sie innerhalb von enter- oder exit-Callbacks nicht rekursiv die Szene und ersetzen Sie dort nicht die Tabelle.

Anwendungsbeispiel

c
scene_update();result[13]=events;result[14]=scene_was_changed();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Die update-Funktion von Szene 0 protokolliert Ereignis 11. Nach dieser regulären Aktualisierung wird das zuvor gesetzte Wechselflag von eins auf null zurückgesetzt.

scene_update: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/scene.h:36

Deklarationshinweise im Original
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

c
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

Prüft, ob derzeit ein Szenenwechsel vermerkt ist.

Syntax

c
u8 scene_was_changed();

Rückgabewert

Gibt bei gesetztem Wechselflag 1 zurück, andernfalls 0.

Bedingungen und Grenzen

Das Lesen löscht das Flag nicht. Initialisierung, Tabellenwechsel und der Beginn einer Aktualisierung der aktiven Szene löschen es. Eine ungültige Szenen-ID lässt es unverändert.

Anwendungsbeispiel

c
result[17]=scene_was_changed();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Die Prüfungen erwarten eins unmittelbar nach einem Wechsel, null nach einer regulären Aktualisierung und null nach dem Ersetzen der Tabelle.

scene_was_changed: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/scene.h:42

Deklarationshinweise im Original
Read the transition flag, which is cleared at the start of an active scene update.

kitaqfc/lib/scene.c:77

c
u8 scene_was_changed()
{
    return kq_scene_changed;
}

scroll.h — Hintergrund, Fenster und geteiltes Scrollen

Erzeugt die PPUCTRL-Nametable-Auswahl und PPUSCROLL aus 16-Bit-Weltkoordinaten. Auch Y wird in 256er-Bereiche aufgeteilt; berücksichtigen Sie daher die Bildschirmhöhe von 240 Pixeln.

nes_camera_follow_center

Zieht den Bildschirmanker von der Weltposition des Ziels ab und speichert das Ergebnis als Kamerakoordinaten.

Syntax

c
void nes_camera_follow_center(unsigned short target_x, unsigned short target_y, unsigned char center_x, unsigned char center_y);

Parameter

target_x

Welt-X des Ziels in Pixeln, 0–65535.

target_y

Welt-Y des Ziels in Pixeln, 0–65535.

center_x

Gewünschtes Bildschirm-X des Ziels, 0–255.

center_y

Gewünschtes Bildschirm-Y des Ziels, 0–255.

Rückgabewert

Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.

Bedingungen und Grenzen

Es wird ein Koordinatenpaar gemeinsam genutzt. Rufen Sie nes_scroll_apply zum Aktualisieren der Hardware auf. Negative Subtraktionsergebnisse laufen in u16 um; begrenzen Sie die Weltkanten im Spiel.

Anwendungsbeispiel

c
nes_camera_follow_center(300,260,128,120);result[4]=nes_scroll_camera_x;result[5]=nes_scroll_camera_y;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel zeigt, wie gespeicherte 16-Bit-Koordinaten PPUCTRL und Scrollwerte ergeben. Der Grundsteuerwert ist 144; Anwenden von (264,272) ergibt 147. Das Verfolgen von Ziel (300,260) mit Anker (128,120) ergibt Kamera (172,140). Separate Zustandsprüfungen untersuchen die tatsächlichen PPU-Schreibzugriffe.

nes_camera_follow_center: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr

Anwendungsbeispiel

c
nes_scroll_set_base_ctrl(0);
nes_scroll_set(264,16);
nes_scroll_apply();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Zeigen Sie auf NROM mit vertikaler Spiegelung Nametable 1 an. Ein rotes 32×16-Rechteck an Weltposition (288,32) erscheint bei Kamera (264,16) an Bildschirmposition (24,16). Dies zeigt die Tabellenauswahl über Bit 8 und das Scrolling über das untere Byte.

nes_camera_follow_center: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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=vertical
Implementierung und Quelltext

kitaqfc/lib/scroll.h:21

Deklarationshinweise im Original
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

c
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

Kombiniert gespeicherte Koordinaten mit dem PPUCTRL-Grundwert, setzt das Latch zurück und schreibt PPUCTRL sowie X/Y-Scrollwerte.

Syntax

c
void nes_scroll_apply(void);

Rückgabewert

Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.

Bedingungen und Grenzen

Bit 8 jeder Achse wählt eine Nametable; das untere Byte liefert den Scrollwert. Y-Werte von 240–255 sind keine gewöhnlichen vertikalen Scrollpositionen. Das gesamte PPUCTRL-Register wird ersetzt; initialisieren Sie NMI und die übrigen Grundbits daher bewusst. Es wird nicht auf VBlank gewartet; das Lesen von PPUSTATUS beeinflusst auch das VBlank-Flag und das gemeinsame Latch.

Anwendungsbeispiel

c
nes_scroll_apply();result[3]=nes_scroll_ctrl_base|((nes_scroll_camera_x>>8)&1)|((nes_scroll_camera_y>>7)&2);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel zeigt, wie gespeicherte 16-Bit-Koordinaten PPUCTRL und Scrollwerte ergeben. Der Grundsteuerwert ist 144; Anwenden von (264,272) ergibt 147. Das Verfolgen von Ziel (300,260) mit Anker (128,120) ergibt Kamera (172,140). Separate Zustandsprüfungen untersuchen die tatsächlichen PPU-Schreibzugriffe.

nes_scroll_apply: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr

Anwendungsbeispiel

c
nes_scroll_set_base_ctrl(0);
nes_scroll_set(264,16);
nes_scroll_apply();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Zeigen Sie auf NROM mit vertikaler Spiegelung Nametable 1 an. Ein rotes 32×16-Rechteck an Weltposition (288,32) erscheint bei Kamera (264,16) an Bildschirmposition (24,16). Dies zeigt die Tabellenauswahl über Bit 8 und das Scrolling über das untere Byte.

nes_scroll_apply: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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=vertical
Implementierung und Quelltext

kitaqfc/lib/scroll.h:18

Deklarationshinweise im Original
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

c
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

Speichert 16-Bit-Kamerakoordinaten, ohne in die PPU zu schreiben.

Syntax

c
void nes_scroll_set(unsigned short camera_x, unsigned short camera_y);

Parameter

camera_x

Horizontale Koordinate in ganzen Pixeln; beim Anwenden werden die unteren neun Bits verwendet.

camera_y

Vertikale Koordinate; beim Anwenden werden die unteren neun Bits verwendet, ohne auf die Nametable-Höhe von 240 Pixeln zu normieren.

Rückgabewert

Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.

Bedingungen und Grenzen

Es wird ein Koordinatenpaar gemeinsam genutzt. Rufen Sie nes_scroll_apply zum Aktualisieren der Hardware auf. Negative Subtraktionsergebnisse laufen in u16 um; begrenzen Sie die Weltkanten im Spiel.

Anwendungsbeispiel

c
nes_scroll_set(264,272);result[1]=nes_scroll_camera_x;result[2]=nes_scroll_camera_y;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel zeigt, wie gespeicherte 16-Bit-Koordinaten PPUCTRL und Scrollwerte ergeben. Der Grundsteuerwert ist 144; Anwenden von (264,272) ergibt 147. Das Verfolgen von Ziel (300,260) mit Anker (128,120) ergibt Kamera (172,140). Separate Zustandsprüfungen untersuchen die tatsächlichen PPU-Schreibzugriffe.

nes_scroll_set: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr

Anwendungsbeispiel

c
nes_scroll_set_base_ctrl(0);
nes_scroll_set(264,16);
nes_scroll_apply();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Zeigen Sie auf NROM mit vertikaler Spiegelung Nametable 1 an. Ein rotes 32×16-Rechteck an Weltposition (288,32) erscheint bei Kamera (264,16) an Bildschirmposition (24,16). Dies zeigt die Tabellenauswahl über Bit 8 und das Scrolling über das untere Byte.

nes_scroll_set: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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=vertical
Implementierung und Quelltext

kitaqfc/lib/scroll.h:12

Deklarationshinweise im Original
Store camera coordinates without touching hardware registers.

kitaqfc/lib/scroll.c:25

c
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

Speichert den PPUCTRL-Grundwert mit gelöschten zwei Bits zur Nametable-Auswahl.

Syntax

c
void nes_scroll_set_base_ctrl(unsigned char ctrl);

Parameter

ctrl

PPUCTRL-Wert mit NMI-, Mustertabellen- und Inkrementeinstellungen; die unteren zwei Bits werden aus den Koordinaten abgeleitet.

Rückgabewert

Kein Rückgabewert. Der betroffene Zustand und der Zeitpunkt der Wirkung werden in diesem Eintrag beschrieben.

Bedingungen und Grenzen

Es wird ein Koordinatenpaar gemeinsam genutzt. Rufen Sie nes_scroll_apply zum Aktualisieren der Hardware auf. Negative Subtraktionsergebnisse laufen in u16 um; begrenzen Sie die Weltkanten im Spiel.

Anwendungsbeispiel

c
nes_scroll_set_base_ctrl(0x93);result[0]=nes_scroll_ctrl_base;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel zeigt, wie gespeicherte 16-Bit-Koordinaten PPUCTRL und Scrollwerte ergeben. Der Grundsteuerwert ist 144; Anwenden von (264,272) ergibt 147. Das Verfolgen von Ziel (300,260) mit Anker (128,120) ergibt Kamera (172,140). Separate Zustandsprüfungen untersuchen die tatsächlichen PPU-Schreibzugriffe.

nes_scroll_set_base_ctrl: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr

Anwendungsbeispiel

c
nes_scroll_set_base_ctrl(0);
nes_scroll_set(264,16);
nes_scroll_apply();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Zeigen Sie auf NROM mit vertikaler Spiegelung Nametable 1 an. Ein rotes 32×16-Rechteck an Weltposition (288,32) erscheint bei Kamera (264,16) an Bildschirmposition (24,16). Dies zeigt die Tabellenauswahl über Bit 8 und das Scrolling über das untere Byte.

nes_scroll_set_base_ctrl: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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=vertical
Implementierung und Quelltext

kitaqfc/lib/scroll.h:10

Deklarationshinweise im Original
Store PPUCTRL bits other than the two nametable-selection bits for later application.

kitaqfc/lib/scroll.c:19

c
void nes_scroll_set_base_ctrl(unsigned char ctrl)
{
    nes_scroll_ctrl_base = (unsigned char)(ctrl & 0xFC);
}

sprite.h — OBJ-Reservierung, Positionierung, Metasprites und Animation

Sprites sind bewegliche Hardwareobjekte, meist 8×8 oder 8×16 Pixel groß, die durch Einträge im Object Attribute Memory (OAM) beschrieben werden. Reservieren Sie Einträge, setzen Sie Position, Tile und Attribute im Arbeitspuffer und übertragen Sie ihn anschließend. Ein Metasprite fasst mehrere Einträge zu einem Objekt zusammen. GB bietet 40 Einträge mit höchstens 10 pro Zeile; FC bietet 64 mit höchstens 8 pro Zeile.

FC-Attribute: Bits 0..1 wählen eine von vier Paletten, Bit 5 legt das Sprite hinter Hintergrundpixel mit Index ungleich null, Bits 6/7 spiegeln X/Y. Unbenutzte Bits 2..4 bleiben null. Die Werte unterscheiden sich von GB; verwenden Sie die Konstanten der jeweiligen Plattform.

anim_update

Erhöht den SpriteAnim-Zähler und gibt die gewählte Tile-Nummer zurück. Nach ticks_per_frame Aufrufen folgt das nächste fortlaufende Tile; nach frame_count Bildern beginnt die Folge von vorn. Der Aufrufer übernimmt das Ergebnis mit sprite_set_tile.

Syntax

c
u8 anim_update(SpriteAnim* anim);

Parameter

anim

Beschreibbarer SpriteAnim-Zustand mit first_tile, frame_count, frame, ticks und ticks_per_frame. Bei Grenzen ungleich null muss frame kleiner als frame_count und ticks kleiner als ticks_per_frame sein.

Rückgabewert

Gewählte 8-Bit-Tile-Nummer; 0 bei einem Nullzeiger. Die Funktion schreibt nicht in das OAM.

Bedingungen und Grenzen

frame_count=0 liefert first_tile ohne Fortschritt; ticks_per_frame=0 hält das aktuelle Bild fest. Der Zähler zählt Aufrufe, keine Videobilder. Tile-Nummern laufen nach 255 über und steigen auch im 8×16-Modus jeweils nur um eins.

Anwendungsbeispiel

c
sprite_example_animation.first_tile=128;sprite_example_animation.frame_count=2;
sprite_example_animation.frame=0;sprite_example_animation.ticks=0;
sprite_example_animation.ticks_per_frame=2;
sprite_example_expect(anim_update(&sprite_example_animation)==128);
tile=anim_update(&sprite_example_animation);
sprite_example_expect(tile==129);sprite_set_tile(5,tile);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Bei first_tile=128, zwei Bildern und zwei Aufrufen pro Bild liefert die erste Aktualisierung Pfeil-Tile 128 und die zweite Quadrat-Tile 129. Das Quadrat neben ANIMATION zeigt, dass das Ergebnis ins OAM übernommen wurde.

Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.

NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.

Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.

Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.

anim_update: NTSC
NTSC

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/sprite.h:74

Deklarationshinweise im Original
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

c
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

Platziert eine angegebene Anzahl von Sprite-Teilen in aufeinanderfolgenden Einträgen. Jeder Teil enthält vorzeichenbehaftete Versätze, Tile und Attribute. Freie Einträge werden aktiviert, aktive überschrieben; am Eintragslimit endet die Ausgabe.

Syntax

c
u8 metasprite_draw(u8 first_id, u8 x, u8 y, const MetaSpritePart* parts, u8 count);

Parameter

first_id

Eintrags-ID von 0 bis SPRITE_MAX-1, standardmäßig 0..39 auf GB und 0..63 auf FC. Ungültige IDs werden ignoriert.

x

Horizontale Position in Pixeln als vorzeichenloses Byte; keine Tile-Koordinate.

y

Y-Byte des OAM. Für eine Oberkante unterhalb der Zeile null wird ihre Position minus eins übergeben; 239..255 liegen außerhalb der 240 sichtbaren Zeilen.

parts

Lesbares Array mit mindestens count MetaSpritePart-Einträgen. Jeder vier Byte große Eintrag enthält vorzeichenbehaftete dx/dy-Werte, Tile und Attribute; es gibt keine Endmarkierung.

count

Anzahl der Teile als vorzeichenloses Byte. Null bewirkt keine Schreibzugriffe. Beim Erreichen von SPRITE_MAX werden nur die bis dahin passenden Teile geschrieben.

Rückgabewert

Zahl geschriebener Teile von 0 bis count. Daran lässt sich erkennen, ob die Ausgabe am Eintragslimit gekürzt wurde.

Bedingungen und Grenzen

Position, Tile, Attribute und Ausblenden ändern nur den Arbeitspuffer. Sie reservieren keine Einträge und aktualisieren das Hardware-OAM nicht sofort. Übertragen Sie das vorbereitete Bild mit sprite_flush_oam.

Die vorzeichenbehafteten Byte-Versätze werden zur Basisposition addiert; das Ergebnis läuft auf acht Bit über. Das Teilearray muss während des Aufrufs lesbar bleiben. Aktive Einträge werden überschrieben, auch wenn sie zu einem anderen Objekt gehören.

Anwendungsbeispiel

c
sprite_example_expect(metasprite_draw(10,88,SPRITE_EXAMPLE_Y(64),sprite_example_pair,2)==2);
sprite_example_expect(sprite_count_used()==9); // Sparse IDs count actual active slots.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Nach der Initialisierung sind null Einträge reserviert. Acht Reservierungen liefern 0..7. Ausblenden von Eintrag 6 belässt den Zähler bei 8; zweimalige Freigabe von 7 ergibt 7. Das Paar in Einträgen 10 und 11 erhöht ihn auf 9.

Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.

NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.

Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.

Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.

metasprite_draw: NTSC
NTSC

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/sprite.h:71

Deklarationshinweise im Original
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

c
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

Reserviert den ersten freien Sprite-Eintrag und blendet ihn bis zur Positionierung aus. Ein ausgeblendeter Eintrag bleibt reserviert. Legen Sie vor der Anzeige Tile und Attribute fest.

Syntax

c
u8 sprite_alloc(void);

Rückgabewert

ID des reservierten Eintrags oder 0xFF, wenn alle Einträge aktiv sind.

Bedingungen und Grenzen

Position, Tile, Attribute und Ausblenden ändern nur den Arbeitspuffer. Sie reservieren keine Einträge und aktualisieren das Hardware-OAM nicht sofort. Übertragen Sie das vorbereitete Bild mit sprite_flush_oam.

Anwendungsbeispiel

c
for(i=0;i<8;i++) sprite_example_expect(sprite_alloc()==i);
sprite_example_expect(sprite_count_used()==8);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Nach der Initialisierung sind null Einträge reserviert. Acht Reservierungen liefern 0..7. Ausblenden von Eintrag 6 belässt den Zähler bei 8; zweimalige Freigabe von 7 ergibt 7. Das Paar in Einträgen 10 und 11 erhöht ihn auf 9.

Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.

NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.

Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.

Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.

sprite_alloc: NTSC
NTSC

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/sprite.h:45

Deklarationshinweise im Original
Claim and hide the first free slot, or return 0xFF if all slots are active.

kitaqfc/lib/sprite.c:35

c
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

Gibt die Zahl reservierter Einträge zurück, einschließlich ausgeblendeter Sprites und durch metasprite_draw aktivierter Einträge. Gezählt werden Reservierungen, keine sichtbaren Sprites.

Syntax

c
u8 sprite_count_used(void);

Rückgabewert

Vorzeichenloser Bytewert von 0 bis SPRITE_MAX.

Anwendungsbeispiel

c
sprite_example_expect(sprite_count_used()==9); // After hiding, freeing and drawing the pair.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Nach der Initialisierung sind null Einträge reserviert. Acht Reservierungen liefern 0..7. Ausblenden von Eintrag 6 belässt den Zähler bei 8; zweimalige Freigabe von 7 ergibt 7. Das Paar in Einträgen 10 und 11 erhöht ihn auf 9.

Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.

NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.

Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.

Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.

sprite_count_used: NTSC
NTSC

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/sprite.h:62

Deklarationshinweise im Original
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

c
u8 sprite_count_used(void)
{
    return kq_sprite_used;
}
sprite_flush_oam

Wartet auf den nächsten Stand des NMI-Bildzählers und überträgt dann die 256 Byte große OAM-Seite. NMI muss aktiviert sein, und der Handler muss diesen Zähler aktualisieren.

Syntax

c
void sprite_flush_oam(void);

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Die FC-Routine setzt OAMADDR auf null und startet DMA aus CPU-Seite $02 ($0200–$02FF). Verwenden Sie sie während VBlank oder bei abgeschalteter Darstellung; vermeiden Sie gleichzeitige Änderungen derselben Seite durch Interrupt-Code.

Anwendungsbeispiel

c
while(1) { sprite_flush_oam(); } // Transfer prepared sprites at the next frame boundary.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.

Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.

Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.

Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.

sprite_flush_oam: NTSC
NTSC

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/sprite.h:59

Deklarationshinweise im Original
Wait for NMI before requesting OAM DMA.

kitaqfc/lib/sprite.c:100

c
void sprite_flush_oam(void)
{
    __nmi_wait();
    __oam_dma();
}
sprite_flush_oam_now

Überträgt den OAM-Arbeitspuffer sofort an die Hardware. Die Routine wartet nicht auf einen sicheren Anzeigezeitraum; der aufrufende Code bestimmt den Zeitpunkt.

Syntax

c
void sprite_flush_oam_now(void);

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Die FC-Routine setzt OAMADDR auf null und startet DMA aus CPU-Seite $02 ($0200–$02FF). Verwenden Sie sie während VBlank oder bei abgeschalteter Darstellung; vermeiden Sie gleichzeitige Änderungen derselben Seite durch Interrupt-Code.

Anwendungsbeispiel

c
// Rendering is disabled here; all shadow entries have been prepared.
sprite_flush_oam_now();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.

Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.

Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.

Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.

sprite_flush_oam_now: NTSC
NTSC

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/sprite.h:57

Deklarationshinweise im Original
Transfer intrinsic shadow OAM immediately; this wrapper does not wait for VBlank.

kitaqfc/lib/sprite.c:94

c
void sprite_flush_oam_now(void)
{
    __oam_dma();
}
sprite_free

Gibt einen reservierten Eintrag frei, blendet ihn aus und verringert die Zahl aktiver Einträge um eins. Ungültige IDs und bereits freie Einträge bleiben ohne Wirkung.

Syntax

c
void sprite_free(u8 id);

Parameter

id

Eintrags-ID von 0 bis SPRITE_MAX-1, standardmäßig 0..39 auf GB und 0..63 auf FC. Ungültige IDs werden ignoriert.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Position, Tile, Attribute und Ausblenden ändern nur den Arbeitspuffer. Sie reservieren keine Einträge und aktualisieren das Hardware-OAM nicht sofort. Übertragen Sie das vorbereitete Bild mit sprite_flush_oam.

Anwendungsbeispiel

c
sprite_free(7);sprite_free(7);
sprite_example_expect(sprite_count_used()==7); // Repeated release is ignored.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Nach der Initialisierung sind null Einträge reserviert. Acht Reservierungen liefern 0..7. Ausblenden von Eintrag 6 belässt den Zähler bei 8; zweimalige Freigabe von 7 ergibt 7. Das Paar in Einträgen 10 und 11 erhöht ihn auf 9.

Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.

NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.

Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.

Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.

sprite_free: NTSC
NTSC

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/sprite.h:47

Deklarationshinweise im Original
Release an active valid slot and hide it; invalid/repeated frees are ignored.

kitaqfc/lib/sprite.c:52

c
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

Blendet ein Sprite durch Änderung seiner Position im Arbeitspuffer aus. Reservierung, Tile und Attribute bleiben erhalten. Eine sichtbare Position blendet es ohne erneute Reservierung wieder ein.

Syntax

c
void sprite_hide(u8 id);

Parameter

id

Eintrags-ID von 0 bis SPRITE_MAX-1, standardmäßig 0..39 auf GB und 0..63 auf FC. Ungültige IDs werden ignoriert.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Position, Tile, Attribute und Ausblenden ändern nur den Arbeitspuffer. Sie reservieren keine Einträge und aktualisieren das Hardware-OAM nicht sofort. Übertragen Sie das vorbereitete Bild mit sprite_flush_oam.

Anwendungsbeispiel

c
sprite_hide(6);
sprite_example_expect(sprite_count_used()==8); // Hiding retains allocation.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Nach der Initialisierung sind null Einträge reserviert. Acht Reservierungen liefern 0..7. Ausblenden von Eintrag 6 belässt den Zähler bei 8; zweimalige Freigabe von 7 ergibt 7. Das Paar in Einträgen 10 und 11 erhöht ihn auf 9.

Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.

NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.

Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.

Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.

sprite_hide: NTSC
NTSC

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/sprite.h:55

Deklarationshinweise im Original
Mark the software position off screen and hide its OAM entry without freeing it.

kitaqfc/lib/sprite.c:85

c
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

Setzt die Sprite-Verwaltung zurück und blendet alle Einträge im OAM-Arbeitspuffer aus. Die im Programm gespeicherte Höhe wird auf 8 Pixel gesetzt. Hardwaregröße und OAM-Übertragung werden separat eingerichtet.

Syntax

c
void sprite_init(void);

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Auf FC werden Reservierungen und verwaltete Koordinaten zurückgesetzt; beim Ausblenden bleiben Tile- und Attributbytes erhalten. SPRITE_MAX muss zwischen 1 und 64 liegen.

Anwendungsbeispiel

c
sprite_init();
sprite_example_expect(sprite_count_used()==0);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Nach der Initialisierung sind null Einträge reserviert. Acht Reservierungen liefern 0..7. Ausblenden von Eintrag 6 belässt den Zähler bei 8; zweimalige Freigabe von 7 ergibt 7. Das Paar in Einträgen 10 und 11 erhöht ihn auf 9.

Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.

NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.

Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.

Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.

sprite_init: NTSC
NTSC

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/sprite.h:43

Deklarationshinweise im Original
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

c
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

Ermittelt aus den verwalteten Y-Positionen und kq_sprite_height die größte Zahl aktiver Sprites auf einer sichtbaren Bildschirmzeile.

Syntax

c
u8 sprite_max_scanline_count(void);

Rückgabewert

Vorzeichenloser Bytewert von 0 bis SPRITE_MAX.

Bedingungen und Grenzen

Setzen Sie kq_sprite_height auf die Hardwarehöhe 8 oder 16. Transparenz, horizontale Sichtbarkeit und Hardwarepriorität werden nicht berücksichtigt. FC verwendet die Bibliothekskoordinaten; direkte Änderungen durch OAM-Intrinsics gehen nicht in die Schätzung ein.

Anwendungsbeispiel

c
sprite_example_expect(sprite_max_scanline_count()==SPRITE_EXAMPLE_LINE_COUNT);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.

Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.

NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.

Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.

sprite_max_scanline_count: NTSC
NTSC

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/sprite.h:67

Deklarationshinweise im Original
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

c
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

Ersetzt das gesamte Attributbyte. Kombinieren Sie die Konstanten der Plattform für Spiegelung, Palette und Hintergrundpriorität. Nicht gesetzte Bits werden gelöscht.

Syntax

c
void sprite_set_flags(u8 id, u8 flags);

Parameter

id

Eintrags-ID von 0 bis SPRITE_MAX-1, standardmäßig 0..39 auf GB und 0..63 auf FC. Ungültige IDs werden ignoriert.

flags

Vollständiges Attributbyte aus den SPRITE_FLAG_*-Konstanten der Plattform. Mehrere Flags werden mit bitweisem ODER (|) kombiniert.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Position, Tile, Attribute und Ausblenden ändern nur den Arbeitspuffer. Sie reservieren keine Einträge und aktualisieren das Hardware-OAM nicht sofort. Übertragen Sie das vorbereitete Bild mit sprite_flush_oam.

FC-Attribute: Bits 0..1 wählen eine von vier Paletten, Bit 5 legt das Sprite hinter Hintergrundpixel mit Index ungleich null, Bits 6/7 spiegeln X/Y. Unbenutzte Bits 2..4 bleiben null. Die Werte unterscheiden sich von GB; verwenden Sie die Konstanten der jeweiligen Plattform.

Anwendungsbeispiel

c
sprite_set_flags(1,SPRITE_FLAG_XFLIP);
sprite_set_flags(2,SPRITE_FLAG_YFLIP);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.

Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.

Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.

Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.

sprite_set_flags: NTSC
NTSC

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/sprite.h:53

Deklarationshinweise im Original
Replace the hardware attribute byte of a valid OAM slot.

kitaqfc/lib/sprite.c:78

c
void sprite_set_flags(u8 id, u8 flags)
{
    if (sprite_valid(id) == 0) return;
    __sprite_attr(id, flags);
}
sprite_set_pos

Aktualisiert die verwaltete Position und die OAM-Koordinaten des FC-Sprites. X ist die Bildschirmposition; Y ist der OAM-Bytewert. Für eine sichtbare Oberkante bei Pixel 32 wird Y=31 übergeben.

Syntax

c
void sprite_set_pos(u8 id, u8 x, u8 y);

Parameter

id

Eintrags-ID von 0 bis SPRITE_MAX-1, standardmäßig 0..39 auf GB und 0..63 auf FC. Ungültige IDs werden ignoriert.

x

Horizontale Position in Pixeln als vorzeichenloses Byte; keine Tile-Koordinate.

y

Y-Byte des OAM. Für eine Oberkante unterhalb der Zeile null wird ihre Position minus eins übergeben; 239..255 liegen außerhalb der 240 sichtbaren Zeilen.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Position, Tile, Attribute und Ausblenden ändern nur den Arbeitspuffer. Sie reservieren keine Einträge und aktualisieren das Hardware-OAM nicht sofort. Übertragen Sie das vorbereitete Bild mit sprite_flush_oam.

Koordinaten werden mit acht Bit addiert und laufen modulo 256 über; die Bibliothek schneidet nicht am Bildschirmrand ab. Gültige Einträge sind auch ohne Reservierung bearbeitbar.

Anwendungsbeispiel

c
sprite_set_pos(0,88,SPRITE_EXAMPLE_Y(16)); // Visible top-left: (88,16).

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.

Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.

Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.

Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.

sprite_set_pos: NTSC
NTSC

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/sprite.h:49

Deklarationshinweise im Original
Update software coordinates and the intrinsic OAM position for a valid slot.

kitaqfc/lib/sprite.c:62

c
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

Ersetzt die Tile-Nummer eines OAM-Eintrags. Damit werden bereits im Tile-Speicher liegende Grafiken ausgewählt; Grafikdaten werden weder geladen noch Sprite-Einträge reserviert.

Syntax

c
void sprite_set_tile(u8 id, u8 tile);

Parameter

id

Eintrags-ID von 0 bis SPRITE_MAX-1, standardmäßig 0..39 auf GB und 0..63 auf FC. Ungültige IDs werden ignoriert.

tile

8-Bit-Tile-Nummer. Die Grafik muss vorher geladen werden. Die Hardware-Regeln für 8×16-Sprites gelten weiterhin; die Nummer wird nicht für Tile-Paare angepasst.

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

Position, Tile, Attribute und Ausblenden ändern nur den Arbeitspuffer. Sie reservieren keine Einträge und aktualisieren das Hardware-OAM nicht sofort. Übertragen Sie das vorbereitete Bild mit sprite_flush_oam.

Anwendungsbeispiel

c
sprite_set_tile(5,129); // Select the green square beside ANIMATION.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Bei first_tile=128, zwei Bildern und zwei Aufrufen pro Bild liefert die erste Aktualisierung Pfeil-Tile 128 und die zweite Quadrat-Tile 129. Das Quadrat neben ANIMATION zeigt, dass das Ergebnis ins OAM übernommen wurde.

Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.

NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.

Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.

Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.

sprite_set_tile: NTSC
NTSC

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/sprite.h:51

Deklarationshinweise im Original
Replace the tile byte of a valid OAM slot without changing allocation state.

kitaqfc/lib/sprite.c:71

c
void sprite_set_tile(u8 id, u8 tile)
{
    if (sprite_valid(id) == 0) return;
    __sprite_tile(id, tile);
}
sprite_warn_scanline_overflow

Vergleicht sprite_max_scanline_count mit dem Zeilenlimit von 10 Sprites auf GB beziehungsweise 8 auf FC. Das Ergebnis ist eine Softwareschätzung; das Hardware-Überlaufbit wird nicht gelesen.

Syntax

c
u8 sprite_warn_scanline_overflow(void);

Rückgabewert

1 bei Überschreitung des Zeilenlimits, sonst 0.

Bedingungen und Grenzen

Setzen Sie kq_sprite_height auf die Hardwarehöhe 8 oder 16. Transparenz, horizontale Sichtbarkeit und Hardwarepriorität werden nicht berücksichtigt. FC verwendet die Bibliothekskoordinaten; direkte Änderungen durch OAM-Intrinsics gehen nicht in die Schätzung ein.

Anwendungsbeispiel

c
sprite_example_expect(sprite_warn_scanline_overflow()==1);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Die Reihe unter SCAN LIMIT beginnt bei (8,128). Das Programm übergibt dort 11 GB- beziehungsweise 9 FC-Sprites, absichtlich eines zu viel. Sichtbar sein müssen 10 Pfeile auf GB und 8 auf FC; der zuletzt übergebene fehlt. Die Softwareprüfungen müssen trotzdem den Höchstwert 11/9 und das Warnsignal 1 liefern.

Das Programm zeigt Reservierung, Positionierung, Spiegelung, zusammengesetzte Objekte, Überlagerung, Animation und Zeilenlimit. Die beiden Ziffern oben rechts müssen 00 sein: Alle internen Prüfungen sind erfüllt. Jeder Pfeil und jedes Quadrat belegt ein 8×8-Tile.

NORMAL zeigt einen Rechtspfeil bei (88,16). FLIP X zeigt bei (88,32) nach links; FLIP Y spiegelt den Pfeil bei (88,48) vertikal. META setzt zwei Pfeile bei (88,64) und (96,64). Unter OVERLAP liegt der Pfeil bei (88,80) vor dem Quadrat bei (92,80), das durch transparente Pfeilpixel sichtbar bleibt. ANIMATION zeigt das Quadrat bei (88,96). Die Bereiche (120,16) und (120,32) bleiben nach Ausblenden und Freigabe leer.

Auf CGB und FC haben die Pfeile einen grünen Schaft, rote Konturen und blaue Details an der Spitze; das Quadrat ist grün. Transparente Pixel zeigen den weißen GB- beziehungsweise schwarzen FC-Hintergrund. DMG ersetzt Rot, Grün und Blau durch Hellgrau, Dunkelgrau und Schwarz.

sprite_warn_scanline_overflow: NTSC
NTSC

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/sprite.h:64

Deklarationshinweise im Original
Flag software overlap estimates above eight sprites on one scanline.

kitaqfc/lib/sprite.c:143

c
u8 sprite_warn_scanline_overflow(void)
{
    return (u8)(sprite_max_scanline_count() > 8);
}

system.h — Start, Bildzähler, Wartefunktionen und Interrupts

Verwaltet Frame-Wartezähler, Callbacks nach dem Warten und die Steuerung maskierbarer CPU-Interrupts.

fc_frame_count

fc_frame_count ist ein Alias für system_get_frame. Liest den 16-Bit-Softwarezähler der abgeschlossenen Warteaufrufe des Wrappers.

Liest den 16-Bit-Zähler der Frame-Wartefunktion.

Syntax

c
u16 fc_frame_count(void);

Rückgabewert

Gibt den aktuellen Zählerstand von 0 bis 65535 zurück.

Bedingungen und Grenzen

Der Header definiert ein objektartiges Makro, das zum Implementierungsnamen expandiert. Argumente, Rückgabewerte und Zustandszugriffe entsprechen dem Ziel; der Alias fügt keinen eigenen Zustand oder Verarbeitungsschritt hinzu. Verwenden Sie wie im vollständigen Beispiel und Buildbefehl input.h/input.c für Eingaben oder system.h/system.c für Framedienste.

Der Zähler zählt Wartevorgänge über diese Wrapper-Funktion, nicht automatisch die tatsächlich verstrichenen Hardware-Frames. Beim Überlauf nach 16 Bits beginnt er wieder bei null.

Die FC-Initialisierung aktiviert NMI. Das Warten setzt eine funktionierende NMI-Zustellung voraus. Das Maskieren von CPU-IRQs hält NMI nicht an.

system_get_frame

Anwendungsbeispiel

c
result[3]=fc_frame_count();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel liest nach drei Wartevorgängen drei. Für den Überlauftest wird der Zähler ausdrücklich auf 65535 gesetzt und nach dem nächsten Wartevorgang auf null geprüft.

fc_frame_count: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/system.h:30

c
#define fc_frame_count system_get_frame

kitaqfc/lib/system.c:30

c
u16 system_get_frame(void)
{
    return kq_system_frame;
}
fc_init

fc_init ist ein Alias für system_init. Setzt den Software-Framezähler und die Callback-Registrierung zurück.

Initialisiert die Frame-Verwaltung, indem Zähler und registrierter Callback gelöscht werden.

Syntax

c
void fc_init(void);

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Der Header definiert ein objektartiges Makro, das zum Implementierungsnamen expandiert. Argumente, Rückgabewerte und Zustandszugriffe entsprechen dem Ziel; der Alias fügt keinen eigenen Zustand oder Verarbeitungsschritt hinzu. Verwenden Sie wie im vollständigen Beispiel und Buildbefehl input.h/input.c für Eingaben oder system.h/system.c für Framedienste.

Der Zähler zählt Wartevorgänge über diese Wrapper-Funktion, nicht automatisch die tatsächlich verstrichenen Hardware-Frames. Beim Überlauf nach 16 Bits beginnt er wieder bei null.

Die FC-Initialisierung aktiviert NMI. Das Warten setzt eine funktionierende NMI-Zustellung voraus. Das Maskieren von CPU-IRQs hält NMI nicht an.

system_init

Anwendungsbeispiel

c
fc_init();result[0]=fc_frame_count();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel bestätigt vor dem Registrieren des Callbacks, dass die anfängliche Frame-Nummer null ist.

fc_init: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/system.h:27

c
#define fc_init system_init

kitaqfc/lib/system.c:7

c
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 ist ein Alias für system_set_vblank_callback. Registriert oder entfernt den nach dem Framewarten synchron aufgerufenen Callback.

Registriert, ersetzt oder entfernt die nach einem Frame-Wartevorgang aufgerufene Funktion.

Syntax

c
void fc_set_vblank_callback(SystemCallback callback);

Parameter

callback

Aufzurufende Funktion; 0 entfernt den Callback.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Der Header definiert ein objektartiges Makro, das zum Implementierungsnamen expandiert. Argumente, Rückgabewerte und Zustandszugriffe entsprechen dem Ziel; der Alias fügt keinen eigenen Zustand oder Verarbeitungsschritt hinzu. Verwenden Sie wie im vollständigen Beispiel und Buildbefehl input.h/input.c für Eingaben oder system.h/system.c für Framedienste.

Dies ist ein gewöhnlicher Zeiger auf eine Funktion ohne Parameter und Rückgabewert. Er enthält keine Banknummer; der Zielcode muss eingeblendet bleiben, solange Aufrufe möglich sind.

Die FC-Initialisierung aktiviert NMI. Das Warten setzt eine funktionierende NMI-Zustellung voraus. Das Maskieren von CPU-IRQs hält NMI nicht an.

system_set_vblank_callback

Anwendungsbeispiel

c
fc_set_vblank_callback(on_frame);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Nach drei Callback-Aufrufen deaktiviert die Registrierung von 0 den Aufruf. Der nächste Wartevorgang erhöht den Frame-Zähler auf vier, während die Callback-Anzahl drei bleibt.

fc_set_vblank_callback: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/system.h:29

c
#define fc_set_vblank_callback system_set_vblank_callback

kitaqfc/lib/system.c:24

c
void system_set_vblank_callback(SystemCallback callback)
{
    system_vblank_callback = callback;
}
fc_wait_vblank

fc_wait_vblank ist ein Alias für system_wait_vblank. Wartet auf die Framegrenze, erhöht den Software-Framezähler und ruft den registrierten Callback auf.

Wartet auf den nächsten Frame, erhöht den Zähler und ruft anschließend den registrierten Callback auf.

Syntax

c
void fc_wait_vblank(void);

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Der Header definiert ein objektartiges Makro, das zum Implementierungsnamen expandiert. Argumente, Rückgabewerte und Zustandszugriffe entsprechen dem Ziel; der Alias fügt keinen eigenen Zustand oder Verarbeitungsschritt hinzu. Verwenden Sie wie im vollständigen Beispiel und Buildbefehl input.h/input.c für Eingaben oder system.h/system.c für Framedienste.

Der Callback läuft synchron innerhalb dieser Funktion; seine Registrierung installiert keinen Interrupt-Handler. Der Zähler zählt die Wartevorgänge dieses Wrappers und misst nicht automatisch die verstrichenen Hardware-Frames. Beim 16-Bit-Überlauf beginnt er wieder bei null.

Die FC-Initialisierung aktiviert NMI. Das Warten setzt eine funktionierende NMI-Zustellung voraus. Das Maskieren von CPU-IRQs hält NMI nicht an.

system_wait_vblank

Anwendungsbeispiel

c
fc_wait_vblank();fc_wait_vblank();fc_wait_vblank();result[1]=frame_calls;result[2]=frame_seen;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Drei Wartevorgänge rufen den Callback dreimal auf; der zuletzt darin gelesene Zählerstand beträgt drei.

fc_wait_vblank: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/system.h:28

c
#define fc_wait_vblank system_wait_vblank

kitaqfc/lib/system.c:16

c
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 ist ein Alias für system_get_frame. Liest den 16-Bit-Softwarezähler der abgeschlossenen Warteaufrufe des Wrappers.

Liest den 16-Bit-Zähler der Frame-Wartefunktion.

Syntax

c
u16 gb_frame_count(void);

Rückgabewert

Gibt den aktuellen Zählerstand von 0 bis 65535 zurück.

Bedingungen und Grenzen

Der Header definiert ein objektartiges Makro, das zum Implementierungsnamen expandiert. Argumente, Rückgabewerte und Zustandszugriffe entsprechen dem Ziel; der Alias fügt keinen eigenen Zustand oder Verarbeitungsschritt hinzu. Verwenden Sie wie im vollständigen Beispiel und Buildbefehl input.h/input.c für Eingaben oder system.h/system.c für Framedienste.

Dies ist die von der FC-Bibliothek angebotene gb_-Schreibweise. Sie ruft die FC-Implementierung system_* auf, keine Game-Boy-Hardware. Der entsprechende fc_-Name ruft dieselbe FC-Implementierung auf.

Der Zähler zählt Wartevorgänge über diese Wrapper-Funktion, nicht automatisch die tatsächlich verstrichenen Hardware-Frames. Beim Überlauf nach 16 Bits beginnt er wieder bei null.

Die FC-Initialisierung aktiviert NMI. Das Warten setzt eine funktionierende NMI-Zustellung voraus. Das Maskieren von CPU-IRQs hält NMI nicht an.

system_get_frame

Anwendungsbeispiel

c
result[3]=gb_frame_count();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel liest nach drei Wartevorgängen drei. Für den Überlauftest wird der Zähler ausdrücklich auf 65535 gesetzt und nach dem nächsten Wartevorgang auf null geprüft.

gb_frame_count: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/system.h:34

c
#define gb_frame_count system_get_frame

kitaqfc/lib/system.c:30

c
u16 system_get_frame(void)
{
    return kq_system_frame;
}
gb_init

gb_init ist ein Alias für system_init. Setzt den Software-Framezähler und die Callback-Registrierung zurück.

Initialisiert die Frame-Verwaltung, indem Zähler und registrierter Callback gelöscht werden.

Syntax

c
void gb_init(void);

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Der Header definiert ein objektartiges Makro, das zum Implementierungsnamen expandiert. Argumente, Rückgabewerte und Zustandszugriffe entsprechen dem Ziel; der Alias fügt keinen eigenen Zustand oder Verarbeitungsschritt hinzu. Verwenden Sie wie im vollständigen Beispiel und Buildbefehl input.h/input.c für Eingaben oder system.h/system.c für Framedienste.

Dies ist die von der FC-Bibliothek angebotene gb_-Schreibweise. Sie ruft die FC-Implementierung system_* auf, keine Game-Boy-Hardware. Der entsprechende fc_-Name ruft dieselbe FC-Implementierung auf.

Der Zähler zählt Wartevorgänge über diese Wrapper-Funktion, nicht automatisch die tatsächlich verstrichenen Hardware-Frames. Beim Überlauf nach 16 Bits beginnt er wieder bei null.

Die FC-Initialisierung aktiviert NMI. Das Warten setzt eine funktionierende NMI-Zustellung voraus. Das Maskieren von CPU-IRQs hält NMI nicht an.

system_init

Anwendungsbeispiel

c
gb_init();result[0]=gb_frame_count();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel bestätigt vor dem Registrieren des Callbacks, dass die anfängliche Frame-Nummer null ist.

gb_init: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/system.h:31

c
#define gb_init system_init

kitaqfc/lib/system.c:7

c
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 ist ein Alias für system_set_vblank_callback. Registriert oder entfernt den nach dem Framewarten synchron aufgerufenen Callback.

Registriert, ersetzt oder entfernt die nach einem Frame-Wartevorgang aufgerufene Funktion.

Syntax

c
void gb_set_vblank_callback(SystemCallback callback);

Parameter

callback

Aufzurufende Funktion; 0 entfernt den Callback.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Der Header definiert ein objektartiges Makro, das zum Implementierungsnamen expandiert. Argumente, Rückgabewerte und Zustandszugriffe entsprechen dem Ziel; der Alias fügt keinen eigenen Zustand oder Verarbeitungsschritt hinzu. Verwenden Sie wie im vollständigen Beispiel und Buildbefehl input.h/input.c für Eingaben oder system.h/system.c für Framedienste.

Dies ist die von der FC-Bibliothek angebotene gb_-Schreibweise. Sie ruft die FC-Implementierung system_* auf, keine Game-Boy-Hardware. Der entsprechende fc_-Name ruft dieselbe FC-Implementierung auf.

Dies ist ein gewöhnlicher Zeiger auf eine Funktion ohne Parameter und Rückgabewert. Er enthält keine Banknummer; der Zielcode muss eingeblendet bleiben, solange Aufrufe möglich sind.

Die FC-Initialisierung aktiviert NMI. Das Warten setzt eine funktionierende NMI-Zustellung voraus. Das Maskieren von CPU-IRQs hält NMI nicht an.

system_set_vblank_callback

Anwendungsbeispiel

c
gb_set_vblank_callback(on_frame);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Nach drei Callback-Aufrufen deaktiviert die Registrierung von 0 den Aufruf. Der nächste Wartevorgang erhöht den Frame-Zähler auf vier, während die Callback-Anzahl drei bleibt.

gb_set_vblank_callback: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/system.h:33

c
#define gb_set_vblank_callback system_set_vblank_callback

kitaqfc/lib/system.c:24

c
void system_set_vblank_callback(SystemCallback callback)
{
    system_vblank_callback = callback;
}
gb_wait_vblank

gb_wait_vblank ist ein Alias für system_wait_vblank. Wartet auf die Framegrenze, erhöht den Software-Framezähler und ruft den registrierten Callback auf.

Wartet auf den nächsten Frame, erhöht den Zähler und ruft anschließend den registrierten Callback auf.

Syntax

c
void gb_wait_vblank(void);

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Der Header definiert ein objektartiges Makro, das zum Implementierungsnamen expandiert. Argumente, Rückgabewerte und Zustandszugriffe entsprechen dem Ziel; der Alias fügt keinen eigenen Zustand oder Verarbeitungsschritt hinzu. Verwenden Sie wie im vollständigen Beispiel und Buildbefehl input.h/input.c für Eingaben oder system.h/system.c für Framedienste.

Dies ist die von der FC-Bibliothek angebotene gb_-Schreibweise. Sie ruft die FC-Implementierung system_* auf, keine Game-Boy-Hardware. Der entsprechende fc_-Name ruft dieselbe FC-Implementierung auf.

Der Callback läuft synchron innerhalb dieser Funktion; seine Registrierung installiert keinen Interrupt-Handler. Der Zähler zählt die Wartevorgänge dieses Wrappers und misst nicht automatisch die verstrichenen Hardware-Frames. Beim 16-Bit-Überlauf beginnt er wieder bei null.

Die FC-Initialisierung aktiviert NMI. Das Warten setzt eine funktionierende NMI-Zustellung voraus. Das Maskieren von CPU-IRQs hält NMI nicht an.

system_wait_vblank

Anwendungsbeispiel

c
gb_wait_vblank();gb_wait_vblank();gb_wait_vblank();result[1]=frame_calls;result[2]=frame_seen;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Drei Wartevorgänge rufen den Callback dreimal auf; der zuletzt darin gelesene Zählerstand beträgt drei.

gb_wait_vblank: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/system.h:32

c
#define gb_wait_vblank system_wait_vblank

kitaqfc/lib/system.c:16

c
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

Deaktiviert maskierbare CPU-Interrupts.

Syntax

c
void system_disable_interrupts(void);

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Halten Sie geschützte Aktualisierungen kurz und stellen Sie die Interrupts danach passend wieder her. Die Interruptsperre ist unabhängig von den Voraussetzungen einer Frame-Warteroutine.

Die FC-Initialisierung aktiviert NMI. Das Warten setzt eine funktionierende NMI-Zustellung voraus. Das Maskieren von CPU-IRQs hält NMI nicht an.

Anwendungsbeispiel

c
system_disable_interrupts();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel kombiniert Deaktivierung und Aktivierung. Eigene Prüfprogramme kontrollieren zusätzlich den CPU-Interruptzustand.

system_disable_interrupts: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/system.h:25

Deklarationshinweise im Original
Disable maskable CPU IRQs; this does not disable the PPU's NMI source.

kitaqfc/lib/system.c:48

c
void system_disable_interrupts(void)
{
    __irq_disable();
}
system_enable_interrupts

Aktiviert maskierbare CPU-Interrupts.

Syntax

c
void system_enable_interrupts(void);

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Bereiten Sie Interruptquellen und Handler vor der Aktivierung vor. Auf FC ist dies unabhängig davon, ob NMI aktiviert oder deaktiviert ist.

Die FC-Initialisierung aktiviert NMI. Das Warten setzt eine funktionierende NMI-Zustellung voraus. Das Maskieren von CPU-IRQs hält NMI nicht an.

Anwendungsbeispiel

c
system_enable_interrupts();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel stellt die Interrupts wieder her. Das FC-Programm deaktiviert zuerst die APU-Frame- und DMC-IRQ-Quellen, damit eine nicht quittierte IRQ nicht wiederholt bearbeitet wird.

system_enable_interrupts: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/system.h:23

Deklarationshinweise im Original
Enable maskable CPU IRQs through the intrinsic; NMI is controlled separately.

kitaqfc/lib/system.c:42

c
void system_enable_interrupts(void)
{
    __irq_enable();
}
system_get_frame

Liest den 16-Bit-Zähler der Frame-Wartefunktion.

Syntax

c
u16 system_get_frame(void);

Rückgabewert

Gibt den aktuellen Zählerstand von 0 bis 65535 zurück.

Bedingungen und Grenzen

Der Zähler zählt Wartevorgänge über diese Wrapper-Funktion, nicht automatisch die tatsächlich verstrichenen Hardware-Frames. Beim Überlauf nach 16 Bits beginnt er wieder bei null.

Die FC-Initialisierung aktiviert NMI. Das Warten setzt eine funktionierende NMI-Zustellung voraus. Das Maskieren von CPU-IRQs hält NMI nicht an.

Anwendungsbeispiel

c
result[3]=system_get_frame();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel liest nach drei Wartevorgängen drei. Für den Überlauftest wird der Zähler ausdrücklich auf 65535 gesetzt und nach dem nächsten Wartevorgang auf null geprüft.

system_get_frame: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/system.h:19

Deklarationshinweise im Original
Return the wrapping 16-bit count of completed waits through this wrapper.

kitaqfc/lib/system.c:30

c
u16 system_get_frame(void)
{
    return kq_system_frame;
}
system_get_frame8

Liest für kurze Wiederholungsintervalle die unteren acht Bits des Frame-Zählers.

Syntax

c
u8 system_get_frame8(void);

Rückgabewert

Gibt das niederwertige Byte von 0 bis 255 zurück.

Bedingungen und Grenzen

Der Zähler zählt Wartevorgänge über diese Wrapper-Funktion, nicht automatisch die tatsächlich verstrichenen Hardware-Frames. Beim Überlauf nach 16 Bits beginnt er wieder bei null.

Die FC-Initialisierung aktiviert NMI. Das Warten setzt eine funktionierende NMI-Zustellung voraus. Das Maskieren von CPU-IRQs hält NMI nicht an.

Anwendungsbeispiel

c
result[4]=system_get_frame8();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel liest nach drei Wartevorgängen drei und beim Überlauf des 16-Bit-Zählers null.

system_get_frame8: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/system.h:21

Deklarationshinweise im Original
Return the low byte of the software frame counter.

kitaqfc/lib/system.c:36

c
u8 system_get_frame8(void)
{
    return (u8)kq_system_frame;
}
system_init

Initialisiert die Frame-Verwaltung, indem Zähler und registrierter Callback gelöscht werden.

Syntax

c
void system_init(void);

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Der Zähler zählt Wartevorgänge über diese Wrapper-Funktion, nicht automatisch die tatsächlich verstrichenen Hardware-Frames. Beim Überlauf nach 16 Bits beginnt er wieder bei null.

Die FC-Initialisierung aktiviert NMI. Das Warten setzt eine funktionierende NMI-Zustellung voraus. Das Maskieren von CPU-IRQs hält NMI nicht an.

Anwendungsbeispiel

c
system_init();result[0]=system_get_frame();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das Beispiel bestätigt vor dem Registrieren des Callbacks, dass die anfängliche Frame-Nummer null ist.

system_init: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/system.h:13

Deklarationshinweise im Original
Reset the software frame counter and callback storage, then enable NMI.

kitaqfc/lib/system.c:7

c
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

Registriert, ersetzt oder entfernt die nach einem Frame-Wartevorgang aufgerufene Funktion.

Syntax

c
void system_set_vblank_callback(SystemCallback callback);

Parameter

callback

Aufzurufende Funktion; 0 entfernt den Callback.

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Dies ist ein gewöhnlicher Zeiger auf eine Funktion ohne Parameter und Rückgabewert. Er enthält keine Banknummer; der Zielcode muss eingeblendet bleiben, solange Aufrufe möglich sind.

Die FC-Initialisierung aktiviert NMI. Das Warten setzt eine funktionierende NMI-Zustellung voraus. Das Maskieren von CPU-IRQs hält NMI nicht an.

Anwendungsbeispiel

c
system_set_vblank_callback(on_frame);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Nach drei Callback-Aufrufen deaktiviert die Registrierung von 0 den Aufruf. Der nächste Wartevorgang erhöht den Frame-Zähler auf vier, während die Callback-Anzahl drei bleibt.

system_set_vblank_callback: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/system.h:17

Deklarationshinweise im Original
Replace the per-wait callback; null disables callback dispatch.

kitaqfc/lib/system.c:24

c
void system_set_vblank_callback(SystemCallback callback)
{
    system_vblank_callback = callback;
}
system_wait_vblank

Wartet auf den nächsten Frame, erhöht den Zähler und ruft anschließend den registrierten Callback auf.

Syntax

c
void system_wait_vblank(void);

Rückgabewert

Kein Rückgabewert.

Bedingungen und Grenzen

Der Callback läuft synchron innerhalb dieser Funktion; seine Registrierung installiert keinen Interrupt-Handler. Der Zähler zählt die Wartevorgänge dieses Wrappers und misst nicht automatisch die verstrichenen Hardware-Frames. Beim 16-Bit-Überlauf beginnt er wieder bei null.

Die FC-Initialisierung aktiviert NMI. Das Warten setzt eine funktionierende NMI-Zustellung voraus. Das Maskieren von CPU-IRQs hält NMI nicht an.

Anwendungsbeispiel

c
system_wait_vblank();system_wait_vblank();system_wait_vblank();result[1]=frame_calls;result[2]=frame_seen;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Drei Wartevorgänge rufen den Callback dreimal auf; der zuletzt darin gelesene Zählerstand beträgt drei.

system_wait_vblank: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/system.h:15

Deklarationshinweise im Original
Wait for NMI, count the completed wait, then invoke the registered callback.

kitaqfc/lib/system.c:16

c
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 — Rechteckige Operationen auf Kachelkarten

Liest ein zeilenweises Kachelarray und prüft Solidität über einen ID-Schwellenwert. Rechtecktests prüfen nur die vier Ecken, nicht den gesamten Innenraum.

nes_tilemap_get

Liest die Kachel-ID und gibt bei Koordinaten außerhalb der Karte 255 zurück.

Syntax

c
unsigned char nes_tilemap_get(struct NesTilemap* map, unsigned char tx, unsigned char ty);

Parameter

map

Gültige Karte mit zeilenweisem Kachelarray, Abmessungen und Soliditätsschwelle; der Speicher muss während des Aufrufs lesbar bleiben.

tx

Kachel-X-Koordinate; eine Einheit entspricht acht Pixeln.

ty

Kachel-Y-Koordinate; eine Einheit entspricht acht Pixeln.

Rückgabewert

Kachelbyte oder 255; eine gespeicherte 255 lässt sich nicht von einem Ergebnis außerhalb der Karte unterscheiden.

Bedingungen und Grenzen

Benötigt eine gültige Karte und ein nichtleeres lesbares Array. Die Eigenschaft „solide“ wird über einen Schwellenwert der Kachel-ID bestimmt, nicht über eine separate Kollisionsmaske.

Anwendungsbeispiel

c
result[1]=nes_tilemap_get(&map,2,1);result[2]=nes_tilemap_get(&map,5,1);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Setzen Sie die solide Kachel 5 bei (2,1) in eine 5×3-Karte: Ihr Array-Index ist 7, eine Abfrage außerhalb liefert 255. Berührt eine Ecke das Hindernis, ist das Ergebnis 1. Ein 40×24-Rechteck, das es nur im Inneren einschließt, liefert 0 und zeigt damit die Beschränkung auf die Eckprüfung.

nes_tilemap_get: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/tilemap.h:19

Deklarationshinweise im Original
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

c
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

Wandelt Kachelkoordinaten in den zeilenweisen Byte-Offset ty*width+tx um.

Syntax

c
unsigned short nes_tilemap_index(struct NesTilemap* map, unsigned char tx, unsigned char ty);

Parameter

map

Gültige Karte mit zeilenweisem Kachelarray, Abmessungen und Soliditätsschwelle; der Speicher muss während des Aufrufs lesbar bleiben.

tx

Kachel-X-Koordinate; eine Einheit entspricht acht Pixeln.

ty

Kachel-Y-Koordinate; eine Einheit entspricht acht Pixeln.

Rückgabewert

Berechneter 16-Bit-Offset; die Koordinaten werden nicht auf Bereichsgrenzen geprüft.

Bedingungen und Grenzen

Benötigt eine gültige Karte und ein nichtleeres lesbares Array. Die Eigenschaft „solide“ wird über einen Schwellenwert der Kachel-ID bestimmt, nicht über eine separate Kollisionsmaske.

Anwendungsbeispiel

c
result[0]=nes_tilemap_index(&map,2,1);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Setzen Sie die solide Kachel 5 bei (2,1) in eine 5×3-Karte: Ihr Array-Index ist 7, eine Abfrage außerhalb liefert 255. Berührt eine Ecke das Hindernis, ist das Ergebnis 1. Ein 40×24-Rechteck, das es nur im Inneren einschließt, liefert 0 und zeigt damit die Beschränkung auf die Eckprüfung.

nes_tilemap_index: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/tilemap.h:16

Deklarationshinweise im Original
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

c
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

Prüft eine Kachel gegen solid_from; Kachel 255 und Koordinaten außerhalb der Karte gelten immer als solide.

Syntax

c
unsigned char nes_tilemap_point_solid(struct NesTilemap* map, unsigned char tx, unsigned char ty);

Parameter

map

Gültige Karte mit zeilenweisem Kachelarray, Abmessungen und Soliditätsschwelle; der Speicher muss während des Aufrufs lesbar bleiben.

tx

Kachel-X-Koordinate; eine Einheit entspricht acht Pixeln.

ty

Kachel-Y-Koordinate; eine Einheit entspricht acht Pixeln.

Rückgabewert

1 für solide, andernfalls 0.

Bedingungen und Grenzen

Benötigt eine gültige Karte und ein nichtleeres lesbares Array. Die Eigenschaft „solide“ wird über einen Schwellenwert der Kachel-ID bestimmt, nicht über eine separate Kollisionsmaske.

Anwendungsbeispiel

c
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);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Setzen Sie die solide Kachel 5 bei (2,1) in eine 5×3-Karte: Ihr Array-Index ist 7, eine Abfrage außerhalb liefert 255. Berührt eine Ecke das Hindernis, ist das Ergebnis 1. Ein 40×24-Rechteck, das es nur im Inneren einschließt, liefert 0 und zeigt damit die Beschränkung auf die Eckprüfung.

nes_tilemap_point_solid: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/tilemap.h:22

Deklarationshinweise im Original
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

c
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

Prüft die linke obere, rechte obere, linke untere und rechte untere Ecke eines Weltrechtecks.

Syntax

c
unsigned char nes_tilemap_world_box_solid(struct NesTilemap* map, unsigned short world_x, unsigned short world_y, unsigned char width, unsigned char height);

Parameter

map

Gültige Karte mit zeilenweisem Kachelarray, Abmessungen und Soliditätsschwelle; der Speicher muss während des Aufrufs lesbar bleiben.

world_x

Welt-X in ganzen Pixeln; halten Sie den Wert unter 2048, um einen Umlauf zu vermeiden.

world_y

Welt-Y in ganzen Pixeln; halten Sie den Wert unter 2048, um einen Umlauf zu vermeiden.

width

Rechteckbreite, 1–255 Pixel; die gegenüberliegende Kante world_x+width-1 muss unter 2048 bleiben.

height

Rechteckhöhe, 1–255 Pixel; die gegenüberliegende Kante world_y+height-1 muss unter 2048 bleiben.

Rückgabewert

1, wenn mindestens eine Ecke solide ist, andernfalls 0.

Bedingungen und Grenzen

Breite und Höhe dürfen nicht null sein. Kanten zwischen den Ecken und der Innenraum werden nicht abgesucht; große Rechtecke können daher Hindernisse übersehen. Das Beispiel liefert bei einem Hindernis in der Mitte null, wenn alle vier Ecken frei sind.

Anwendungsbeispiel

c
result[12]=nes_tilemap_world_box_solid(&map,8,8,16,8);result[13]=nes_tilemap_world_box_solid(&map,0,0,40,24);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Setzen Sie die solide Kachel 5 bei (2,1) in eine 5×3-Karte: Ihr Array-Index ist 7, eine Abfrage außerhalb liefert 255. Berührt eine Ecke das Hindernis, ist das Ergebnis 1. Ein 40×24-Rechteck, das es nur im Inneren einschließt, liefert 0 und zeigt damit die Beschränkung auf die Eckprüfung.

nes_tilemap_world_box_solid: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/tilemap.h:33

Deklarationshinweise im Original
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

c
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

Wandelt einen Weltpunkt in Koordinaten von Acht-Pixel-Kacheln um und prüft auf Solidität.

Syntax

c
unsigned char nes_tilemap_world_point_solid(struct NesTilemap* map, unsigned short world_x, unsigned short world_y);

Parameter

map

Gültige Karte mit zeilenweisem Kachelarray, Abmessungen und Soliditätsschwelle; der Speicher muss während des Aufrufs lesbar bleiben.

world_x

Welt-X in ganzen Pixeln; halten Sie den Wert unter 2048, um einen Umlauf zu vermeiden.

world_y

Welt-Y in ganzen Pixeln; halten Sie den Wert unter 2048, um einen Umlauf zu vermeiden.

Rückgabewert

1, wenn die entsprechende Kachel solide ist, andernfalls 0.

Bedingungen und Grenzen

Benötigt eine gültige Karte und ein nichtleeres lesbares Array. Die Eigenschaft „solide“ wird über einen Schwellenwert der Kachel-ID bestimmt, nicht über eine separate Kollisionsmaske.

Anwendungsbeispiel

c
result[10]=nes_tilemap_world_point_solid(&map,16,8);result[11]=nes_tilemap_world_point_solid(&map,0,0);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Setzen Sie die solide Kachel 5 bei (2,1) in eine 5×3-Karte: Ihr Array-Index ist 7, eine Abfrage außerhalb liefert 255. Berührt eine Ecke das Hindernis, ist das Ergebnis 1. Ein 40×24-Rechteck, das es nur im Inneren einschließt, liefert 0 und zeigt damit die Beschränkung auf die Eckprüfung.

nes_tilemap_world_point_solid: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/tilemap.h:29

Deklarationshinweise im Original
Convert a world point to tile coordinates and apply the tile solidity rule.

kitaqfc/lib/tilemap.c:77

c
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

Teilt Welt-X durch acht und begrenzt das Ergebnis auf ein Kachelkoordinaten-Byte.

Syntax

c
unsigned char nes_world_to_tile8_x(unsigned short world_x);

Parameter

world_x

Welt-X in ganzen Pixeln; halten Sie den Wert unter 2048, um einen Umlauf zu vermeiden.

Rückgabewert

Die unteren acht Bits von world_x >> 3; läuft alle 2048 Pixel um.

Bedingungen und Grenzen

Benötigt eine gültige Karte und ein nichtleeres lesbares Array. Die Eigenschaft „solide“ wird über einen Schwellenwert der Kachel-ID bestimmt, nicht über eine separate Kollisionsmaske.

Anwendungsbeispiel

c
result[6]=nes_world_to_tile8_x(23);result[7]=nes_world_to_tile8_x(24);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Setzen Sie die solide Kachel 5 bei (2,1) in eine 5×3-Karte: Ihr Array-Index ist 7, eine Abfrage außerhalb liefert 255. Berührt eine Ecke das Hindernis, ist das Ergebnis 1. Ein 40×24-Rechteck, das es nur im Inneren einschließt, liefert 0 und zeigt damit die Beschränkung auf die Eckprüfung.

nes_world_to_tile8_x: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/tilemap.h:25

Deklarationshinweise im Original
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

c
unsigned char nes_world_to_tile8_x(unsigned short world_x)
{
    return (unsigned char)(world_x >> 3);
}
nes_world_to_tile8_y

Teilt Welt-Y durch acht und begrenzt das Ergebnis auf ein Kachelkoordinaten-Byte.

Syntax

c
unsigned char nes_world_to_tile8_y(unsigned short world_y);

Parameter

world_y

Welt-Y in ganzen Pixeln; halten Sie den Wert unter 2048, um einen Umlauf zu vermeiden.

Rückgabewert

Die unteren acht Bits von world_y >> 3; läuft alle 2048 Pixel um.

Bedingungen und Grenzen

Benötigt eine gültige Karte und ein nichtleeres lesbares Array. Die Eigenschaft „solide“ wird über einen Schwellenwert der Kachel-ID bestimmt, nicht über eine separate Kollisionsmaske.

Anwendungsbeispiel

c
result[8]=nes_world_to_tile8_y(15);result[9]=nes_world_to_tile8_y(16);

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Setzen Sie die solide Kachel 5 bei (2,1) in eine 5×3-Karte: Ihr Array-Index ist 7, eine Abfrage außerhalb liefert 255. Berührt eine Ecke das Hindernis, ist das Ergebnis 1. Ein 40×24-Rechteck, das es nur im Inneren einschließt, liefert 0 und zeigt damit die Beschränkung auf die Eckprüfung.

nes_world_to_tile8_y: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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.chr
Implementierung und Quelltext

kitaqfc/lib/tilemap.h:27

Deklarationshinweise im Original
Convert pixels to eight-pixel tile Y with the same byte-coordinate limit.

kitaqfc/lib/tilemap.c:71

c
unsigned char nes_world_to_tile8_y(unsigned short world_y)
{
    return (unsigned char)(world_y >> 3);
}

vram.h — VRAM-Aktualisierungen und Übertragung per Warteschlange

Initialisiert die Warteschlange für aufgeschobene VRAM-Schreibbefehle als leer und löscht die Überlaufmeldung. Löscht weder den Bildschirm noch lädt es Tile-Grafiken oder reserviert physischen VRAM.

FC zählt codierte Befehlsbytes in einem festen intrinsischen 128-Byte-Puffer. Ein Tile-Schreibbefehl braucht 4 Bytes, ein Fülleintrag 5 und eine Zeigerkopie 6 einschließlich Metadaten. NMI kann eine bereite Warteschlange verarbeiten; prüfen und befüllen Sie sie vor der Freigabe und koordinieren Sie Erzeuger und Verbraucher.

Gibt die intrinsische Warteschlange mit __vramq_commit frei und wartet mit __nmi_wait auf den NMI-Pfad. Der Standardhandler verarbeitet die bereite Warteschlange. NMI und Handler müssen aktiv bleiben; große Übertragungen werden durch diesen Aufruf nicht auf mehrere VBlanks verteilt.

Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.

vram_clear_queue

Verwirft ausstehende VRAM-Befehle und löscht das Überlaufflag, ohne die Schreibvorgänge auszuführen.

Syntax

c
void vram_clear_queue(void);

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

FC zählt codierte Befehlsbytes in einem festen intrinsischen 128-Byte-Puffer. Ein Tile-Schreibbefehl braucht 4 Bytes, ein Fülleintrag 5 und eine Zeigerkopie 6 einschließlich Metadaten. NMI kann eine bereite Warteschlange verarbeiten; prüfen und befüllen Sie sie vor der Freigabe und koordinieren Sie Erzeuger und Verbraucher.

Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.

Anwendungsbeispiel

c
vram_clear_queue();
if (vram_get_queue_used()!=0 || vram_get_overflowed()!=0) failures++;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.

Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.

Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.

Auf FC kennzeichnet Rot die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat. Blau kennzeichnet das Rechteck von 32 × 24 und die Kopie aus zwei Mustern. Grün kennzeichnet den Block aus 3 × 2 Kacheln und den Balken von 40 × 8. Der Hintergrund ist schwarz; Position und Farbe jedes gezeichneten Pixels werden geprüft.

vram_clear_queue: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vram.h:15

Deklarationshinweise im Original
Discard queued commands and explicitly reset the overflow latch.

kitaqfc/lib/vram.c:17

c
void vram_clear_queue(void)
{
    __vramq_clear();
    __vramq_clear_overflow();
}
vram_flush

Gibt die intrinsische Warteschlange mit __vramq_commit frei und wartet mit __nmi_wait auf den NMI-Pfad. Der Standardhandler verarbeitet die bereite Warteschlange. NMI und Handler müssen aktiv bleiben; große Übertragungen werden durch diesen Aufruf nicht auf mehrere VBlanks verteilt.

Syntax

c
void vram_flush(void);

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

FC zählt codierte Befehlsbytes in einem festen intrinsischen 128-Byte-Puffer. Ein Tile-Schreibbefehl braucht 4 Bytes, ein Fülleintrag 5 und eine Zeigerkopie 6 einschließlich Metadaten. NMI kann eine bereite Warteschlange verarbeiten; prüfen und befüllen Sie sie vor der Freigabe und koordinieren Sie Erzeuger und Verbraucher.

Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.

PPU-Byteadresse (0x0000–0x3FFF), kein CPU-Zeiger. Das Ziel muss beschreibbar sein: Musteränderungen benötigen CHR-RAM statt CHR-ROM. PPU-Adressabbildung und Spiegelung gelten weiterhin. Wählen Sie für fortlaufendes Kopieren und Füllen die Schrittweite 1 in PPUCTRL. Führen Sie Befehle zu einem sicheren PPU-Zeitpunkt aus und stellen Sie danach den Scrollzustand her; der Ausführer schreibt PPUADDR und PPUDATA, ohne Scrolleinstellungen wiederherzustellen.

Anwendungsbeispiel

c
vram_flush(); // One small write through the VBlank/NMI path.
__scroll_set(0,0);
if (vram_get_queue_used()!=0) failures++;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.

Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.

Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.

Auf FC kennzeichnet Rot die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat. Blau kennzeichnet das Rechteck von 32 × 24 und die Kopie aus zwei Mustern. Grün kennzeichnet den Block aus 3 × 2 Kacheln und den Balken von 40 × 8. Der Hintergrund ist schwarz; Position und Farbe jedes gezeichneten Pixels werden geprüft.

vram_flush: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vram.h:41

Deklarationshinweise im Original
Commit queued records for consumption and wait for the NMI path.

kitaqfc/lib/vram.c:115

c
void vram_flush(void)
{
    __vramq_commit();
    __nmi_wait();
}
vram_flush_now

Ruft sofort __vramq_exec auf. Ausgeführt wird nur bei durch __vramq_commit gesetztem Bereit-Flag; eine nicht freigegebene Warteschlange bleibt unverändert. Nach der Ausführung werden Länge und Bereit-Flag gelöscht, die Überlaufmeldung bleibt. Diese Funktion gibt die Warteschlange weder frei noch wartet sie auf einen sicheren PPU-Zeitpunkt.

Syntax

c
void vram_flush_now(void);

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

FC zählt codierte Befehlsbytes in einem festen intrinsischen 128-Byte-Puffer. Ein Tile-Schreibbefehl braucht 4 Bytes, ein Fülleintrag 5 und eine Zeigerkopie 6 einschließlich Metadaten. NMI kann eine bereite Warteschlange verarbeiten; prüfen und befüllen Sie sie vor der Freigabe und koordinieren Sie Erzeuger und Verbraucher.

Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.

PPU-Byteadresse (0x0000–0x3FFF), kein CPU-Zeiger. Das Ziel muss beschreibbar sein: Musteränderungen benötigen CHR-RAM statt CHR-ROM. PPU-Adressabbildung und Spiegelung gelten weiterhin. Wählen Sie für fortlaufendes Kopieren und Füllen die Schrittweite 1 in PPUCTRL. Führen Sie Befehle zu einem sicheren PPU-Zeitpunkt aus und stellen Sie danach den Scrollzustand her; der Ausführer schreibt PPUADDR und PPUDATA, ohne Scrolleinstellungen wiederherzustellen.

Anwendungsbeispiel

c
// 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++;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.

Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.

Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.

Auf FC kennzeichnet Rot die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat. Blau kennzeichnet das Rechteck von 32 × 24 und die Kopie aus zwei Mustern. Grün kennzeichnet den Block aus 3 × 2 Kacheln und den Balken von 40 × 8. Der Hintergrund ist schwarz; Position und Farbe jedes gezeichneten Pixels werden geprüft.

vram_flush_now: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vram.h:39

Deklarationshinweise im Original
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

c
void vram_flush_now(void)
{
    __vramq_exec();
}
vram_get_overflowed

Liest das Überlaufflag, ohne es zu löschen; es kann einen früheren Fehler festhalten.

Syntax

c
u8 vram_get_overflowed(void);

Rückgabewert

0 ohne gespeicherten Überlauf; nach einem abgelehnten Eintrag 1 bis zum ausdrücklichen Zurücksetzen. Die Ausführung der Warteschlange löscht diese Meldung nicht.

Bedingungen und Grenzen

FC zählt codierte Befehlsbytes in einem festen intrinsischen 128-Byte-Puffer. Ein Tile-Schreibbefehl braucht 4 Bytes, ein Fülleintrag 5 und eine Zeigerkopie 6 einschließlich Metadaten. NMI kann eine bereite Warteschlange verarbeiten; prüfen und befüllen Sie sie vor der Freigabe und koordinieren Sie Erzeuger und Verbraucher.

Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.

Anwendungsbeispiel

c
overflow_seen=vram_get_overflowed();
if (overflow_seen!=1) failures++;
// Reading the latch again does not clear it.
if (vram_get_overflowed()!=1) failures++;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.

Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.

Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.

Auf FC kennzeichnet Rot die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat. Blau kennzeichnet das Rechteck von 32 × 24 und die Kopie aus zwei Mustern. Grün kennzeichnet den Block aus 3 × 2 Kacheln und den Balken von 40 × 8. Der Hintergrund ist schwarz; Position und Farbe jedes gezeichneten Pixels werden geprüft.

vram_get_overflowed: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vram.h:52

Deklarationshinweise im Original
Read the overflow latch without clearing it.

kitaqfc/lib/vram.c:144

c
u8 vram_get_overflowed(void)
{
    return __vramq_overflow();
}
vram_get_queue_capacity

Gibt die Gesamtkapazität des Befehlspuffers unabhängig von seiner aktuellen Belegung zurück.

Syntax

c
u8 vram_get_queue_capacity(void);

Rückgabewert

Ein vorzeichenloses Byte in den hier beschriebenen plattformspezifischen Einheiten. Die Abfrage verändert oder verarbeitet die Warteschlange nicht.

Bedingungen und Grenzen

FC zählt codierte Befehlsbytes in einem festen intrinsischen 128-Byte-Puffer. Ein Tile-Schreibbefehl braucht 4 Bytes, ein Fülleintrag 5 und eine Zeigerkopie 6 einschließlich Metadaten. NMI kann eine bereite Warteschlange verarbeiten; prüfen und befüllen Sie sie vor der Freigabe und koordinieren Sie Erzeuger und Verbraucher.

Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.

Anwendungsbeispiel

c
capacity=vram_get_queue_capacity();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.

Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.

Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.

Auf FC kennzeichnet Rot die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat. Blau kennzeichnet das Rechteck von 32 × 24 und die Kopie aus zwei Mustern. Grün kennzeichnet den Block aus 3 × 2 Kacheln und den Balken von 40 × 8. Der Hintergrund ist schwarz; Position und Farbe jedes gezeichneten Pixels werden geprüft.

vram_get_queue_capacity: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vram.h:50

Deklarationshinweise im Original
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

c
u8 vram_get_queue_capacity(void)
{
    return __vramq_capacity();
}
vram_get_queue_free

Gibt Gesamtkapazität minus aktuelle Belegung zurück. Prüfen Sie vor dem Einfügen, ob der nächste Eintrag oder ganze Stapel hineinpasst; diese Abfrage reserviert keinen Platz.

Syntax

c
u8 vram_get_queue_free(void);

Rückgabewert

Ein vorzeichenloses Byte in den hier beschriebenen plattformspezifischen Einheiten. Die Abfrage verändert oder verarbeitet die Warteschlange nicht.

Bedingungen und Grenzen

FC zählt codierte Befehlsbytes in einem festen intrinsischen 128-Byte-Puffer. Ein Tile-Schreibbefehl braucht 4 Bytes, ein Fülleintrag 5 und eine Zeigerkopie 6 einschließlich Metadaten. NMI kann eine bereite Warteschlange verarbeiten; prüfen und befüllen Sie sie vor der Freigabe und koordinieren Sie Erzeuger und Verbraucher.

Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.

Anwendungsbeispiel

c
available=vram_get_queue_free();
if (used+available!=capacity) failures++;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.

Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.

Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.

Auf FC kennzeichnet Rot die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat. Blau kennzeichnet das Rechteck von 32 × 24 und die Kopie aus zwei Mustern. Grün kennzeichnet den Block aus 3 × 2 Kacheln und den Balken von 40 × 8. Der Hintergrund ist schwarz; Position und Farbe jedes gezeichneten Pixels werden geprüft.

vram_get_queue_free: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vram.h:47

Deklarationshinweise im Original
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

c
u8 vram_get_queue_free(void)
{
    return (u8)(__vramq_capacity() - __vramq_len());
}
vram_get_queue_used

Gibt den von ausstehenden Befehlen belegten Pufferumfang zurück, nicht die Bytezahl der späteren Videodaten.

Syntax

c
u8 vram_get_queue_used(void);

Rückgabewert

Ein vorzeichenloses Byte in den hier beschriebenen plattformspezifischen Einheiten. Die Abfrage verändert oder verarbeitet die Warteschlange nicht.

Bedingungen und Grenzen

FC zählt codierte Befehlsbytes in einem festen intrinsischen 128-Byte-Puffer. Ein Tile-Schreibbefehl braucht 4 Bytes, ein Fülleintrag 5 und eine Zeigerkopie 6 einschließlich Metadaten. NMI kann eine bereite Warteschlange verarbeiten; prüfen und befüllen Sie sie vor der Freigabe und koordinieren Sie Erzeuger und Verbraucher.

Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.

Anwendungsbeispiel

c
used=vram_get_queue_used();

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.

Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.

Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.

Auf FC kennzeichnet Rot die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat. Blau kennzeichnet das Rechteck von 32 × 24 und die Kopie aus zwei Mustern. Grün kennzeichnet den Block aus 3 × 2 Kacheln und den Balken von 40 × 8. Der Hintergrund ist schwarz; Position und Farbe jedes gezeichneten Pixels werden geprüft.

vram_get_queue_used: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vram.h:43

Deklarationshinweise im Original
Return the encoded queue length in bytes, not the number of commands.

kitaqfc/lib/vram.c:122

c
u8 vram_get_queue_used(void)
{
    return __vramq_len();
}
vram_init

Initialisiert die Warteschlange für aufgeschobene VRAM-Schreibbefehle als leer und löscht die Überlaufmeldung. Löscht weder den Bildschirm noch lädt es Tile-Grafiken oder reserviert physischen VRAM.

Syntax

c
void vram_init(void);

Rückgabewert

Keiner (void).

Bedingungen und Grenzen

FC zählt codierte Befehlsbytes in einem festen intrinsischen 128-Byte-Puffer. Ein Tile-Schreibbefehl braucht 4 Bytes, ein Fülleintrag 5 und eine Zeigerkopie 6 einschließlich Metadaten. NMI kann eine bereite Warteschlange verarbeiten; prüfen und befüllen Sie sie vor der Freigabe und koordinieren Sie Erzeuger und Verbraucher.

Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.

Anwendungsbeispiel

c
vram_init();
if (vram_get_queue_used()!=0 || vram_get_overflowed()!=0) failures++;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.

Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.

Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.

Auf FC kennzeichnet Rot die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat. Blau kennzeichnet das Rechteck von 32 × 24 und die Kopie aus zwei Mustern. Grün kennzeichnet den Block aus 3 × 2 Kacheln und den Balken von 40 × 8. Der Hintergrund ist schwarz; Position und Farbe jedes gezeichneten Pixels werden geprüft.

vram_init: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vram.h:13

Deklarationshinweise im Original
Clear the intrinsic queue and its overflow latch.

kitaqfc/lib/vram.c:10

c
void vram_init(void)
{
    __vramq_clear();
    __vramq_clear_overflow();
}
vram_queue_bg_block

Stellt ein Rechteck aus w × h Tile-Nummern von src für die Karte an base bereit. Quellzeilen enthalten jeweils w direkt aufeinanderfolgende Bytes; Zielzeilen haben 32 Bytes Abstand. Der Quellzeiger bleibt gespeichert, daher ändern spätere Quelldatenänderungen vor der Ausführung den sichtbaren Block.

Syntax

c
u8 vram_queue_bg_block(u16 base, u8 x, u8 y, u8 w, u8 h, const u8* src);

Parameter

base

Kachel- und Rechteckbefehle verwenden das zur Übersetzung festgelegte VRAM_NT_BASE, standardmäßig 0x2000. Blockübertragungen verwenden die angegebene Nametable-Basis (0x2000, 0x2400, 0x2800 oder 0x2C00); Nametable-Spiegelung gilt weiterhin. Adressen werden beim Einreihen mit 32 Bytes je Zeile berechnet. Bleiben Sie innerhalb von 32 × 30 Kacheln, um Attributbytes nicht zu überschreiben.

x, y

Linke obere Position in 8×8-Tiles, nicht Pixeln. Es erfolgt kein Abschneiden. Halten Sie x + w <= 32 und auf GB y + h <= 32, im Tile-Bereich einer FC-Nametable <= 30 ein. Ein einzelnes Tile hat Breite und Höhe 1.

w, h

Breite und Höhe in Tiles als vorzeichenlose Bytes. Der Quellblock enthält zeilenweise w * h Bytes. Nullabmessungen erzeugen keine sichtbaren Schreibzugriffe; der Platzbedarf folgt dennoch den Plattformregeln.

src

Nahzeiger auf lesbare Bytes, der bis zur Ausführung gespeichert bleibt. Daten und ihre Speicher- oder ROM-Bank müssen während der gesamten Verarbeitung gültig und eingeblendet bleiben; weder Banknummer noch Kopie werden gespeichert. Nichtleere Übertragungen benötigen eine gültige Quelle. Verwenden Sie kein abgelaufenes lokales Array.

Rückgabewert

1, wenn nach dem Versuch keine Überlaufmeldung gesetzt ist, andernfalls 0. Auch bei passendem aktuellem Eintrag kann ein früherer Überlauf 0 verursachen. Mehrteilige Operationen können teilweise eingereiht bleiben; ein Rückgängigmachen erfolgt nicht. Selbst eine Länge von null kann wegen einer vorhandenen Meldung 0 liefern.

Bedingungen und Grenzen

FC zählt codierte Befehlsbytes in einem festen intrinsischen 128-Byte-Puffer. Ein Tile-Schreibbefehl braucht 4 Bytes, ein Fülleintrag 5 und eine Zeigerkopie 6 einschließlich Metadaten. NMI kann eine bereite Warteschlange verarbeiten; prüfen und befüllen Sie sie vor der Freigabe und koordinieren Sie Erzeuger und Verbraucher.

Dieser Aufruf benötigt 6 * h Befehlspuffer-Bytes für die vollständige Operation. Die Formel zählt codierte Einträge einschließlich Metadaten, nicht die übertragenen Nutzdaten. Prüfen Sie vor mehrteiligen Operationen den freien Platz.

Kachel- und Rechteckbefehle verwenden das zur Übersetzung festgelegte VRAM_NT_BASE, standardmäßig 0x2000. Blockübertragungen verwenden die angegebene Nametable-Basis (0x2000, 0x2400, 0x2800 oder 0x2C00); Nametable-Spiegelung gilt weiterhin. Adressen werden beim Einreihen mit 32 Bytes je Zeile berechnet. Bleiben Sie innerhalb von 32 × 30 Kacheln, um Attributbytes nicht zu überschreiben.

Jede Zeile verwendet einen Eintrag. Höhe 0 fügt keinen hinzu; Breite 0 fügt weiterhin einen je Zeile hinzu, schreibt aber keine Bytes. Zeilenkoordinaten werden in u8 umgewandelt; y + row läuft bei 256 um. Begrenzung und Rücknahme teilweiser Einträge erfolgen nicht.

Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.

Anwendungsbeispiel

c
check_result=vram_queue_bg_block(MAP_BASE,10,4,3,2,block);
block[0]=1; // The queued pointer sees this change when the queue executes.
if (check_result!=1) failures++;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.

Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.

Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.

Auf FC kennzeichnet Rot die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat. Blau kennzeichnet das Rechteck von 32 × 24 und die Kopie aus zwei Mustern. Grün kennzeichnet den Block aus 3 × 2 Kacheln und den Balken von 40 × 8. Der Hintergrund ist schwarz; Position und Farbe jedes gezeichneten Pixels werden geprüft.

vram_queue_bg_block: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vram.h:27

Deklarationshinweise im Original
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

c
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

Stellt ein Hintergrundkartenrechteck aus derselben Tile-Nummer in die Warteschlange. Die linke obere Tile-Position ist (x, y), die Größe w × h Tiles. Ein einfarbiges Tile ergibt ein gefülltes Rechteck; ein gemustertes wiederholt sein Muster in jeder Zelle.

Syntax

c
u8 vram_queue_bg_rect(u8 x, u8 y, u8 w, u8 h, u8 tile);

Parameter

x, y

Linke obere Position in 8×8-Tiles, nicht Pixeln. Es erfolgt kein Abschneiden. Halten Sie x + w <= 32 und auf GB y + h <= 32, im Tile-Bereich einer FC-Nametable <= 30 ein. Ein einzelnes Tile hat Breite und Höhe 1.

w, h

Breite und Höhe in Tiles als vorzeichenlose Bytes. Der Quellblock enthält zeilenweise w * h Bytes. Nullabmessungen erzeugen keine sichtbaren Schreibzugriffe; der Platzbedarf folgt dennoch den Plattformregeln.

tile

Tile-Kartenbyte von 0 bis 255. Laden Sie die Grafik separat und wählen Sie die passende Mustertabelle beziehungsweise Adressierungsart. Eine Tile-Nummer ist weder Zeiger noch Farbwert.

Rückgabewert

1, wenn nach dem Versuch keine Überlaufmeldung gesetzt ist, andernfalls 0. Auch bei passendem aktuellem Eintrag kann ein früherer Überlauf 0 verursachen. Mehrteilige Operationen können teilweise eingereiht bleiben; ein Rückgängigmachen erfolgt nicht. Selbst eine Länge von null kann wegen einer vorhandenen Meldung 0 liefern.

Bedingungen und Grenzen

FC zählt codierte Befehlsbytes in einem festen intrinsischen 128-Byte-Puffer. Ein Tile-Schreibbefehl braucht 4 Bytes, ein Fülleintrag 5 und eine Zeigerkopie 6 einschließlich Metadaten. NMI kann eine bereite Warteschlange verarbeiten; prüfen und befüllen Sie sie vor der Freigabe und koordinieren Sie Erzeuger und Verbraucher.

Dieser Aufruf benötigt 5 * h Befehlspuffer-Bytes für die vollständige Operation. Die Formel zählt codierte Einträge einschließlich Metadaten, nicht die übertragenen Nutzdaten. Prüfen Sie vor mehrteiligen Operationen den freien Platz.

Kachel- und Rechteckbefehle verwenden das zur Übersetzung festgelegte VRAM_NT_BASE, standardmäßig 0x2000. Blockübertragungen verwenden die angegebene Nametable-Basis (0x2000, 0x2400, 0x2800 oder 0x2C00); Nametable-Spiegelung gilt weiterhin. Adressen werden beim Einreihen mit 32 Bytes je Zeile berechnet. Bleiben Sie innerhalb von 32 × 30 Kacheln, um Attributbytes nicht zu überschreiben.

Jede Zeile verwendet einen Eintrag. Höhe 0 fügt keinen hinzu; Breite 0 fügt weiterhin einen je Zeile hinzu, schreibt aber keine Bytes. Zeilenkoordinaten werden in u8 umgewandelt; y + row läuft bei 256 um. Begrenzung und Rücknahme teilweiser Einträge erfolgen nicht.

Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.

Anwendungsbeispiel

c
check_result=vram_queue_bg_rect(2,4,4,3,1); // A filled 32x24 rectangle at (16,32).
if (check_result!=1) failures++;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.

Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.

Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.

Auf FC kennzeichnet Rot die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat. Blau kennzeichnet das Rechteck von 32 × 24 und die Kopie aus zwei Mustern. Grün kennzeichnet den Block aus 3 × 2 Kacheln und den Balken von 40 × 8. Der Hintergrund ist schwarz; Position und Farbe jedes gezeichneten Pixels werden geprüft.

vram_queue_bg_rect: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vram.h:23

Deklarationshinweise im Original
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

c
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

Stellt einen Schreibbefehl für eine Hintergrund-Tile-Nummer an (x, y) in die Warteschlange. Sichtbar wird die Änderung bei deren Ausführung. Geschrieben wird ein Karteneintrag, weder Pixeldaten noch Palettenattribute.

Syntax

c
u8 vram_queue_bg_tile(u8 x, u8 y, u8 tile);

Parameter

x, y

Linke obere Position in 8×8-Tiles, nicht Pixeln. Es erfolgt kein Abschneiden. Halten Sie x + w <= 32 und auf GB y + h <= 32, im Tile-Bereich einer FC-Nametable <= 30 ein. Ein einzelnes Tile hat Breite und Höhe 1.

tile

Tile-Kartenbyte von 0 bis 255. Laden Sie die Grafik separat und wählen Sie die passende Mustertabelle beziehungsweise Adressierungsart. Eine Tile-Nummer ist weder Zeiger noch Farbwert.

Rückgabewert

1, wenn nach dem Versuch keine Überlaufmeldung gesetzt ist, andernfalls 0. Auch bei passendem aktuellem Eintrag kann ein früherer Überlauf 0 verursachen. Mehrteilige Operationen können teilweise eingereiht bleiben; ein Rückgängigmachen erfolgt nicht. Selbst eine Länge von null kann wegen einer vorhandenen Meldung 0 liefern.

Bedingungen und Grenzen

FC zählt codierte Befehlsbytes in einem festen intrinsischen 128-Byte-Puffer. Ein Tile-Schreibbefehl braucht 4 Bytes, ein Fülleintrag 5 und eine Zeigerkopie 6 einschließlich Metadaten. NMI kann eine bereite Warteschlange verarbeiten; prüfen und befüllen Sie sie vor der Freigabe und koordinieren Sie Erzeuger und Verbraucher.

Dieser Aufruf benötigt 4 Befehlspuffer-Bytes für die vollständige Operation. Die Formel zählt codierte Einträge einschließlich Metadaten, nicht die übertragenen Nutzdaten. Prüfen Sie vor mehrteiligen Operationen den freien Platz.

Kachel- und Rechteckbefehle verwenden das zur Übersetzung festgelegte VRAM_NT_BASE, standardmäßig 0x2000. Blockübertragungen verwenden die angegebene Nametable-Basis (0x2000, 0x2400, 0x2800 oder 0x2C00); Nametable-Spiegelung gilt weiterhin. Adressen werden beim Einreihen mit 32 Bytes je Zeile berechnet. Bleiben Sie innerhalb von 32 × 30 Kacheln, um Attributbytes nicht zu überschreiben.

Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.

Anwendungsbeispiel

c
check_result=vram_queue_bg_tile(2,2,1); // A solid 8x8 tile at pixel (16,16).
if (check_result!=1) failures++;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.

Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.

Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.

Auf FC kennzeichnet Rot die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat. Blau kennzeichnet das Rechteck von 32 × 24 und die Kopie aus zwei Mustern. Grün kennzeichnet den Block aus 3 × 2 Kacheln und den Balken von 40 × 8. Der Hintergrund ist schwarz; Position und Farbe jedes gezeichneten Pixels werden geprüft.

vram_queue_bg_tile: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vram.h:18

Deklarationshinweise im Original
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

c
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

Stellt eine Kopie von len aufeinanderfolgenden Bytes von src nach dst bereit. Beide Adressen steigen byteweise ohne Tile-Zeilensprung. Übertragbar sind Kartenbytes oder beschreibbare Musterdaten; Formate werden nicht umgewandelt und die Bytezahl eines Tiles wird nicht ermittelt.

Syntax

c
u8 vram_queue_memcpy(u16 dst, const void* src, u16 len);

Parameter

dst

PPU-Byteadresse (0x0000–0x3FFF), kein CPU-Zeiger. Das Ziel muss beschreibbar sein: Musteränderungen benötigen CHR-RAM statt CHR-ROM. PPU-Adressabbildung und Spiegelung gelten weiterhin. Wählen Sie für fortlaufendes Kopieren und Füllen die Schrittweite 1 in PPUCTRL. Führen Sie Befehle zu einem sicheren PPU-Zeitpunkt aus und stellen Sie danach den Scrollzustand her; der Ausführer schreibt PPUADDR und PPUDATA, ohne Scrolleinstellungen wiederherzustellen.

src

Nahzeiger auf lesbare Bytes, der bis zur Ausführung gespeichert bleibt. Daten und ihre Speicher- oder ROM-Bank müssen während der gesamten Verarbeitung gültig und eingeblendet bleiben; weder Banknummer noch Kopie werden gespeichert. Nichtleere Übertragungen benötigen eine gültige Quelle. Verwenden Sie kein abgelaufenes lokales Array.

len

Anzahl aufeinanderfolgender Bytes von 0 bis 65535, keine Tile-Anzahl. Der gesamte Bereich muss in gültiger Quelle und beschreibbarem Ziel liegen; die API prüft keine Grenzen und verhindert keinen 16-Bit-Adressüberlauf.

Rückgabewert

1, wenn nach dem Versuch keine Überlaufmeldung gesetzt ist, andernfalls 0. Auch bei passendem aktuellem Eintrag kann ein früherer Überlauf 0 verursachen. Mehrteilige Operationen können teilweise eingereiht bleiben; ein Rückgängigmachen erfolgt nicht. Selbst eine Länge von null kann wegen einer vorhandenen Meldung 0 liefern.

Bedingungen und Grenzen

FC zählt codierte Befehlsbytes in einem festen intrinsischen 128-Byte-Puffer. Ein Tile-Schreibbefehl braucht 4 Bytes, ein Fülleintrag 5 und eine Zeigerkopie 6 einschließlich Metadaten. NMI kann eine bereite Warteschlange verarbeiten; prüfen und befüllen Sie sie vor der Freigabe und koordinieren Sie Erzeuger und Verbraucher.

Dieser Aufruf benötigt 6 * ceil(len / 127) Befehlspuffer-Bytes für die vollständige Operation. Die Formel zählt codierte Einträge einschließlich Metadaten, nicht die übertragenen Nutzdaten. Prüfen Sie vor mehrteiligen Operationen den freien Platz.

Teilt len in Abschnitte von höchstens 127 Bytes; ceil bedeutet Aufrunden. len=0 fügt keinen Eintrag hinzu. Diese Teilung gehört zur Bibliotheksfunktion; das darunterliegende Intrinsic akzeptiert einen vorzeichenlosen 8-Bit-Zähler. Nach Überlauf folgen weitere Einfügeversuche, ohne frühere Einträge zurückzunehmen.

Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.

Anwendungsbeispiel

c
check_result=vram_queue_memcpy(MAP_BASE+8*32+2,strip,3);
if (check_result!=1) failures++; // Copy three map bytes, not three tile patterns.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.

Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.

Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.

Auf FC kennzeichnet Rot die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat. Blau kennzeichnet das Rechteck von 32 × 24 und die Kopie aus zwei Mustern. Grün kennzeichnet den Block aus 3 × 2 Kacheln und den Balken von 40 × 8. Der Hintergrund ist schwarz; Position und Farbe jedes gezeichneten Pixels werden geprüft.

vram_queue_memcpy: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vram.h:31

Deklarationshinweise im Original
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

c
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

Stellt das Füllen von len aufeinanderfolgenden Bytes ab dst mit dem Byte value bereit. Wiederholt wird ein Byte, kein mehrteiliges Tile-Muster; ein Kartenzeilenabstand von 32 Bytes wird nicht eingefügt.

Syntax

c
u8 vram_queue_memset(u16 dst, u8 value, u16 len);

Parameter

dst

PPU-Byteadresse (0x0000–0x3FFF), kein CPU-Zeiger. Das Ziel muss beschreibbar sein: Musteränderungen benötigen CHR-RAM statt CHR-ROM. PPU-Adressabbildung und Spiegelung gelten weiterhin. Wählen Sie für fortlaufendes Kopieren und Füllen die Schrittweite 1 in PPUCTRL. Führen Sie Befehle zu einem sicheren PPU-Zeitpunkt aus und stellen Sie danach den Scrollzustand her; der Ausführer schreibt PPUADDR und PPUDATA, ohne Scrolleinstellungen wiederherzustellen.

value

Ein wiederholtes Byte von 0 bis 255. Seine sichtbare Wirkung hängt davon ab, ob das Ziel Tile-Indizes, Pixelebenen oder eine andere Bytestruktur enthält.

len

Anzahl aufeinanderfolgender Bytes von 0 bis 65535, keine Tile-Anzahl. Der gesamte Bereich muss in gültiger Quelle und beschreibbarem Ziel liegen; die API prüft keine Grenzen und verhindert keinen 16-Bit-Adressüberlauf.

Rückgabewert

1, wenn nach dem Versuch keine Überlaufmeldung gesetzt ist, andernfalls 0. Auch bei passendem aktuellem Eintrag kann ein früherer Überlauf 0 verursachen. Mehrteilige Operationen können teilweise eingereiht bleiben; ein Rückgängigmachen erfolgt nicht. Selbst eine Länge von null kann wegen einer vorhandenen Meldung 0 liefern.

Bedingungen und Grenzen

FC zählt codierte Befehlsbytes in einem festen intrinsischen 128-Byte-Puffer. Ein Tile-Schreibbefehl braucht 4 Bytes, ein Fülleintrag 5 und eine Zeigerkopie 6 einschließlich Metadaten. NMI kann eine bereite Warteschlange verarbeiten; prüfen und befüllen Sie sie vor der Freigabe und koordinieren Sie Erzeuger und Verbraucher.

Dieser Aufruf benötigt 5 * ceil(len / 127) Befehlspuffer-Bytes für die vollständige Operation. Die Formel zählt codierte Einträge einschließlich Metadaten, nicht die übertragenen Nutzdaten. Prüfen Sie vor mehrteiligen Operationen den freien Platz.

Teilt len in Abschnitte von höchstens 127 Bytes; ceil bedeutet Aufrunden. len=0 fügt keinen Eintrag hinzu. Diese Teilung gehört zur Bibliotheksfunktion; das darunterliegende Intrinsic akzeptiert einen vorzeichenlosen 8-Bit-Zähler. Nach Überlauf folgen weitere Einfügeversuche, ohne frühere Einträge zurückzunehmen.

Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.

Anwendungsbeispiel

c
check_result=vram_queue_memset(MAP_BASE+8*32+10,1,5);
if (check_result!=1) failures++; // Five solid tiles form a 40x8 horizontal bar.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.

Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.

Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.

Auf FC kennzeichnet Rot die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat. Blau kennzeichnet das Rechteck von 32 × 24 und die Kopie aus zwei Mustern. Grün kennzeichnet den Block aus 3 × 2 Kacheln und den Balken von 40 × 8. Der Hintergrund ist schwarz; Position und Farbe jedes gezeichneten Pixels werden geprüft.

vram_queue_memset: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vram.h:36

Deklarationshinweise im Original
Queue fills of at most 127 bytes each. Overflow can leave a partially queued
transfer; no rollback is performed.

kitaqfc/lib/vram.c:94

c
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 ruft vram_queue_bg_tile direkt mit denselben Argumenten auf und gibt dessen Ergebnis zurück. Der Kurzname schreibt einen Hintergrundkarteneintrag; er bearbeitet keine Sprites und lädt keine Tile-Grafiken.

Syntax

c
u8 vram_queue_tile(u8 x, u8 y, u8 tile);

Parameter

x, y

Linke obere Position in 8×8-Tiles, nicht Pixeln. Es erfolgt kein Abschneiden. Halten Sie x + w <= 32 und auf GB y + h <= 32, im Tile-Bereich einer FC-Nametable <= 30 ein. Ein einzelnes Tile hat Breite und Höhe 1.

tile

Tile-Kartenbyte von 0 bis 255. Laden Sie die Grafik separat und wählen Sie die passende Mustertabelle beziehungsweise Adressierungsart. Eine Tile-Nummer ist weder Zeiger noch Farbwert.

Rückgabewert

1, wenn nach dem Versuch keine Überlaufmeldung gesetzt ist, andernfalls 0. Auch bei passendem aktuellem Eintrag kann ein früherer Überlauf 0 verursachen. Mehrteilige Operationen können teilweise eingereiht bleiben; ein Rückgängigmachen erfolgt nicht. Selbst eine Länge von null kann wegen einer vorhandenen Meldung 0 liefern.

Bedingungen und Grenzen

FC zählt codierte Befehlsbytes in einem festen intrinsischen 128-Byte-Puffer. Ein Tile-Schreibbefehl braucht 4 Bytes, ein Fülleintrag 5 und eine Zeigerkopie 6 einschließlich Metadaten. NMI kann eine bereite Warteschlange verarbeiten; prüfen und befüllen Sie sie vor der Freigabe und koordinieren Sie Erzeuger und Verbraucher.

Dieser Aufruf benötigt 4 Befehlspuffer-Bytes für die vollständige Operation. Die Formel zählt codierte Einträge einschließlich Metadaten, nicht die übertragenen Nutzdaten. Prüfen Sie vor mehrteiligen Operationen den freien Platz.

Kachel- und Rechteckbefehle verwenden das zur Übersetzung festgelegte VRAM_NT_BASE, standardmäßig 0x2000. Blockübertragungen verwenden die angegebene Nametable-Basis (0x2000, 0x2400, 0x2800 oder 0x2C00); Nametable-Spiegelung gilt weiterhin. Adressen werden beim Einreihen mit 32 Bytes je Zeile berechnet. Bleiben Sie innerhalb von 32 × 30 Kacheln, um Attributbytes nicht zu überschreiben.

Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.

Anwendungsbeispiel

c
check_result=vram_queue_tile(4,2,1); // The short alias draws at pixel (32,16).
if (check_result!=1) failures++;

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.

Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.

Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.

Auf FC kennzeichnet Rot die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat. Blau kennzeichnet das Rechteck von 32 × 24 und die Kopie aus zwei Mustern. Grün kennzeichnet den Block aus 3 × 2 Kacheln und den Balken von 40 × 8. Der Hintergrund ist schwarz; Position und Farbe jedes gezeichneten Pixels werden geprüft.

vram_queue_tile: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vram.h:20

Deklarationshinweise im Original
Alias the queued background-tile operation.

kitaqfc/lib/vram.c:32

c
u8 vram_queue_tile(u8 x, u8 y, u8 tile)
{
    return vram_queue_bg_tile(x, y, tile);
}
vram_queue_tiles

vram_queue_tiles ruft direkt vram_queue_memcpy auf. len zählt weiterhin Bytes statt Tiles. Quellzeiger, Warteschlangeneinträge, Rückgabewert und Ausführungszeitpunkt sind identisch.

Syntax

c
u8 vram_queue_tiles(u16 dst, const void* src, u16 len);

Parameter

dst

PPU-Byteadresse (0x0000–0x3FFF), kein CPU-Zeiger. Das Ziel muss beschreibbar sein: Musteränderungen benötigen CHR-RAM statt CHR-ROM. PPU-Adressabbildung und Spiegelung gelten weiterhin. Wählen Sie für fortlaufendes Kopieren und Füllen die Schrittweite 1 in PPUCTRL. Führen Sie Befehle zu einem sicheren PPU-Zeitpunkt aus und stellen Sie danach den Scrollzustand her; der Ausführer schreibt PPUADDR und PPUDATA, ohne Scrolleinstellungen wiederherzustellen.

src

Nahzeiger auf lesbare Bytes, der bis zur Ausführung gespeichert bleibt. Daten und ihre Speicher- oder ROM-Bank müssen während der gesamten Verarbeitung gültig und eingeblendet bleiben; weder Banknummer noch Kopie werden gespeichert. Nichtleere Übertragungen benötigen eine gültige Quelle. Verwenden Sie kein abgelaufenes lokales Array.

len

Anzahl aufeinanderfolgender Bytes von 0 bis 65535, keine Tile-Anzahl. Der gesamte Bereich muss in gültiger Quelle und beschreibbarem Ziel liegen; die API prüft keine Grenzen und verhindert keinen 16-Bit-Adressüberlauf.

Rückgabewert

1, wenn nach dem Versuch keine Überlaufmeldung gesetzt ist, andernfalls 0. Auch bei passendem aktuellem Eintrag kann ein früherer Überlauf 0 verursachen. Mehrteilige Operationen können teilweise eingereiht bleiben; ein Rückgängigmachen erfolgt nicht. Selbst eine Länge von null kann wegen einer vorhandenen Meldung 0 liefern.

Bedingungen und Grenzen

FC zählt codierte Befehlsbytes in einem festen intrinsischen 128-Byte-Puffer. Ein Tile-Schreibbefehl braucht 4 Bytes, ein Fülleintrag 5 und eine Zeigerkopie 6 einschließlich Metadaten. NMI kann eine bereite Warteschlange verarbeiten; prüfen und befüllen Sie sie vor der Freigabe und koordinieren Sie Erzeuger und Verbraucher.

Dieser Aufruf benötigt 6 * ceil(len / 127) Befehlspuffer-Bytes für die vollständige Operation. Die Formel zählt codierte Einträge einschließlich Metadaten, nicht die übertragenen Nutzdaten. Prüfen Sie vor mehrteiligen Operationen den freien Platz.

Teilt len in Abschnitte von höchstens 127 Bytes; ceil bedeutet Aufrunden. len=0 fügt keinen Eintrag hinzu. Diese Teilung gehört zur Bibliotheksfunktion; das darunterliegende Intrinsic akzeptiert einen vorzeichenlosen 8-Bit-Zähler. Nach Überlauf folgen weitere Einfügeversuche, ohne frühere Einträge zurückzunehmen.

Koordinieren Sie Aufbau und Verarbeitung der Warteschlange. Fügen Sie während ihrer Interrupt-Ausführung nichts hinzu, ändern Sie die Verwaltung nicht direkt und überschreiben Sie gespeicherte Quelldaten nicht versehentlich. Diese APIs bieten weder Sperren noch Doppelpufferung. Die Kapazität betrifft den Befehlspuffer, nicht freie Bytes im Hardware-VRAM.

Anwendungsbeispiel

c
check_result=vram_queue_tiles(MAP_BASE+8*32+6,strip+1,2);
if (check_result!=1) failures++; // This alias also measures length in bytes.

Dieser Ausschnitt zeigt den Aufruf. Beachten Sie beim Einbau in ein vollständiges Programm die angegebenen Anforderungen an Initialisierung und Puffer.

Erwartetes Ergebnis

Das vollständige Programm zeigt aufgeschobene Schreibzugriffe, Kapazitätsverwaltung und die Behandlung eines Überlaufs. Sieben Zeichenaufrufe belegen auf dem GB 7 von 32 Plätzen, auf dem FC 52 von 128 Bytes: CAPACITY/USED/FREE zeigt 032/007/025 oder 128/052/076. AFTER FLUSH und FAILED CHECKS müssen 000 anzeigen, OVERFLOW SEEN dagegen 001. Ein absichtlicher Einfügeversuch in die volle Warteschlange prüft die Meldung: Lesen und Ausführen löschen sie nicht, das Leeren der Warteschlange schon. Auf dem FC muss eine direkte Ausführung ohne Freigabe die Warteschlange unverändert lassen.

Bildkoordinaten sind Pixelangaben ab der linken oberen Ecke. Erwartet werden ausgefüllte Quadrate von 8 × 8 bei (16,16) und (32,16), ein ausgefülltes Rechteck von 32 × 24 bei (16,32) sowie ein waagerechter Balken von 40 × 8 bei (80,64). Der letzte VBlank-Schreibzugriff ergänzt ein Quadrat von 8 × 8 bei (144,80). Die verworfene Schreibposition (144,24) muss leer bleiben. DMG zeigt schwarze Formen auf Weiß, CGB rote, blaue und grüne Formen auf Weiß und FC rote, blaue und grüne Formen auf Schwarz. Diese Emulatorbilder sind keine Prüfung auf echter Hardware.

Drei eigene Muster von 8 × 8 unterscheiden die Kopiervorgänge: Kachel 1 ist ausgefüllt, Kachel 2 füllt die vier linken Spalten, Kachel 3 bildet ein linksbündiges Dreieck mit einem Pixel Breite oben und acht unten. Der Block aus 3 × 2 Kacheln bei (80,32) muss [1,2,3] / [3,0,2] zeigen; 0 ist leer. Sein erstes Quellbyte ändert sich nach dem Einreihen. Die ausgefüllte Kachel oben links belegt deshalb, dass der Quellzeiger erhalten bleibt. Die Kopie bei (16,64) zeigt [1,2,3], der Alias tiles bei (48,64) zeigt [2,3]. Die Größen betragen entsprechend 24 × 16, 24 × 8 und 16 × 8 Pixel.

Auf FC kennzeichnet Rot die beiden oberen Quadrate, die Kopie aus drei Mustern und das letzte VBlank-Quadrat. Blau kennzeichnet das Rechteck von 32 × 24 und die Kopie aus zwei Mustern. Grün kennzeichnet den Block aus 3 × 2 Kacheln und den Balken von 40 × 8. Der Hintergrund ist schwarz; Position und Farbe jedes gezeichneten Pixels werden geprüft.

vram_queue_tiles: NROM
NROM

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vram.h:33

Deklarationshinweise im Original
Alias the byte-copy queue helper; len remains a byte count, not a tile count.

kitaqfc/lib/vram.c:87

c
u8 vram_queue_tiles(u16 dst, const void* src, u16 len)
{
    return vram_queue_memcpy(dst, src, len);
}

vrc6_sound.h — VRC6-Audioerweiterung

Verwenden Sie --mapper=vrc6 (Mapper 24) für diese Registerverdrahtung. Eine Cartridge ohne VRC6 kann diese Stimmen nicht erzeugen. Nur die unteren zwölf Periodenbits werden genutzt; die Hilfen konfigurieren das Frequenzsteuerregister $9003 nicht.

VRC6_PULSE_DUTY_12/25/50/75 bezeichnen 0x00/0x10/0x20/0x30. Die Suffixe sind keine gemessenen Tastgradprozentsätze. KUROSAKI modelliert Code d als (d+1)/16.

nes_vrc6_pulse1_off

Stoppt VRC6-Puls 1 durch Löschen des oberen Timer-/Aktivierungsregisters.

Syntax

c
void nes_vrc6_pulse1_off(void);

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Bedingungen und Grenzen

Verwenden Sie --mapper=vrc6 (Mapper 24) für diese Registerverdrahtung. Eine Cartridge ohne VRC6 kann diese Stimmen nicht erzeugen. Nur die unteren zwölf Periodenbits werden genutzt; die Hilfen konfigurieren das Frequenzsteuerregister $9003 nicht.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Es folgen VRC6-Puls 1, Puls 2 mit anderem Tastgrad und Sägezahn, jeweils 45 Frames mit 15 Frames Pause. Alle drei liegen bei etwa 440 Hz und stoppen am Ende.

nes_vrc6_pulse1_off: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vrc6_sound.h:22

Deklarationshinweise im Original
Disable pulse 1 by clearing its high timer/enable register.

kitaqfc/lib/vrc6_sound.c:43

c
void nes_vrc6_pulse1_off(void)
{
    VRC6_P1_HI = 0x00;
}
nes_vrc6_pulse1_set

Schreibt VRC6-Puls-1-Steuerwert und 12-Bit-Timer und aktiviert die Stimme.

Syntax

c
void nes_vrc6_pulse1_set(u8 control, u16 period);

Parameter

control

VRC6-Pulssteuerung: Bit 7 Gate, Bits 6..4 Tastgradcode, unteres Halbbyte Lautstärke 0..15.

period

12-Bit-Timer 0..4095; obere Bits werden verworfen. Das Beispiel nutzt Puls 253 und Sägezahn 289.

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Bedingungen und Grenzen

Verwenden Sie --mapper=vrc6 (Mapper 24) für diese Registerverdrahtung. Eine Cartridge ohne VRC6 kann diese Stimmen nicht erzeugen. Nur die unteren zwölf Periodenbits werden genutzt; die Hilfen konfigurieren das Frequenzsteuerregister $9003 nicht.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Es folgen VRC6-Puls 1, Puls 2 mit anderem Tastgrad und Sägezahn, jeweils 45 Frames mit 15 Frames Pause. Alle drei liegen bei etwa 440 Hz und stoppen am Ende.

nes_vrc6_pulse1_set: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vrc6_sound.h:18

Deklarationshinweise im Original
Write pulse-1 control and the low 12 timer bits, then enable the channel.

kitaqfc/lib/vrc6_sound.c:27

c
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

Stoppt VRC6-Puls 2 durch Löschen des oberen Timer-/Aktivierungsregisters.

Syntax

c
void nes_vrc6_pulse2_off(void);

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Bedingungen und Grenzen

Verwenden Sie --mapper=vrc6 (Mapper 24) für diese Registerverdrahtung. Eine Cartridge ohne VRC6 kann diese Stimmen nicht erzeugen. Nur die unteren zwölf Periodenbits werden genutzt; die Hilfen konfigurieren das Frequenzsteuerregister $9003 nicht.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Es folgen VRC6-Puls 1, Puls 2 mit anderem Tastgrad und Sägezahn, jeweils 45 Frames mit 15 Frames Pause. Alle drei liegen bei etwa 440 Hz und stoppen am Ende.

nes_vrc6_pulse2_off: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vrc6_sound.h:24

Deklarationshinweise im Original
Disable pulse 2 by clearing its high timer/enable register.

kitaqfc/lib/vrc6_sound.c:49

c
void nes_vrc6_pulse2_off(void)
{
    VRC6_P2_HI = 0x00;
}
nes_vrc6_pulse2_set

Schreibt VRC6-Puls-2-Steuerwert und 12-Bit-Timer und aktiviert die Stimme.

Syntax

c
void nes_vrc6_pulse2_set(u8 control, u16 period);

Parameter

control

VRC6-Pulssteuerung: Bit 7 Gate, Bits 6..4 Tastgradcode, unteres Halbbyte Lautstärke 0..15.

period

12-Bit-Timer 0..4095; obere Bits werden verworfen. Das Beispiel nutzt Puls 253 und Sägezahn 289.

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Bedingungen und Grenzen

Verwenden Sie --mapper=vrc6 (Mapper 24) für diese Registerverdrahtung. Eine Cartridge ohne VRC6 kann diese Stimmen nicht erzeugen. Nur die unteren zwölf Periodenbits werden genutzt; die Hilfen konfigurieren das Frequenzsteuerregister $9003 nicht.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Es folgen VRC6-Puls 1, Puls 2 mit anderem Tastgrad und Sägezahn, jeweils 45 Frames mit 15 Frames Pause. Alle drei liegen bei etwa 440 Hz und stoppen am Ende.

nes_vrc6_pulse2_set: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vrc6_sound.h:20

Deklarationshinweise im Original
Write pulse-2 control and the low 12 timer bits, then enable the channel.

kitaqfc/lib/vrc6_sound.c:35

c
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

Stoppt den VRC6-Sägezahn durch Löschen des oberen Timer-/Aktivierungsregisters.

Syntax

c
void nes_vrc6_saw_off(void);

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Bedingungen und Grenzen

Verwenden Sie --mapper=vrc6 (Mapper 24) für diese Registerverdrahtung. Eine Cartridge ohne VRC6 kann diese Stimmen nicht erzeugen. Nur die unteren zwölf Periodenbits werden genutzt; die Hilfen konfigurieren das Frequenzsteuerregister $9003 nicht.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Es folgen VRC6-Puls 1, Puls 2 mit anderem Tastgrad und Sägezahn, jeweils 45 Frames mit 15 Frames Pause. Alle drei liegen bei etwa 440 Hz und stoppen am Ende.

nes_vrc6_saw_off: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vrc6_sound.h:28

Deklarationshinweise im Original
Disable the saw channel by clearing its high timer/enable register.

kitaqfc/lib/vrc6_sound.c:63

c
void nes_vrc6_saw_off(void)
{
    VRC6_SAW_HI = 0x00;
}
nes_vrc6_saw_set

Schreibt die 6-Bit-Akkumulatorrate und den 12-Bit-Timer des VRC6-Sägezahns und aktiviert ihn.

Syntax

c
void nes_vrc6_saw_set(u8 rate, u16 period);

Parameter

rate

Sägezahn-Akkumulatorzuwachs 0..63; nur die unteren sechs Bits werden verwendet.

period

12-Bit-Timer 0..4095; obere Bits werden verworfen. Das Beispiel nutzt Puls 253 und Sägezahn 289.

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Bedingungen und Grenzen

Verwenden Sie --mapper=vrc6 (Mapper 24) für diese Registerverdrahtung. Eine Cartridge ohne VRC6 kann diese Stimmen nicht erzeugen. Nur die unteren zwölf Periodenbits werden genutzt; die Hilfen konfigurieren das Frequenzsteuerregister $9003 nicht.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Es folgen VRC6-Puls 1, Puls 2 mit anderem Tastgrad und Sägezahn, jeweils 45 Frames mit 15 Frames Pause. Alle drei liegen bei etwa 440 Hz und stoppen am Ende.

nes_vrc6_saw_set: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vrc6_sound.h:26

Deklarationshinweise im Original
Mask the saw accumulation rate to six bits, load a 12-bit timer and enable output.

kitaqfc/lib/vrc6_sound.c:55

c
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

Deaktiviert alle drei VRC6-Stimmen und löscht Pulssteuerwerte sowie Sägezahnrate.

Syntax

c
void nes_vrc6_silence_all(void);

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Bedingungen und Grenzen

Verwenden Sie --mapper=vrc6 (Mapper 24) für diese Registerverdrahtung. Eine Cartridge ohne VRC6 kann diese Stimmen nicht erzeugen. Nur die unteren zwölf Periodenbits werden genutzt; die Hilfen konfigurieren das Frequenzsteuerregister $9003 nicht.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Es folgen VRC6-Puls 1, Puls 2 mit anderem Tastgrad und Sägezahn, jeweils 45 Frames mit 15 Frames Pause. Alle drei liegen bei etwa 440 Hz und stoppen am Ende.

nes_vrc6_silence_all: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vrc6_sound.h:16

Deklarationshinweise im Original
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

c
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 — VRC7-FM-Audio

Für --mapper=vrc7 (Mapper 85). Schützen Sie Registerauswahl-/Datenpaare gegen dazwischenliegende Interruptschreibzugriffe. Die Hilfen fügen keine Einschwingverzögerung ein. Aufnahmen erfassen KUROSAKIs FM-Modell und bestätigen weder Hardwareklangfarbe noch reales Schreibtiming.

nes_vrc7_channel_set

Konfiguriert Frequenz, Block, Key-Flags, Instrument und Dämpfung einer FM-Stimme.

Syntax

c
void nes_vrc7_channel_set(u8 channel, u8 instrument, u8 volume, u16 fnum, u8 block, u8 key_flags);

Parameter

channel

VRC7-Kanal 0..5; größere Werte bewirken nichts.

instrument

Instrument 0..15: 0=Benutzerklang, 1..15=Vorgaben. Nur das untere Halbbyte wird genutzt.

volume

VRC7-Dämpfung 0..15: 0 ist am lautesten, 15 die stärkste Dämpfung. Nur das untere Halbbyte wird genutzt.

fnum

Frequenzzahl 0..511, die zusammen mit block die Tonhöhe bestimmt. Nur neun Bits werden genutzt.

block

Oktavblock 0..7; nur die unteren drei Bits werden genutzt.

key_flags

0x10 Key-on, 0x20 Sustain-Flag; andere Bits werden verworfen.

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Bedingungen und Grenzen

Für --mapper=vrc7 (Mapper 85). Schützen Sie Registerauswahl-/Datenpaare gegen dazwischenliegende Interruptschreibzugriffe. Die Hilfen fügen keine Einschwingverzögerung ein. Aufnahmen erfassen KUROSAKIs FM-Modell und bestätigen weder Hardwareklangfarbe noch reales Schreibtiming.

Instrument 0 wird von allen Stimmen geteilt. channel_set schreibt Key/obere Frequenz vor Instrument/Dämpfung. Nach key_off muss die nächste Note auch obere Frequenz und Block wiederherstellen.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Vergleichen Sie Vorgabeinstrument 1 mit einem eigenen anhaltenden Benutzerinstrument 0, jeweils 60 Frames auf gleicher Tonhöhe. Die Folge endet mit Key-off und maximaler Dämpfung.

nes_vrc7_channel_set: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vrc7_sound.h:18

Deklarationshinweise im Original
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

c
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

Löscht das gesamte obere Frequenz-/Block-/Key-Register der gewählten Stimme.

Syntax

c
void nes_vrc7_key_off(u8 channel);

Parameter

channel

VRC7-Kanal 0..5; größere Werte bewirken nichts.

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Bedingungen und Grenzen

Für --mapper=vrc7 (Mapper 85). Schützen Sie Registerauswahl-/Datenpaare gegen dazwischenliegende Interruptschreibzugriffe. Die Hilfen fügen keine Einschwingverzögerung ein. Aufnahmen erfassen KUROSAKIs FM-Modell und bestätigen weder Hardwareklangfarbe noch reales Schreibtiming.

Instrument 0 wird von allen Stimmen geteilt. channel_set schreibt Key/obere Frequenz vor Instrument/Dämpfung. Nach key_off muss die nächste Note auch obere Frequenz und Block wiederherstellen.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Vergleichen Sie Vorgabeinstrument 1 mit einem eigenen anhaltenden Benutzerinstrument 0, jeweils 60 Frames auf gleicher Tonhöhe. Die Folge endet mit Key-off und maximaler Dämpfung.

nes_vrc7_key_off: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vrc7_sound.h:21

Deklarationshinweise im Original
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

c
void nes_vrc7_key_off(u8 channel)
{
    if (channel >= 6) return;
    nes_vrc7_write((u8)(0x20 + channel), 0x00);
}
nes_vrc7_set_user_patch

Schreibt acht Bytes der Reihe nach in die VRC7-Benutzerinstrumentregister.

Syntax

c
void nes_vrc7_set_user_patch(const u8* patch8);

Parameter

patch8

Acht Bytes zur Definition von Instrument 0. NULL wird nicht geprüft. Halten Sie die Quellbank während des Aufrufs eingeblendet.

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Bedingungen und Grenzen

Für --mapper=vrc7 (Mapper 85). Schützen Sie Registerauswahl-/Datenpaare gegen dazwischenliegende Interruptschreibzugriffe. Die Hilfen fügen keine Einschwingverzögerung ein. Aufnahmen erfassen KUROSAKIs FM-Modell und bestätigen weder Hardwareklangfarbe noch reales Schreibtiming.

Instrument 0 wird von allen Stimmen geteilt. channel_set schreibt Key/obere Frequenz vor Instrument/Dämpfung. Nach key_off muss die nächste Note auch obere Frequenz und Block wiederherstellen.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Vergleichen Sie Vorgabeinstrument 1 mit einem eigenen anhaltenden Benutzerinstrument 0, jeweils 60 Frames auf gleicher Tonhöhe. Die Folge endet mit Key-off und maximaler Dämpfung.

nes_vrc7_set_user_patch: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vrc7_sound.h:14

Deklarationshinweise im Original
Copy eight caller-supplied patch bytes into user-instrument registers 0..7.

kitaqfc/lib/vrc7_sound.c:16

c
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

Schaltet alle sechs Stimmen per Key-off aus und wählt Instrument 0 mit maximaler Dämpfung.

Syntax

c
void nes_vrc7_silence_all(void);

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Bedingungen und Grenzen

Für --mapper=vrc7 (Mapper 85). Schützen Sie Registerauswahl-/Datenpaare gegen dazwischenliegende Interruptschreibzugriffe. Die Hilfen fügen keine Einschwingverzögerung ein. Aufnahmen erfassen KUROSAKIs FM-Modell und bestätigen weder Hardwareklangfarbe noch reales Schreibtiming.

Instrument 0 wird von allen Stimmen geteilt. channel_set schreibt Key/obere Frequenz vor Instrument/Dämpfung. Nach key_off muss die nächste Note auch obere Frequenz und Block wiederherstellen.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Vergleichen Sie Vorgabeinstrument 1 mit einem eigenen anhaltenden Benutzerinstrument 0, jeweils 60 Frames auf gleicher Tonhöhe. Die Folge endet mit Key-off und maximaler Dämpfung.

nes_vrc7_silence_all: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vrc7_sound.h:23

Deklarationshinweise im Original
Key off all six voices and set instrument zero with maximum attenuation.

kitaqfc/lib/vrc7_sound.c:54

c
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

Schreibt die Registernummer in den VRC7-Auswahlport, dann den Wert in den Datenport.

Syntax

c
void nes_vrc7_write(u8 reg, u8 value);

Parameter

reg

VRC7-Registernummer. Für Kanal 0: 0x10 untere Frequenzbits, 0x20 obere Bits/Block/Key, 0x30 Instrument/Dämpfung.

value

In das gewählte VRC7-Register zu schreibendes Byte.

Rückgabewert

Kein Rückgabewert. Ändert Audioregister oder Treiberzustand.

Bedingungen und Grenzen

Für --mapper=vrc7 (Mapper 85). Schützen Sie Registerauswahl-/Datenpaare gegen dazwischenliegende Interruptschreibzugriffe. Die Hilfen fügen keine Einschwingverzögerung ein. Aufnahmen erfassen KUROSAKIs FM-Modell und bestätigen weder Hardwareklangfarbe noch reales Schreibtiming.

Instrument 0 wird von allen Stimmen geteilt. channel_set schreibt Key/obere Frequenz vor Instrument/Dämpfung. Nach key_off muss die nächste Note auch obere Frequenz und Block wiederherstellen.

Anwendungsbeispiel

c
// 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();
}

Erwartetes Ergebnis

Vergleichen Sie Vorgabeinstrument 1 mit einem eigenen anhaltenden Benutzerinstrument 0, jeweils 60 Frames auf gleicher Tonhöhe. Die Folge endet mit Key-off und maximaler Dämpfung.

nes_vrc7_write: NTSC
NTSC
NTSC — Aufgenommenes Audio

Vollständiges Beispielprogramm

Build-Befehl

powershell
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-disasm
Implementierung und Quelltext

kitaqfc/lib/vrc7_sound.h:12

Deklarationshinweise im Original
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

c
void nes_vrc7_write(u8 reg, u8 value)
{
    VRC7_ADDR = reg;
    VRC7_DATA = value;
}

Strukturen, Konstanten und vollständige Header

Diese Header enthalten auch Makros ohne Funktionsform, Strukturen, Arraygrenzen, Aufzählungen und Aliase. Sie geben die erfassten Quellen einschließlich der ursprünglichen Kommentare unverändert wieder.

actor.h — Arrays für Spielakteure
c
/*
 * 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 — Ressourcen-IDs und Datenbeschreibungen
c
#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);

#endif

kitaqfc/lib/asset.h

attribute.h — Nametable-Attribute
c
/*
 * 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 — Musik, Soundeffekte und Audiosteuerung
c
#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);

#endif

kitaqfc/lib/audio.h

audio_vblank.h — Musikwiedergabe im VBlank-Interrupt
c
#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);
#endif

kitaqfc/lib/audio_vblank.h

bank.h — Bankabhängiger Zugriff auf Code und Daten
c
#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)

#endif

kitaqfc/lib/bank.h

chain.h — Ringpuffer für Positionsverläufe
c
#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);

#endif

kitaqfc/lib/chain.h

collision.h — Kollisionstests für Rechtecke und andere Formen
c
/*
 * 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 — Grundlegende Ganzzahltypen
c
#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

#endif

kitaqfc/lib/core.h

danmaku.h — Geschosspools, Fächermuster, Treffer und Streiferkennung
c
// 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);
#endif

kitaqfc/lib/danmaku.h

debug.h — RAM-Protokolle und Zusicherungen
c
#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)

#endif

kitaqfc/lib/debug.h

entity.h — Objektpools mit festen Arrays
c
#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);

#endif

kitaqfc/lib/entity.h

fc.h — Sammelheader der Bibliothek
c
#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"

#endif

kitaqfc/lib/fc.h

fds.h — FDS-Diskettenoperationen
c
#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);

#endif

kitaqfc/lib/fds.h

fds_file.h — Laden von FDS-Dateien
c
#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);

#endif

kitaqfc/lib/fds_file.h

fds_overlay.h — FDS-Overlaycode
c
#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);

#endif

kitaqfc/lib/fds_overlay.h

fds_save.h — Deklarationen zum Speichern auf FDS
c
#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"

#endif

kitaqfc/lib/fds_save.h

fds_sound.h — FDS-Wavetable-Audio
c
#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);

#endif

kitaqfc/lib/fds_sound.h

fixed.h — Q8.8-Festkommaarithmetik und Rechtecke
c
#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);

#endif

kitaqfc/lib/fixed.h

input.h — Tastenzustand, Drücken, Loslassen und Wiederholung
c
#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

#endif

kitaqfc/lib/input.h

input_repeat.h — Wiederholung bei gehaltener Taste
c
/*
 * 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 — Compiler-Intrinsics
c
#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);

#endif

kitaqfc/lib/intrinsics.h

keyboard.h — Tastaturabfrage
c
#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);
#endif

kitaqfc/lib/keyboard.h

mapper.h — Mapper-Banken und Interrupts
c
#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);

#endif

kitaqfc/lib/mapper.h

math_fast.h — Schnelle Ganzzahlarithmetik
c
#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);

#endif

kitaqfc/lib/math_fast.h

math_fixed.h — Intrinsics für Festkommaarithmetik
c
#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);

#endif

kitaqfc/lib/math_fixed.h

math_lut.h — Nachschlagetabellen
c
#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];

#endif

kitaqfc/lib/math_lut.h

metasprite.h — Bilder aus mehreren Sprites
c
/*
 * 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 — Mikrofoneingabe
c
#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);
#endif

kitaqfc/lib/mic.h

midi.h — MIDI-Ein- und -Ausgabe
c
#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);
#endif

kitaqfc/lib/midi.h

nametable_asset.h — Nametable-Ressourcen und ihre Platzierung
c
/*
 * 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 — Operationsmakros für Spiele
c
#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))

#endif

kitaqfc/lib/nes_game.h

oam.h — Operationen auf der OAM-Arbeitskopie
c
#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);

#endif

kitaqfc/lib/oam.h

oam_fair.h — Wechselnder Spritevorrang mit Prioritäten
c
#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);
#endif

kitaqfc/lib/oam_fair.h

oam_fair_impl.h — Implementierung des wechselnden Spritevorrangs
c
#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 — NES-Controllereingaben
c
/*
 * 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 — NES-Paletten
c
/*
 * 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 — 2D-Bewegung und Kollisionen
c
#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 — Physik für achsenparallele 3D-Quader
c
#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 — Deklarationen zur PPU-Anzeige
c
#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);

#endif

kitaqfc/lib/ppu.h

ppu_direct.h — Direkte PPU-Operationen
c
#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);

#endif

kitaqfc/lib/ppu_direct.h

rob.h — ROB-Steuerung
c
#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);
#endif

kitaqfc/lib/rob.h

runtime.h — C-Hilfsfunktionen für NMI, OAM und PPU-Übertragungen
c
/*
 * 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 — Szenenregistrierung, -wechsel und -aktualisierung
c
#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);

#endif

kitaqfc/lib/scene.h

scroll.h — Hintergrund, Fenster und geteiltes Scrollen
c
/*
 * 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 — OBJ-Reservierung, Positionierung, Metasprites und Animation
c
#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);

#endif

kitaqfc/lib/sprite.h

system.h — Start, Bildzähler, Wartefunktionen und Interrupts
c
#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

#endif

kitaqfc/lib/system.h

tilemap.h — Rechteckige Operationen auf Kachelkarten
c
/*
 * 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 — VRAM-Aktualisierungen und Übertragung per Warteschlange
c
#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);

#endif

kitaqfc/lib/vram.h

vram_queue.h — Durch NMI verarbeitete VRAM-Warteschlangen
c
#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);

#endif

kitaqfc/lib/vram_queue.h

vrc6_sound.h — VRC6-Audioerweiterung
c
#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);

#endif

kitaqfc/lib/vrc6_sound.h

vrc7_sound.h — VRC7-FM-Audio
c
#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);

#endif

kitaqfc/lib/vrc7_sound.h

wire3d.h — Drahtgitterdarstellung für DMG
c
// 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);
#endif

kitaqfc/lib/wire3d.h

wire3d_tables.h —
c
// 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,
};
#endif

kitaqfc/lib/wire3d_tables.h

zapper.h — Eingabeschnittstelle für die Lichtpistole
c
#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);
#endif

kitaqfc/lib/zapper.h

zx0.h —
c
#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