Freitag, 2. Juni 2017

DIY: Emulator Teil 2.1_2: Der Rest (Graphikaufbau)

Hier haben wir eine neue JavaScript-Datei mit einer neuen Klasse erstellt. Die initialize-Funktion von dort benötigt noch einige Dinge, welche nun abgehandelt werden.

Wir befinden uns immer noch in der Klasse EmuGraphicsAdapter. Zuerst kommt die Funktion, mit welcher man die Buffer wechselt:

EmuGraphicsAdapter.js:



var EmuGraphicsAdapter = function(newwidth, newheight, bgcolor, bordercolor)
{
    // Variablen... (siehe Teil 2.1_1)
    // initialize-Funktion... (siehe Teil 2.1_1)

    this.switchBuffers = function()
    {
        var oldBuf = doubleBufferIndex;
        doubleBufferIndex = Math.abs(doubleBufferIndex - 1);
        EmuGraphicsAdapter.containers[doubleBufferIndex].visible = false;
        EmuGraphicsAdapter.containers[oldBuf].visible = true;
    }



Die Funktion switchBuffers() wird (soll) aufgerufen (werden), nachdem das Bild fertig aufgebaut ist, um dieses anzuzeigen.

Der doubleBufferIndex wechselt immer zwischen 0 und 1, da der absolute Wert (ohne minus davor)  des Buffers-minus-Eins genommen wird: abs(0 - 1) = 1, abs(1 - 1) = 0...

Dann wird der neue Buffer unsichtbar gemacht und der alte Buffer angezeigt, denn auf diesem haben wir zuletzt etwas gezeichnet.

Nun kommt die Funktion, welche den Emulator-Bildschirm im Browser-Bildschirm zentriert:


    this.reposition = function()
    {
        var realScreenWidth = RUNPIXI.getScreenSize().w;
        var realScreenHeight = RUNPIXI.getScreenSize().h;

        for(var i = 0; i < EmuGraphicsAdapter.containers.length; i++)
        {
            var container = EmuGraphicsAdapter.containers[i];
            container.x = realScreenWidth * 0.5 - container.width * 0.5;
            container.y = realScreenHeight *0.5 - container.height * 0.5;
        }
    }


Die neue Container-Position befindet sich in der Mitte des Bildschirms minus der Hälfte der Grösse des Containers.

Nun werden wir das erste Mal die Pixel mit Farbe "beschreiben". Dazu gibt es erstmal die fill- und clear-Funktionen:


    var fillBuffer = function(color, bufferIndex)
    {
        if(screenArray[bufferIndex].length <= 0)
            return;

        for(z = 0; z < screenArray[bufferIndex].length; z++)
        {
            screenArray[bufferIndex][z].tint = color;
        }
    }

    this.fill = function(color) { fillBuffer(color, doubleBufferIndex); }
    this.clear = function() { this.fill(emuBackgroundColor); }


Wie du siehst, rufen die zwei Funktionen this.fill und this.clear am Ende jeweils fillBuffer auf. Dort wird der tint-Wert des gesamten screenArrays mit der gegebenen Farbe belegt. Das screenArray referenziert auf die Pixel-Objekte im Buffer-Container. Hier brauchen wir weder x noch y (darum z), da sowieso alle Pixel betroffen sind.

Nun wird am Ende der "Funktion"/"Klasse" noch die initialize-Funktion aufgerufen, so dass wir sie nicht selbst aufrufen müssen wenn wir eine neue Instanz erstellen. Die Klasse ist hiermit beendet.


    this.initialize(newwidth, newheight, bgcolor, bordercolor);

}


Die abschliessende Klammer nicht vergessen. ;)

Jetzt fehlen nur noch ein paar globale Variablen und Funktionen (und die öffentlichen DrawPixel-Funktionen, aber das kannst du dir erstmal ja selbst ausrechnen, siehe fill. ;) ):


