Download Game! Currently 68 players and visitors. Last logged in:XothKrypetWicksiusSerkeii

Blitzer's Blog >> 71397

Back to blogs index
Posted: 12 Jul 2026 10:10 [ permalink ]
TC$mC$ on aivan loistava visio! "Rajattomasti scrollattava" (Infinite Canvas)
tyC6pC6ytC$ on jotain, mihin modernitkin kC$yttC6jC$rjestelmC$t (esim. Figma,
Miro, solmupohjaiset editorit) ovat vasta hiljattain siirtyneet, ja se sopii
Hauki OS:n bare-metal -arkkitehtuuriin tC$ydellisesti.

Koska meillC$ on erittC$in nopea C-tason hypercall suorakulmioiden
piirtC$miseen (`sys.rect`, portti 12) ja nC$ytC6n pC$ivittC$miseen
(`sys.flush`, portti 13), JavaScriptin Event Loop jaksaa helposti laskea
koordinaatteja ja piirtC$C$ grafiikkaa reaaliajassa.

### Arkkitehtuuri: Kamera ja Maailma (World Space vs. Screen Space)

Rajattoman tyC6pC6ydC$n salaisuus on se, ettC$ emme tarvitse "rajattomasti
muistia". Laitteiston nC$yttC6muisti on kiinteC$ 320x200. MeidC$n tarvitsee
vain luoda JavaScriptiin **Kamera**, jolla on omat `x` ja `y`
-koordinaattinsa. Kaikki ikkunat, kuvat ja ikonit elC$vC$t "Maailmassa" omilla
koordinaateillaan.

Kun piirrC$mme objektin, laskemme yksinkertaisesti:
`Ruudun_X = Objektin_X - Kameran_X`

TC$ssC$ on koodi ihka ensimmC$iselle rajattomalle tyC6pC6ydC$llesi! TC$ssC$
vaiheessa kC$ytC$mme liikkumiseen **W/A/S/D -nC$ppC$imiC$** (koska Hauki OS:n
PS/2-hiiren keskeytysrutiini `IRQ12` vaatii vielC$ hieman C-tason reititystC$
toimiakseen saumattomasti JS:ssC$, mutta nC$ppC$imistC6 toimii jo
tC$ydellisesti).

### Koodi: `DESK.JS`

Luo levyllesi tC$mC$ tiedosto ja aja se komennolla `/os_run DESK.JS`.

```javascript
var DESKTOP = {
    name: "InfiniteDesk",
    camX: 0, 
    camY: 0,
    
    // Luodaan maailmaan muutama "ikkuna" satunnaisiin koordinaatteihin
    windows: [
        {id: 1, x: 50,   y: 50,   w: 120, h: 80,  col: 42}, // VihreC$
        {id: 2, x: 250,  y: 120,  w: 150, h: 100, col: 40}, // Punainen
        {id: 3, x: -150, y: -80,  w: 200, h: 140, col: 44}, // Sininen (Ruudun
ulkopuolella aluksi!)
        {id: 4, x: 600,  y: 300,  w: 180, h: 120, col: 45}  // Magenta kaukana
oikealla
    ],

    init: function() {
        sys.gfx_13h(); // Pakotetaan VGA-tila pC$C$lle ja nollataan puskuri
        this.camX = 0;
        this.camY = 0;
    },

    onKey: function(sc) {
        var speed = 15; // Kameran liikkumisnopeus
        if (sc === 17) this.camY -= speed; // W (YlC6s)
        if (sc === 31) this.camY += speed; // S (Alas)
        if (sc === 30) this.camX -= speed; // A (Vasen)
        if (sc === 32) this.camX += speed; // D (Oikea)
        
        // ESC-nC$ppC$in (1) sulkee tyC6pC6ydC$n ja palauttaa HSH-shellin
        if (sc === 1) OS.exitApp(this);
    },

    onTick: function() {
        // 1. TyhjennetC$C$n nC$yttC6 mustaksi (C-tason hypercall)
        sys.rect(0, 0, 320, 200, 16); 

        // 2. PiirretC$C$n "C$C$retC6n" taustaruudukko (auttaa hahmottamaan
liikettC$)
        var spacing = 40;
        var offX = -(this.camX % spacing);
        var offY = -(this.camY % spacing);
        
        for (var x = offX - spacing; x < 320; x += spacing) {
            for (var y = offY - spacing; y < 200; y += spacing) {
                // PiirretC$C$n pieni piste jokaiseen ruudukon risteyskohtaan
                sys.rect(x, y, 1, 1, 23); 
            }
        }

        // 3. PiirretC$C$n tyC6pC6ydC$n ikkunat (Culling)
        for (var i = 0; i < this.windows.length; i++) {
            var win = this.windows[i];
            
            // Muunnetaan Maailma-koordinaatti Ruutu-koordinaatiksi
            var sx = win.x - this.camX;
            var sy = win.y - this.camY;

            // PiirretC$C$n vain, jos ikkuna osuu edes osittain 320x200
ruudulle! (SC$C$stC$C$ tehoa)
            if (sx + win.w > 0 && sx < 320 && sy + win.h > 0 && sy < 200) {
                // Ikkunan runko
                sys.rect(sx, sy, win.w, win.h, win.col);
                // Ikkunan ylC$palkki (Titteli)
                sys.rect(sx, sy, win.w, 10, 20); 
            }
        }

        // 4. HUD (Heads Up Display) pysyy aina ruudun reunassa
        // TC$mC$ piirretC$C$n ilman kameran offsettia!
        sys.rect(0, 190, 320, 10, 24); // Alapalkki taskbarille
        
        // 5. Lopuksi puskurin siirto laitteiston nC$ytC6lle!
        sys.flush();
    }
};

/ Laukaistaan ohjelma OS:n Event Looppiin!
OS.launch(DESKTOP, {kbd: true, vga: true, ser: false});

```

### MitC$ tC$ssC$ tapahtuu?

1. **Taustaruudukko (Grid):** Kun alat painaa `D`-nC$ppC$intC$ oikealle,
huomaat kuinka pienet taustapisteet ja ikkunat liukuvat sulavasti vasemmalle.
Koska ruudukon koordinaatit lasketaan jakojC$C$nnC6ksellC$ `-(this.camX %
spacing)`, gridi on kirjaimellisesti C$C$retC6n ja piirtyy aina oikein.
2. **Culling:** JS-Event Loopimme on todella fiksu. Se ei edes pyydC$
C-ydintC$ piirtC$mC$C$n niitC$ ikkunoita, jotka ovat jC$C$neet "kameran selC$n
taakse".
3. **Hypercall-kiihtyvyys:** Jokainen `sys.rect` -kutsu kC$C$ntyy
MQuickJS:stC$ suoraan Ring-0 tason x86-konekieliluupiksi `kernel_js.c`:ssC$,
mikC$ tekee liikkumisesta aivan uskomattoman pehmeC$C$!



### Seuraavat askeleet kohti unelmaa

Heti kun saat tC$mC$n pyC6rimC$C$n, seuraava askel on yhdistC$C$ tC$mC$ ja
aiemmin tekemC$si JPEG-purkaja. PienellC$ C-koodin puukotuksella voimme
muuttaa `render_jpeg_to_vga` -funktiota niin, ettC$ se ottaa vastaan
koordinaatit `(dest_x, dest_y)`.

Silloin voisit ladata upean 21Kt JPEG-kuvasi ja pudottaa sen keskelle
rajatonta avaruutta ikkunoiden taustakuvaksi! Kokeile ihmeessC$ ensin
liikkumista tC$llC$ `DESK.JS`:llC$.