kind: reference

PixelRAM

Alle Befehle von PixelRAM zum Nachschlagen: den Bildschirm öffnen, Pixel setzen und lesen, Paletten, Farben ohne Palette, der Speicher hinter dem Bild, Tastatur, Maus und Zeit. PixelRAM hat mit Absicht keine Befehle für Linien, Kreise oder Figuren: Alles, was du siehst, besteht aus einzelnen Pixeln, die dein Programm setzt.

1. Grundlagen

Übersetzen

In einem Ordner mit der PixelRAM-Vorlage übersetzt make die Datei main.c in die Webseite main.html, die du mit »Go Live« in der Vorschau öffnest. Beim ersten Mal lädt make die Bibliothek PixelRAM in den versteckten Ordner .pixelram.

make                   # main.c → main.html
make PROGRAM=spiel     # spiel.c → spiel.html
make PROGRAM=beispiele/feuer
  • Findet make einen Fehler, nennt es Datei und Zeile, und die alte Webseite bleibt, wie sie war. Lies die erste Fehlermeldung zuerst.
  • Was dein Programm mit printf ausgibt, steht in der Konsole der Seite: Fahre mit der Maus über das Bild und klicke unten rechts auf das Terminal-Symbol oder drücke `.
  • Dort sind auch der CRT-Filter (F6), der Scanlines wie auf einem alten Röhrenbildschirm zeigt, und das Vollbild (F11).

Bildschirm und Schleife

#include "pixelram.h"

int main(void)
{
    if (!screen_open(320, 180, pixel_indexed8, "Mein Programm"))
        return 1;

    while (!should_close())
    {
        clear(0);
        // … Pixel setzen …
        present();          // das fertige Bild zeigen
    }

    screen_close();
    return 0;
}
Befehl Bedeutung
screen_open(breite, hoehe, modus, titel) Öffnet den Bildschirm mit so vielen Pixeln; false, wenn es nicht klappt
screen_width(), screen_height() Breite und Höhe in Pixeln
should_close() Wahr, wenn das Programm enden soll
present() Zeigt das fertige Bild und wartet auf das nächste; einmal pro Durchlauf der Schleife
set_target_fps(n) Höchstens n Bilder pro Sekunde, ohne Angabe 60; 0 schaltet die Grenze ab
set_title(titel) Ändert den Titel
set_pixel_aspect(f) Pixel breiter (größer als 1) oder höher (kleiner als 1) als quadratisch
set_fullscreen(true) Vollbild, im Browser nach dem nächsten Klick
screen_close() Schließt den Bildschirm am Ende

Ein Programm ohne Schleife, das nur ein Bild malt, braucht im Browser kein present(): Die Seite zeigt das Bild dann von selbst.

2. Pixel und Farben

Pixel setzen und lesen

Der Pixel (0, 0) ist oben links, x wächst nach rechts, y nach unten. Im Modus pixel_indexed8 ist die Farbe eines Pixels eine Zahl von 0 bis 255, eine Nummer in der Palette.

Befehl Bedeutung
set_pixel(x, y, farbe) Setzt einen Pixel; außerhalb des Bildes passiert nichts
get_pixel(x, y) Die Farbe eines Pixels; außerhalb des Bildes 0
clear(farbe) Füllt das ganze Bild mit einer Farbe

Weil man Pixel auch lesen kann, ist das Bild selbst ein Speicher: Ein Spiel kann nachsehen, ob an einer Stelle schon etwas steht, und ein Feuer kann seine Farbe aus den Pixeln darunter ausrechnen.

for (int y = 0; y < screen_height(); y++)
    for (int x = 0; x < screen_width(); x++)
        set_pixel(x, y, (x ^ y) % 16);

Paletten

Die Palette sagt, welche Farbe zu jeder Nummer gehört. Ändert man eine Farbe der Palette, ändern sich sofort alle Pixel mit dieser Nummer, ohne dass ein einziger Pixel neu gesetzt wird.

Befehl Bedeutung
use_palette("pico_8") Wählt eine fertige Palette; ohne Angabe gilt vga
set_palette(nummer, r, g, b) Gibt einer Nummer eine Farbe, Rot, Grün und Blau von 0 bis 255
get_palette(nummer, &r, &g, &b) Liest eine Farbe der Palette
palette_count(), palette_name(i) Wie viele fertige Paletten es gibt und wie sie heißen

PixelRAM kennt dieselben 88 Paletten wie Pixelflow Canvas, zum Beispiel vga, pico_8, sweetie_16, endesga_32, zughy_32 und aap_64. Alle stehen in der Dokumentation von PixelRAM.

Ein Farbverlauf in der Palette macht aus Nummern Helligkeiten, etwa für Feuer: Nummer 0 ist Schwarz, 63 ist Weiß, dazwischen Rot und Gelb.

for (int i = 0; i < 16; i++) {
    set_palette(i,      i * 8,       0,           0);
    set_palette(i + 16, i * 8 + 128, i * 8,       0);
    set_palette(i + 32, 255,         i * 8 + 128, i * 8);
    set_palette(i + 48, 255,         255,         i * 8 + 128);
}

Farben ohne Palette

In den anderen Modi steht in jedem Pixel gleich die Farbe:

Modus Bytes pro Pixel Bedeutung
pixel_indexed8 1 Nummer in der Palette
pixel_rgb565 2 Farbe mit 5 Bit Rot, 6 Bit Grün, 5 Bit Blau
pixel_rgb24 3 Rot, Grün und Blau mit je 8 Bit
pixel_rgba32 4 Dazu 8 Bit Deckkraft
Befehl Bedeutung
set_pixel_rgb(x, y, r, g, b) Setzt einen Pixel in einer Farbe
get_pixel_rgb(x, y, &r, &g, &b) Liest die Farbe; geht in jedem Modus, auch mit Palette
clear_rgb(r, g, b) Füllt das ganze Bild
screen_set_mode(breite, hoehe, modus) Wechselt Größe und Modus, während das Programm läuft

Der Speicher hinter dem Bild

set_pixel schreibt in einen Speicher, den die Grafik am Ende zeigt. Mit framebuffer() kommt man direkt an ihn heran, so wie Spiele aus den Neunzigerjahren:

uint8_t *pixel = framebuffer();
pixel[y * screen_pitch() + x] = 12;   // dasselbe wie set_pixel(x, y, 12)

screen_pitch() ist die Länge einer Zeile in Bytes, framebuffer_size() die Größe des ganzen Speichers. Im Modus pixel_indexed8 ist jedes Byte ein Pixel. Direkt in den Speicher zu schreiben ist schneller, aber nichts passt mehr auf: Wer über den Rand schreibt, zerstört andere Daten.

3. Eingabe und Zeit

Tastatur

Befehl Wahr, …
key_down(pixel_key_w) solange die Taste gedrückt ist; für Bewegung
key_pressed(pixel_key_space) nur in dem Bild, in dem sie heruntergedrückt wurde
key_released(pixel_key_e) nur in dem Bild, in dem sie losgelassen wurde
poll_key_event(&ereignis) wenn noch ein Tastendruck in der Warteschlange steht; ereignis.key und ereignis.pressed sagen welcher

Die Tasten heißen pixel_key_a bis pixel_key_z, pixel_key_0 bis pixel_key_9, pixel_key_up, pixel_key_down, pixel_key_left, pixel_key_right, pixel_key_space, pixel_key_enter, pixel_key_escape, pixel_key_shift, pixel_key_ctrl und pixel_key_f1 bis pixel_key_f12. Buchstaben und Ziffern haben die Nummer ihres Zeichens: pixel_key_a ist 'a'.

Im Browser bekommt das Programm die Tasten erst, wenn du einmal ins Bild geklickt hast.

Maus

Befehl Bedeutung
mouse_position(&x, &y) Wo die Maus steht, in Pixeln des Bildes
mouse_delta(&dx, &dy) Wie weit sie sich seit dem letzten Bild bewegt hat
mouse_button_down(pixel_mouse_left) Wahr, solange die Taste gedrückt ist; auch pixel_mouse_right, pixel_mouse_middle
mouse_button_pressed(…), mouse_button_released(…) Wahr im Bild des Klicks oder des Loslassens
set_mouse_relative(true) Fängt die Maus: Der Zeiger verschwindet, mouse_delta zählt jede Bewegung; im Browser nach dem nächsten Klick

Zeit

Befehl Bedeutung
seconds() Sekunden seit dem Start, mit Nachkommastellen
ticks_ms() Millisekunden seit dem Start, als ganze Zahl
sleep_ms(ms) Wartet so viele Millisekunden

Damit eine Bewegung auf jedem Computer gleich schnell ist, rechnet man mit der Zeit seit dem letzten Bild:

double vorher = seconds();
while (!should_close())
{
    double jetzt = seconds();
    double dt = jetzt - vorher;
    vorher = jetzt;
    x += 40 * dt;          // 40 Pixel pro Sekunde
    // …
    present();
}