EmuGraphicsAdapter.containers = [];
EmuGraphicsAdapter.originalPixelTex = null;
EmuGraphicsAdapter.createOriginalPixelTex = function()
{
    if(EmuGraphicsAdapter.originalPixelTex != null)
    {
        console.log("EmuGraphicsAdapter: Pixel texture already created.");
        return;
    }

    var gpix = new PIXI.Graphics();
    gpix.beginFill(0xFFFFFF, 1.0);
        gpix.drawRect(0,0,2,2);
    gpix.endFill();

    EmuGraphicsAdapter.originalPixelTex = gpix.generateCanvasTexture();
    console.log("EmuGraphicsAdapter: Created original pixel texture.");
}


Diese Variablen sind statisch und öffentlich, kommen also ohne eine Instanz des EmuGraphicsAdapters aus. In der createOriginalPixelTex-Funktion wird so wie in der initialize-Funktion einfach eine "Graphik" erstellt und dann eine Textur davon "gezogen". Diese Graphik ist ein 2x2 Pixel grosses weisses Quadrat. Die Textur ist eigentlich 3x3 Pixel gross. Wenn wir von 0,0 bis 1,1 gehen, wird ein Pixel nicht richtig dargestellt. Du kannst dies gerne probieren, vielleicht braucht es dies ja für gewisse Zwecke. Es sieht auf jeden Fall interessant aus. Siehe Bild 2.


Bild 1: 0,0 bis 2,2: "Pixel Perfekt"

Bild 2: 0,0 bis 1,1: Fragmentiert


Nun müssen wir das Ganze nur noch in der index.html zusammensetzen:

index.html:

Ich schreibe gleich nochmal die ganze Datei ab. Auch hier wird erst mal nur getestet. Nach diesem Code solltest du die oben angezeigte Ausgabe sehen.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>EmulatroniX</title>
<link rel="stylesheet" type="text/css" href="css/base.css">
</head>
<body>
<div id="wrapper">
<div id="pixiscreen"></div>
</div>
<script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
<script src="https://pixijs.download/v4.5.2/pixi.min.js"></script>
<script src="http://cdn.rawgit.com/ben0bi/RUNPIXI.js/v0.6.4/RUNPIXI/RUNPIXI.js"></script>
<!-- NEW for part 2.1 -->
<script src="js/EmuGraphicsAdapter.js"></script>
<script>
function mainLoop() { // hier kommt dann switchBuffers rein. }
$(document).ready(function() 
{
var browserBackgroundColor = 0x111133;
RUNPIXI.initialize('pixiscreen', mainLoop, browserBackgroundColor);
// NEW for part 2.1
RUNPIXI.PIXELATED(); // use this for pixel perfect rendering.
var emuWidth = 80;
var emuHeight = 40;

var emuGraphics = new EmuGraphicsAdapter(emuWidth, emuHeight,0x000000,0x3333AA);

emuGraphics.fill(0xFF0000);
emuGraphics.switchBuffers();
console.log("Ready.");
});
</script>
</body>
</html>


Zuerst wird natürlich das neue Script geladen.

RUNPIXI.PIXELATED() setzt den internen standard Filter für Texturen von Pixi um. Ansonsten wären auch die "Pixel Perfekt"-Pixel oben verschwommen.

Wir müssen nur eine neue Instanz erstellen, wenn wir einen anderen Emulator starten. Das ist sehr bequem und geht mit einer Zeile. Anstatt eine neue zweite Instanz zu erstellen, kannst du dazu auch einfach wieder initialize aufrufen. Das ist ganz dir überlassen.

Die Zahl/Farbe 0x3333AA wird später durch browserBackgroundColor ersetzt. Somit sieht man dann nur noch ein Rechteck (gefüllt) ohne Rand.

Schliesslich wird noch der Buffer mit Grün gefüllt und dann angezeigt. Das Endergebnis siehst du oben.

Hier findest du das Release zu diesem Teil:
https://github.com/ben0bi/EmulatroniX/releases/tag/Blog_Series_Part_2.1-1

Weiter gehts mit Teil 2.1_3: Endlich mal was zeichnen. Jedenfalls die Funktionen dazu. ;)

[EDIT] Es gibt noch eine Anpassung, welche es nicht in das hiesige Release geschafft hat. Damit wird der Emulator-Bildschirm auf die Grösse des Pixi-Bildschirms skaliert (ohne Verzerrungen).

Ich hoffe das Hilft. Viel Spass beim Basteln.

Keine Kommentare:

Kommentar veröffentlichen