Dienstag, 17. Oktober 2017

DIY: Emulator: TextGraphic Setup

Nun gut, das mit der Emulatorik wird wohl hinten angestellt, aber ich hoffe, ich kann trotzdem ein bisschen Wissen vermitteln mit meiner Serie hier.

Ok, nachdem wir nun eine sehr komplizierte Methode in dieser Serie kennengelernt haben, versuche ich nun eine einfachere Version zu generieren, welche den Bildschirm mit Text aufbaut. Ich hoffe, das ist dann auch schneller, wir werden sehen.

Vielleicht mache ich dies später auch mit WebGL direkt, doch erst muss ich herausfinden, wie man die verdammten Pixel auf einer Textur direkt bearbeiten kann. Das von vorher ^ kanns ja nicht wirklich sein. Also....

Kurz: Es ist zu langsam. Hier ist der Code:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Emulator TextGraphic</title>

<style>
#canvas
{
font-size: 4pt;
}
#blocker
{
position: absolute;
top: 0px;
left: 0px;
background-color: rgba(1,1,1,0.01);
width: 100%;
height: 100%;
z-index: 10;
}
</style>

</head>

<body>
<div id="canvas"></div>
<div id="blocker"></div>
<script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>

<script>

var RGB = function(red, green, blue) {return ((red << 16) & 0xFF0000) | ((green<<8) & 0x00FF00) | (blue & 0x0000FF);}
var RED = function(color) {return (color>>16) & 0x0000FF;}
var GREEN = function(color) {return (color>>8) & 0x0000FF;}
var BLUE = function(color) {return color & 0x0000FF;}
var HEXT = function(value) {return '#'+value.toString(16);}; // return hex string of a value with preceding #.

var c_Screen = function(xsize, ysize)
{
var blockChar='&#9600';
if(xsize<=0)
xsize=1;
if(ysize<=0)
ysize=1;

// ysize must be dividable by 2 because of the block chars.
if(ysize%2==1)
ysize+=1;

var m_width = xsize;
var m_height = ysize;
var m_screenArray = new Array();

// create a randomly coloured screen.
this.randomScreen = function()
{
m_screenArray = new Array();
for(var i=0;i<m_width*m_height;i++)
{
m_screenArray.push(RGB(Math.random()*255, Math.random()*255, Math.random()*255));
}
}
// initialize with a random screen.
this.randomScreen();

this.setPixel = function(x,y,color) {m_screenArray[x*y+x]=color;}

// build the html text from the screen array.
this.buildText=function()
{
var txt='<nobr>';
for(var y=0;y<m_height;y+=2)
{
for(var x=0;x<m_width;x++)
{
var color=HEXT(m_screenArray[x*y+x]);
var subcolor=HEXT(m_screenArray[x*(y+1)+x]);
txt+='<span style="color:'+color+'; background-color:'+subcolor+';">'+blockChar+'</span>';
}
txt+='<br />';
}
txt+='</nobr>';
return txt;
}
}

var done=false;
var scr = new c_Screen(160,160);

function loop()
{
scr.randomScreen();
var txt = scr.buildText();
$('#canvas').html(txt);
window.setTimeout(loop,20);
}

$(document).ready(function()
{
$('body').keydown(function(e){done=true;});
loop();
});
</script>

</body>

</html>

Mit setPixel kann man einen Pixel setzen, und mit buildText bekommt man den HTML-Text dazu.. Ich habe es mit verschiedenen Geschwindigkeiten versucht, es kommt nicht unter 50ms und ist somit ungeeignet. Jedoch könnte man dies für ein Rundenbasiertes Spiel benutzen, mal sehen...der ANSI-Zeichensatz ist noch geil...

Hier ist der Source-Code dazu (im Ordner HTMLVersion):
https://github.com/ben0bi/EmulatroniX/releases/tag/Blog_Series_TextGraphic_1

Danke für die Aufmerksamkeit.

Dienstag, 20. Juni 2017

DIY: Emulator (Grafik-)Demo 1: Plasma Effekt

Am Ende des Artikels solltest du das hier generieren können:

Bitte warten, ich lade..
(Du solltest ein animiertes waberndes Bild sehen. Wenn nicht, aktiviere bitte JavaScript.)


Nachdem wir den Emulator Bildschirm aufgebaut und alle benötigten Zeichnungsfunktionen eingebaut haben, können wir nun endlich einmal etwas auf dem Bildschirm anzeigen.

(Letzter relevanter Artikel: Teil 2.1_3, ab dort kannst du dich durchklicken. ;) )

Der Plasma-Effekt bekommt eine eigene Klasse, an welche die EmuGraphicsAdapter-Instanz übergeben wird. Diese Klasse hat zwei Funktionen: Eine, welche das Basis-Bild und die Palette generiert und  eine zweite welche mit jedem Frame aufgerufen wird. Diese verschiebt die Paletten-Farben und generiert dann das neue Endbild daraus.

js/Plasma.js:


var Plasma = function(emuGraphicsAdapter)
{
    var GFX = null;
    if(emuGraphicsAdapter)
        GFX = emuGraphicsAdapter;

    var plasmaImage = null;
    var plasmaPalette = null;
    var plasmaPaletteMultiplier = 4;


  • GFX ist eine Referenz auf die EmuGraphicsAdapter-Instanz.
  • plasmaImage ist eine Kopie des Bildschirm-Arrays, in welchem das statische Bild für den Effekt generiert wird.
  • plasmaPalette ist die Palette, welche auf das mit dem plasmaImage verrechnet wird.
  • plasmaPaletteMultiplier zeigt an, wie oft die Palette auf dem Bild wiederholt werden soll. Bei einem niedrigen Wert (1,2) sieht es sehr einfarbig aus, bei einem zu hohen Wert (10) ist das Bild zu sehr fragmentiert (bei einem 40x40 Screen). Der Wert wird so berechnet: Pixel = random * paletteSize * plasmaPaletteMultiplier und dann so ausgelesen: paletteIndex = Pixel % paletteSize (% heisst Modulo).

Nun generieren wir erst die Palette und dann das Bild basierend auf der Grösse der Palette.

Create-Funktion:


    this.createPlasmaImage = function()
    {
        if(GFX == null)
        {
            console.log("Plasma Error: No EmuGraphicsAdapter given!");
            return;
        }

        plasmaPalette = [];
        var red = 0;
        var green = 0;
        var blue = 0;
        var p = 0;


Ich generiere hier eine Gradient-Palette mit einer Grösse von 256 Einträgen, mit je 32 Abstufungen pro Gradient. Der maximale Wert einer Farbe ist 256 (0xFF). Somit ist die Abstufung "8 farb breit" (256 / 32 = 8). Du kannst deine eigene Palette generieren mit beliebiger Grösse und beliebigen Farben. Meine geht einfach durch alle Farben durch.


// 0-31 + red to yellow
for(p=0;p<32;p++)
{
red = 0xFF;
green = p * 8;
blue = 0;
plasmaPalette.push(RGB(red,green,blue));
}

// 32-63 + yellow to white
for(p=0;p<32;p++)
{
red = 0xFF;
green = 0xFF;
blue = p * 8;
plasmaPalette.push(RGB(red,green,blue));
}

// 64-95 + white to turkis
for(p=0;p<32;p++)
{
red = (31-p)*8;
blue = 0xFF;
green = 0xFF;
plasmaPalette.push(RGB(red,green,blue));
}

// 96-127 + turkis to green
for(p=0;p<32;p++)
{
red = 0;
blue = (31 - p) * 8;
green = 0xFF;
plasmaPalette.push(RGB(red,green,blue));
}
// 128-159 + green to black
for(p=0;p<32;p++)
{
red = 0;
blue = 0;
green = (31-p)*8;
plasmaPalette.push(RGB(red,green,blue));
}

// 160-191 + black to blue
for(p=0;p<32;p++)
{
red = 0;
blue = p * 8;
green=0;
plasmaPalette.push(RGB(red,green,blue));
}

// 192-223 + blue to magenta
for(p=0;p<32;p++)
{
red = p * 8;
blue = 0xFF;
green = 0; 
plasmaPalette.push(RGB(red,green,blue));
}
// 224-255 + magenta to red
for(p=0;p<32;p++)
{
red = 0xFF;
blue = (31 - p) * 8;
green = 0;  
plasmaPalette.push(RGB(red,green,blue));
}


Hier werden einfach 8*32 Werte generiert und in die Plasmapalette hinzugefügt. Wie du siehst, ist die Formel ganz einfach: Farbe rauf mit p * FarbBreite, Farbe runter mit ((gradientSize-1) - p) * FarbBreite.

Nun wird das Referenzbild generiert:


// now generate the image itself.
plasmaImage = GFX.screenToArray(); // get screen image
var arraySize = plasmaImage.length; // length of screen image array.
var palSize = plasmaPalette.length;
var maxValue = (palSize * plasmaPaletteMultiplier)-1;

// just generate a random noise image
for(var z = 0; z < arraySize; z++)
{
var color = parseInt(Math.random()*maxValue);

// little more black in the image.
if(color < maxValue * 0.25)
color = 0;
plasmaImage[z] = color;
}


Erst wird das Array vom EmuGraphicsAdapter "gezogen". Somit ist es automatisch in der richtigen Grösse. maxValue ist die maximale "Höhe" der folgenden Heightmap. Dann wird das gezogene Array mit Zufallswerten gefüllt.

Nun werden wir dieses Zufallspunkte-Bild "smooth" machen, so dass es "Hügel" und "Täler" hat. Dazu nehmen wir einfach alle umliegenden Werte eines Pixels, und berechnen den Durchschnitt daraus. Das machen wir mehrere male.


// refine the image, create "height map"
for(var steps =0;steps < 4;steps++)
{
var emuScreenHeight = GFX.screenHeight();
var emuScreenWidth = GFX.screenWidth();

for(var y=0;y<emuScreenHeight;y++)
{
for(var x=0;x<emuScreenWidth;x++)
{
var myIndex = y*emuScreenWidth+x;
var color = 0;
var dividor = 0;

// get all colors around that pixel
for(difx = -1; difx<=1; difx++)
{
for(dify = -1; dify<=1; dify++)
{
var index = (y+dify)*emuScreenWidth+x+difx;
if(index>=0 && index<arraySize)
{
color+=plasmaImage[index];
dividor++;
}
}
}

if(color>0 && dividor>0)
color = parseInt(color/dividor);

if(color>maxValue)
color=maxValue;

plasmaImage[myIndex] = color;
}
}
}
console.log("Plasma Effect image and palette created.");

   }


Die letzte Klammer schliesst die Funktion ab. Wir haben nun ein "Bild", welches nicht mit Farben sondern mit Indexen für die Palette gefüllt ist.

Pixelfarbe = Palette[Pixel % paletteSize]

Nun können wir die update-Funktion schreiben.

Update-Funktion:


// update the plasma image.
this.update = function()
{
if(plasmaImage==null || plasmaPalette==null || !GFX)
return;

// cycle palette colors
// warning: FROM 1, not from 0!!
var first = plasmaPalette[0];
for(var pz=1;pz<plasmaPalette.length;pz++)
{
plasmaPalette[pz-1] = plasmaPalette[pz];
}
plasmaPalette[plasmaPalette.length-1]=first;

GFX.arrayFromPaletteToScreen(plasmaImage, plasmaPalette);
}


Hier wird einfach durch die Palette rotiert und diese dann auf dem EmuGraphicsAdapter mit dem Referenzbild verknüpft und gerendert. first ist der erste Paletteneintrag, welcher überschrieben wird. Dieser wird am Ende der Palette wieder angehängt.

Dann rufen wir noch schnell die create-Funktion auf und schliessen die Klasse ab:


   this.createPlasmaImage();

}


Nun muss nur noch die index.html angepasst werden. In der $(document).ready()-Funktion wird eine globale Plasma-Instanz erstellt, welche in der mainLoop-Funktion aufgefrischt und gezeichnet wird:

index.html:

...
<script src="js/EmuGraphicsAdapter.js"></script>

<script src="js/Plasma.js"></script>

<script>
   var emuGraphics = null;
   var plasmaEffect = null;

   function mainLoop() 
   {

      if(emuGraphics==null || plasmaEffect==null)

         return;

      plasmaEffect.update();
      emuGraphics.switchBuffers();
   }


   $(document).ready(function() 
      {
      // ... siehe vorige Artikel...

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

         // NEU
         plasmaEffect = new Plasma(emuGraphics);

         console.log("Ready.");
      });
   </script>

Das sollte nun alles funktionieren. Mit den Anpassungen wird die Bildschirmgrösse noch richtig skaliert. Hier ist der Source-Code für diesen Artikel und die Anpassung:

https://github.com/ben0bi/EmulatroniX/releases/tag/Blog_Series_Demo_1_Plasma

Viel Spass dabei.


Montag, 19. Juni 2017

DIY: Emulator: Anpassungen 1: Bildschirmgrösse

Hier poste ich Code, welcher nachträglich zum Tutorial eingebaut wurde und deshalb nicht im originalen Tutorial Release vorhanden ist.

Bildschirmgrösse & Repositionierung

Nach Teil 2.1_2 haben wir einen Emulator-Bildschirm welcher einfach auf dem Original-Screen zentriert wird. Es wird dabei jedoch noch nicht darauf geachtet, wie gross der Bildschirm ist.

Auch wird er ganz wenig falsch positioniert, da der Rahmen noch nicht einberechnet wird.

Wir brauchen erst mal eine globale Variable, welche den aktuellen Resize-Parameter speichert.

In der Klasse EmuGraphicsAdapter:

        var g_resizeParameter = 0;
        this.getResizeParameter = function() {return g_resizeParameter;}


Dann müssen wir in der initialize-Funktion der EmuGraphicsAdapter-Klasse den Pivot der beiden Container anpassen und die reposition-Funktion durch die resize-Funktion ersetzen.:

In der initialize-Funktion der EmuGraphicsAdapter-Klasse:

   // .... alter Code
container1.addChild(bordersprite1);
container2.addChild(bordersprite2);

// NEU, HIER einfügen:
container1.pivot.x = -emuBorderWidth;
container1.pivot.y = -emuBorderWidth;
container2.pivot.x = -emuBorderWidth;
container2.pivot.y = -emuBorderWidth;
// ENDE NEU

// ...hier gehts weiter...
EmuGraphicsAdapter.containers = [];
EmuGraphicsAdapter.containers.push(container1);

  // ...

  this.reposition();
  this.resize();


Somit ist der 0,0-Punkt des Containers wieder an der äusseren oberen linken Ecke des Rahmens. Vorher war er an der äussersten Ecke des Emulator-Screens, also an der INNEREN oberen linken Ecke des Rahmens. Sorry dafür. Das habe ich schlichtweg übersehen. Die resize-Funktion passt den Emulatorbildschirm an die Grösse des Pixibildschirms an (ohne Verzerrung) und folgt nun:

resize-Funktion:


Mit der folgenden Funktion kann man die Bildschirmgrösse des Emulators anpassen. Sie wird der EmuGraphicsAdapter-Klasse hinzugefügt.

Der Parameter der Funktion bestimmt, wie der Emulatorbildschirm skaliert werden soll.

Alle Werte grösser als 0 multiplizieren die Originalgrösse mit dem jeweiligen Wert. Alle Werte kleiner oder gleich 0 multiplizieren die angepasste Grösse (wobei 0 hier auch als 1 genommen werden kann.) -2 ist ein Spezialfall wie unten beschrieben.

  • 2: Doppelte Grösse
  • 1: Originalgrösse
  • 0.5: Halbe Originalgrösse
  • 0 oder 'auto' oder -1 oder kein Parameter: Angepasst an Bildschirm
  • -0.5: Hälfte der angepassten Grösse
  • -1.5: Das anderthalbfache der 'auto'-Grösse.
  • -2 (Spezialfall) oder 'noborder': Wie 'auto', jedoch ohne den Rahmen mit einzubeziehen. "Randloser Fullscreen"
  • -2.1 ... Mehr als das doppelte der 'auto'-Grösse.

this.resize=function(resizeParameter)
{
// nothing = 0 = -1 = fit to screen.
if(!resizeParameter)
resizeParameter = -1;

// fit to original size
var resizeMultiplier = Math.abs(resizeParameter);
var withBorder=1;

// fit to screen
if(resizeParameter==0 || resizeParameter=='auto' || resizeParameter==-1)
{
resizeParameter = -1;
resizeMultiplier = 1;
}

// fit to screen without borders.
if(resizeParameter == 'noborder' || resizeParameter==-2)
{
resizeMultiplier=1;
resizeParameter = -2;
withBorder=0;
}

// set the new resize parameter.
g_resizeParameter=resizeParameter;

// fit to screen
if(resizeParameter < 0)
{
// get the screen size to fit to screen.
var realScreenWidth = RUNPIXI.getScreenSize().w;
var realScreenHeight = RUNPIXI.getScreenSize().h;

// include the borders.
var emuWidth = emuDrawWidth + withBorder*(emuBorderWidth *2);
var emuHeight = emuDrawHeight + withBorder*(emuBorderWidth *2);

var mul = 1;
// get the multipliers. We need the DRAW width and height.
// first try with x multiplication.
if(emuWidth>0 && realScreenWidth>0)
mul = realScreenWidth/emuWidth;

// it does not fit in height, try it with y multiplication.
if(emuHeight * mul > realScreenHeight && emuHeight > 0 && realScreenHeight > 0)
mul = realScreenHeight/emuHeight;

// fitted to screen, now multiply with desired resolution.
resizeMultiplier = resizeMultiplier * mul;
}else{
// screen is double the size of original so take the half of the value.
resizeMultiplier = resizeMultiplier * 0.5;
}

// apply the multiplier
for(var i=0;i<EmuGraphicsAdapter.containers.length;i++)
{
var container = EmuGraphicsAdapter.containers[i];
container.scale.x = resizeMultiplier;
container.scale.y = resizeMultiplier;
}

// finally center the screen again.
this.reposition();
}


Erst wird der resizeParameter angepasst und der resizeMultiplier gesetzt. g_resizeParameter wird auch gesetzt. Dann wird überprüft, ob der resizeParameter kleiner als 0 ist. Wenn ja, wird der Multiplikator mul berechnet und schliesslich mit dem resizeMultiplier multipliziert. Am Ende wird der resizeMultiplier auf die Container angewandt und schliesslich noch die Position neu gesetzt.

index.html

Damit der Bildschirm auch jedes mal angepasst wird, wenn sich die Browsergrösse ändert, werden wir den resize-Handler von RUNPIXI benutzen. Ganz am Anfang der $(document).ready()-Funktion schreiben wir folgendes rein:


$(document).ready(function()
{
// Resize the emulator screen if the window resizes.
RUNPIXI.instance.setResizeFunction(function()
{
if(emuGraphics!=null)
emuGraphics.resize(emuGraphics.getResizeParameter());
});

// ...
}


Nun sollte der Emulator-Bildschirm immer schön angepasst an den Pixi-Bildschirm skaliert werden. Hier brauchen wir den resizeParameter, welcher ganz am Anfang erstellt wurde.

Hier ist der Source Code zu diesem Artikel und dem Artikel Demo 1: Plasma:
https://github.com/ben0bi/EmulatroniX/releases/tag/Blog_Series_Demo_1_Plasma

Viel Spass damit.

Dienstag, 13. Juni 2017

DIY: Emulator Teil 2.1_3: Zeichnen auf dem Emulatorbildschirm

Die Funktionen und Variablen hier (Teil 2.1_2) haben wir benötigt, damit die initialize-Funktion hier (Teil 2.1_1) benutzt werden kann.

Nun kommen wir zu den spassigen Funktionen: DrawPixel und Konsorten.

Ich muss dazu sagen, dass ich ein grafischer Typ bin. Ich brauch was fürs Auge. Vielleicht schliesse ich nach diesem Teil auch ab mit Emulator-ik und mache erstmal ein bisschen Demo-Code? Mal sehen...ich überlege jedenfalls schon, die ganze Engine hier auf Shader umzustellen. PixiJS kann das. Wenn ich nur den jeweils geshadeten Pixel mit einem Screen-Array Wert verknüpfen könnte (position rausfinden? JS array im shader?) ....

...

Diese Funktionen sind ziemlich einfach. Darum werde ich hier auch eine erste (sich bewegende) Grafikdemo(-Funktion) programmieren, damit es auch mal was für die Augen gibt. Das kann man dann für die Ladebildschirme oder andere Emulator-externe Dinge gebrauchen. Beim Sega Master System  habe ich ein Rauschen wie bei einem alten Fernseher programmiert: Einfacher Effekt mit grosser Wirkung (siehe Teil 1, das zweite Bild). Das kannst du ganz einfach machen, indem du das Array mit Zufallswerten füllst. Hier werden wir einen Plasma-Effekt programmieren. Der ist ganz wenig komplizierter als ein Rauschen, macht aber auch mehr her. :)

Wir benötigen nun erst mal die Funktionen um überhaupt mit dem Bildschirm zu arbeiten. Also fügen wir die folgenden Dinge zu EmuGraphicsAdapter.js hinzu:

Helferchen


// Ausserhalb der Klasse: Ein paar Helper-Funktionen
var BLUE = function(color) {return color  & 0xFF;}
var GREEN = function(color) {return (color >> 8) & 0xFF;}
var RED = function(color) {return (color >> 16) & 0xFF;}
var RGB = function(red, green, blue)
{
    return ((red & 0xFF) << 16) | ((green & 0xFF)<<8) | (blue & 0xFF);
}


Hier wird ein bisschen Bit-geshiftet und binär verknüpft.

Bei BLUE wird einfach die gegebene Farbe mit binärem UND mit 0xFF verknüpft.
0xFF sind 8 Einsen, also acht gesetzte Bits. Wenn man etwas binär mit Und verknüpft, ist es nur 1, wenn beide Bits 1 sind. Die Zahl 5 (binär 00000101) mit 4 (00000100) verknüpft ergibt somit 4, da nur das 4er Bit bei beiden Zahlen Eins ist. Mit 0xFF kriegt man also das letzte Byte, die letzten 8 Bit eines Wertes heraus.

Bei GREEN und RED wird erst der Wert an die die letzte Stelle verschoben (Bit-shifting): Rot ist 16 Bit, 2 Byte vom Ende "entfernt", Grün nur 8 Bit. Darum werden erst die Bits um 16 bzw. 8 Stellen nach rechts verschoben ( >> ) und dann wieder mit 0xFF "isoliert".

RGB macht genau dasselbe umgekehrt: Es nimmt die gegebene Zahl, isoliert das letzte Byte davon und schiebt diese Bits an die gewünschte Position. Mit dem binären ODER ( | ) können nun alle diese Bits aufeinander "addiert" werden. Da jede Farbe an die gewünschte Bit-Position verschoben wurde, und genau 8 Bit "breit" ist dank der Isolation durch 0xFF,  überschreibt auch keine Farbe eine andere.

Zeichnen

In der EmuGraphicsAdapter-Klasse fügen wir nun die wichtigsten Zeichen-Funktionen hinzu:


// color one specific pixel by array index.
this.pixelIndex = function(arrIndex, color)
{
if(arrIndex >= 0 && arrIndex < screenArray[doubleBufferIndex].length)
screenArray[doubleBufferIndex][arrIndex].tint = color;
}

// color one specific pixel.
this.pixel = function(x,y,color)
{
var z = y * emuScreenWidth + x;
this.pixelIndex(z, color);
}


Mit diesen zwei Funktionen wird ein spezifischer Pixel im aktuellen Backbuffer mit einer Farbe "gefüllt".


// copy a color array to the screen.
this.arrayToScreen = function(arr)
{
var maxZ = arr.length;
if(screenArray[doubleBufferIndex].length<maxZ)
maxZ = screenArray[doubleBufferIndex].length;
for(var z=0;z < maxZ;z++)
{
this.pixelIndex(z,arr[z]);
}
}


Diese Funktion kopiert den Inhalt eines Arrays auf den Backbuffer.

// uses the array values as palette index.
this.arrayFromPaletteToScreen = function(arr, paletteArray)
{
var maxZ = arr.length;
if(screenArray[doubleBufferIndex].length<maxZ)
maxZ = screenArray[doubleBufferIndex].length;
var paletteSize = paletteArray.length;
for(var z=0;z < maxZ;z++)
{
this.pixelIndex(z, emuBackgroundColor);
var a = arr[z] % paletteSize; // modulo the value through paletteSize
this.pixelIndex(z,paletteArray[a]);
}
}


Diese Funktion kopiert wie die obere Funktion den Inhalt eines Arrays auf den Backbuffer. Doch anstatt die Werte des Arrays direkt zu applizieren, werden diese als Index auf der mitgegebenen Palette benutzt. Die Palette ist einfach ein Array beliebiger Grösse mit allen benutzten Farben darin. Der Wert im arr-Array wird mit Modulo an die Palettengrösse angepasst. Wir benötigen diese Funktion unbedingt für den Plasma-Effekt. ;)


// returns an array in the size of the screen.
// filled with the backbuffer content.
this.screenToArray = function()
{
var arr = [];
for(z=0;z < screenArray[doubleBufferIndex].length; z++)
{
arr.push(screenArray[doubleBufferIndex][z]);
}
return arr;
}


Mit dieser Funktion kann man sich ein Array in der Grösse des Bildschirms "ziehen". Auf diesem kann man dann herumzeichnen und es dann wieder mit den obigen zwei Funktionen auf dem Bildschirm anzeigen. Wir benötigen dies, um das Basis-Bild des Plasma-Effektes zu erstellen.

Zusätzlich wird hier der Inhalt des Backbuffers auf das Array kopiert. Somit kriegen wir eine Kopie des aktuell im Hintergrund gezeichneten Bildschirms.

Da ich vielleicht die Engine auf Shader umstelle, werde ich für den Plasma-Effekt einen eigenen, neutralen Artikel schreiben. Ansonsten hätte ich ihn jetzt hier in diesem Artikel gepostet.

Für den Klassen-externen Plasmaeffekt brauchen wir schliesslich dann noch die Grösse des EmulatorBildschirms:


// In der EmuGraphicsAdapter-Klasse:
this.screenWidth = function() {return emuScreenWidth;}
this.screenHeight = function() {return emuScreenHeight;}


Hier ist der Source-Code für diesen Teil. Der Plasmaeffekt ist hier auch schon drin als eigene Datei, wird aber in einem anderen Artikel behandelt und bis dahin auch noch verbessert. Die index.html wurde leicht daran angepasst.

https://github.com/ben0bi/EmulatroniX/releases/tag/Blog_Series_Part_2.1_3

Du solltest nun in der Lage sein, deinen Emulatorbildschirm zu benutzen.

In Demo 1: Plasma wird der erwähnte Plasmaeffekt erklärt.

Es gibt noch Anpassungen zum Code nach Teil 2.1_2.

Viel Spass damit.

Dienstag, 6. Juni 2017

RetroPie Screen Orientation

Deutsch 

(click here for the english version.)

Um auf dem RetroPie-System die Bildschirm-Orientation zu ändern, muss man einfach in /boot/config.txt die Variable display_rotate hinzufügen oder ändern.

Aufgrund meiner speziellen Konfiguration habe ich die Kompassrichtungen gewählt, wobei ich bei Nord im Norden sitze und gegen Süden schaue.

Wenn der Bildschirm vor dir steht ist Nord die normale Orientation, Süd ist um 180°, Ost um 90° nach links und West um 90° nach rechts gedreht.

Da ich den Bildschirm nach oben spiegle, braucht es manchmal eine vertikale Spiegelung anstatt einer Drehung. Hier gebe ich euch nun die Zahlen dafür (horizontal spiegeln weiss ich grad nicht mehr, brauchts aber auch nicht wirklich). Für die Spiegelung kann man einfach den Orientation-Wert mit dem Spiegelungs-Wert binär ODER-verknüpfen:

0 = Nord
1 = Ost
2 = Süd
3 = West
0x20000 = Nord vertikal gespiegelt.
0x20001 = Ost vertikal gespiegelt.
0x20002 = Süd vertikal gespiegelt.
0x20003 = West vertikal gespiegelt.

Um ganz schnell die Orientation zu ändern, habe ich mir einfach für jeden Wert eine config.txt und ein .sh-Script geschrieben und die .sh-Scripts dann in ein Menu von EmulationStatin kopiert, welches .sh-Scripts "versteht".

Hier ein Beispiel:
/home/pi/orientation/Config_East_Flipped.txt

...

display_rotate = 0x20001


/home/pi/RetroPie/MyMenu/Orientation_East_Flipped.sh

#!/bin/bash
sudo cp /home/pi/orientation/Config_East_Flipped.txt /boot/config.txt
sudo shutdown -r now


Nach dem Kopieren wird einfach der RasPi neu gestarted und gut ist.

Viel Spass damit!

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.

Dienstag, 23. Mai 2017

DIY: Emulator Teil 2.1_1: Der Emulator Bildschirm

In diesem Artikel haben wir die grundlegende Grafik aufgesetzt. Nun geht es darum, dass der Emulator einen an sich angepassten Bildschirm bekommt, welchen wir jedoch auf unserem Graphikgerüst beliebig skalieren können.

Also ist das Ziel, auf einer Textur, welche die Grösse des Emulator Bildschirms hat, die einzelnen Pixel zu bearbeiten. Diese Textur wird dann skaliert auf unserem Bildschirm angezeigt.

Render-To-Texture so wie ich das wollte scheint nicht wirklich zu gehen. Array-to-Texture, das wärs gewesen. Naja...müssen wir das halt anders machen.

Also generell wird im Internetz geraten, so was auf einem eigenen HTML5 Canvas zu zeichnen. Dies könnte jedoch, nach Angaben, Konflikte mit WebGL geben. Per Zufall bin ich dann auf das Graphics-Objekt gestossen. Da kann man einfach etwas zeichnen und dies dann als Textur generieren.

Da hier einiges an Code abgehandelt wird, wird dieser Artikel in verschiedene Teile gegliedert.
In diesem Teil geht es um die Erstellung einer neuen Klasse und dann um die Initialisierungs-Funktion des Bildschirms. Die weiteren dazu benötigten Funktionen kommen in den folgenden Artikeln.

Theorie

Der Emulatorbildschirm besteht aus einer bestimmten Anzahl Pixel, welche auf dem PIXI-Bildschirm skaliert angezeigt werden sollten. Dazu wird ein PIXI-Container erstellt und daran werden in x und y Richtung reihenweise kleine farbige Rechtecke angehängt. Ein Rechteck stellt einen Pixel dar. Da der Aufbau der Rechtecke recht lange dauert, werden wir dies nur einmal machen. Danach werden wir nur noch die Grundfarbe der Textur verändern mit dem tint-Wert. Deshalb wird die Textur selbst weiss sein (nicht schwarz).

Dies alles wird zwei mal gemacht, so dass wir in dem einen Container "zeichnen" können, während der andere angezeigt wird.  Wenn fertig gezeichnet wurde, können wir einfach das visible-Flag der beiden Container wechseln, und schon wird der vorher gezeichnete Container angezeigt. (Das ist ein sogenannter Double-Buffer) Somit können wir ein "flackern" während des Bildaufbaus verhindern.

Mit PIXI.Graphics können wir Texturen erstellen, ohne dafür ein Bild zu laden. Chrome zum Beispiel motzt blöd rum und verweigert das Laden von Texturen als file:///. (Also in der lokalen Entwicklungsumgebung.)...lassen wir das doch gleich ganz.

Code

Der Code verändert sich mit jedem Part. Eventuell musst du (wie hier in index.html) in schon bearbeiteten Dateien "herumpfuschen". Jetzt kommt ziemlich viel Code. Ich werde den Code in Abschnitten unterbrechen um ihn zu erklären. So lange es nicht anders beschrieben wird, kannst du einfach dort weiterschreiben, wo du vorher warst.

Im Ordner js erstellen wir erst mal eine neue Datei: EmuGraphicsAdapter.js

EmuGraphicsAdapter.js:

EmuGraphicsAdapter = function(newwidth, newheight, bgcolor, bordercolor)
{

//  ...

In JavaScript kann man "Klassen" über Funktionen erstellen. Alle Parameter sind optional, deshalb werden wir prüfen, ob sie gegeben wurden. IN dieser Funktion werden nun folgende Variablen und Funktionen erstellt:


var PIXIStage = RSTAGE(); // oder RBACKSTAGE() oder RHUDSTAGE()

var emuBorderColor = 0x111133; // Dunkles Dunkelblau.
var emuBackgroundColor = 0x000000; // Normalerweise Schwarz.

// Breite des Randes.
var emuBorderWidth = 10;

// Grösse des Emulator Bildschirms
var emuScreenWidth = 40;
var emuScreenHeight = 40;

// Die doppelte Grösse des Emulator Bildschirms.
var emuDrawWidth = emuScreenWidth * 2;
var emuDrawHeight = emuScreenHeight * 2;

// Double Buffering.
var doubleBufferIndex = 0; // 0 oder 1.
var screenArray = [];


Mit var erstellt man private Variablen oder Funktionen in einer JS-Klasse. Öffentliche Variablen erstellt man mit this (z.B. this.positionX = 5;) und spricht sie auch innerhalb der Klasse mit this an.

  • PIXIStage: Referenz zum PIXI-"Root"-Container. RUNPIXI stellt dafür drei Container zur Verfügung: RSTAGE() ist der mittlere, welcher dank RUNPIXI mit Ctrl+Pfeiltasten gescrollt werden kann. Du kannst auch RBACKSTAGE() für den hintersten oder RHUDSTAGE() für den vordersten nehmen. Diese werden jedoch nicht gescrollt.
  • emuBorderColor: Die Farbe des Rahmens. Der Rahmen wird so oder so erstellt, da es "unsichtbare" Linien geben könnte. Wir werden diese später an die Hintergrundfarbe des PIXI-Screens anpassen.
  • emuBackgroundColor: Die standard Hintergrundfarbe des emulierten Systems. Bei einigen kann das Blau sein (Atari 800XL zum Beispiel), bei einigen Hellgrau (GameBoy) und bei den meisten Systemen jedoch schwarz.
  • emuBorderWidth: Die Breite des oben genannten Rahmens (unskaliert).
  • emuScreenWidth / emuScreenHeight: Die Grösse des Emulator Bildschirms.
  • emuDrawWidth / emuDrawHeight: Die doppelte Grösse des Emulator Bildschirms. Ein Emulator-Pixel ist 2x2 "reale" Pixel gross, deshalb wird der Bildschirm verdoppelt und dann um die Häfte runterskaliert um das Originalbild zu erhalten.
  • doubleBufferIndex: Der Index des Buffers auf welchem aktuell gezeichnet wird. Der jeweils andere Buffer wird aktuell angezeigt.
  • screenArray: Dieses Array enthält wieder zwei Arrays welche Referenzen auf die Pixel der Buffer enthalten. Die Container selbst werden ausserhalb der Klasse global erstellt, so dass wir sie aus der PIXI-Hierarchie löschen können wenn ein neuer Bildschirm initialisiert wird.

Initialisierungs-Funktion:


this.initialize = function(width, height, bgColor, borderColor)
{
         if(width)
                  emuScreenWidth = width;
         if(height)
                   emuScreenHeight = height;

         if(bgColor)
                   emuBackgroundColor = bgColor;
         if(borderColor)
                    emuBorderColor = borderColor;

         emuDrawWidth = emuScreenWidth * 2;
         emuDrawHeight = emuScreenHeight * 2;

         if(EmuGraphicsAdapter.containers.length > 0)
         {
                 for(var i = 0; i < EmuGraphicsAdapter.containers.length; i++)
                 {
                       PIXIStage.removeChild(EmuGraphicsAdapter.containers[i]);
                 }
         }

         // eventuell die Pixel Textur erstellen.
        EmuGraphicsAdapter.createOriginalPixelTex();

  • Mit den ifs am Anfang wird überprüft, ob ein Parameter vorhanden ist. Dann wird die zugehörige Variable gesetzt. Danach wird die "reale" Bildschirmgrösse neu berechnet.
  • EmuGraphicsAdapter.containers ist eine globale statische Variable und wird später erstellt. Hier wird überprüft, ob schon etwas vorhanden ist. Wenn ja, wird es von der PIXIStage gelöst.
  • EmuGraphicsAdapter.createOriginalPixelTex() ist eine statische globale Funktion, welche die weisse 2x2px Textur erstellt. Wenn sie schon vorhanden ist, muss sie nicht neu erstellt werden.
Nun wird eine Hintergrundtextur und die Rahmentextur erstellt. Die Hintergrundtextur braucht es nicht wirklich, ich erstelle sie jedoch trotzdem.


    // Hintergrund Textur
   var gbg = new PIXI.Graphics();
   gbg.beginFill(emuBackgroundColor, 1.0);
       gbg.drawRect(0,0, emuDrawWidth, emuDrawHeight);
   gbg.endFill();

   // Rahmen
   var gbord = new PIXI.Graphics();
   gbord.beginFill(emuBorderColor, 1.0);
      gbord.drawRect(0, 0, emuDrawWidth + emuBorderWidth * 2,  emuBorderWidth);
      gbord.drawRect(0, 0, emuBorderWidth, emuDrawHeight + emuBorderWidth * 2);
      gbord.drawRect(emuDrawWidth + emuBorderWidth, 0, emuBorderWidth, emuDrawHeight + emuBorderWidth * 2);
       gbord.drawRect(0, emuDrawHeight + emuBorderWidth, emuDrawWidth + emuBorderWidth * 2, emuBorderWidth);
   gbord.endFill();

   // "ziehe" Texturen davon.
   var backgroundTex = gbg.createCanvasTexture();
   var borderTex = gbord.createCanvasTexture();

   // Nun werden alle "Sprites" generiert.
   // Für jeden Buffer einmal. Zur Sicherheit.
   var backgroundSprite1 = new PIXI.Sprite(backgroundTex);
   var backgroundSprite2 = new PIXI.Sprite(backgroundTex);

    var borderSprite1 = new PIXI.Sprite(borderTex);
    var borderSprite2 = new PIXI.Sprite(borderTex);

    // zwei neue PIXI.Container mit dem zusammengesetzten Bild..
    var container1 = new PIXI.Container();
    var container2 = new PIXI.Container();

    // und das jeweilig zugehörige array.
    var arr1 = [];
    var arr2 = [];

    // ..und erstmal den Hintergrund hinzufügen.
    container1.addChild(backgroundSprite1);
    container2.addChild(backgroundSprite2);


Wir malen erstmal auf zwei PIXI.Graphics()-Objekten herum und generieren uns Texturen daraus.
Texturen kann man nicht direkt anzeigen, dazu werden Sprites benötigt. Eine Textur kann für mehrere Sprites verwendet werden. Sprites haben eine Position, Grösse und Rotation.

Am Schluss wird das Hintergrundsprite an die Buffer-Container angehängt.

Weiter oben haben wir die Funktion EmuGraphicsAdapter.createOriginalPixelTex() aufgerufen. Mit der daraus generierten Textur können wir nun endlich die Pixel generieren...


    for(var y=0; y<emuScreenHeight; y++)
    {
        for(var x=0; x<emuScreenWidth; x++)
        {
            var pixel1 = new PIXI.Sprite(EmuGraphicsAdapter.originalPixelTex);
            pixel1.x = x*2;
            pixel1.y = y*2;

            var pixel2 = new PIXI.Sprite(EmuGraphicsAdapter.originalPixelTex);
            pixel2.x = x*2;
            pixel2.y = y*2;

            container1.addChild(pixel1);
            container2.addChild(pixel2);

            arr1.push(pixel1);
            arr2.push(pixel2);
        }
    }


Wir haben die Pixel generiert und an die richtige Position verschoben an die Container angehängt sowie auch an das zugehörige Array. Um eine x/y-Position im Array zu finden, brauchen wir folgende Formel: index = y*screenX + x
Nun muss nur noch der Rahmen an die Container angehängt werden. Dieser wird noch ein bisschen nach links oben verschoben. Dann wird das Ganze noch zusammengesetzt und schon haben wir unseren Emulator-Bildschirm:


    borderSprite1.x = - emuBorderWidth;
    borderSprite1.y = - emuBorderWidth;
    borderSprite2.x = - emuBorderWidth;
    borderSprite2.y = - emuBorderWidth;
    container1.addChild(borderSprite1);
    container2.addChild(borderSprite2);

    // Buffer-Arrays neu initialisieren und dann aufbauen.
    EmuGraphicsAdapter.containers = [];
    EmuGraphicsAdapter.containers.push(container1);
    EmuGraphicsAdapter.containers.push(container2);

    screenArray = [];
    screenArray.push(arr1);
    screenArray.push(arr2);

    // Buffer index resetten.
    doubleBufferIndex = 0;

    // Schliesslich noch an den Root-Container anhängen.
    PIXIStage.addChild(container1);
    PIXIStage.addChild(container2);


Schliesslich und endlich wird der Bildschirm noch zentriert und dann der eine Buffer unsichtbar gemacht. Dann werden die Buffer noch mit der Hintergrundfarbe "gefüllt".


    this.reposition();
    this.switchBuffers();
    fillBuffer(emuBackgroundColor, 0);
    fillBuffer(emuBackgroundColor, 1);

    console.log("EmuGraphicsAdapter: Screen with size "+emuScreenWidth+"x"+emuScreenHeight+" created.");

}


Das war die Initialisierungsfunktion. Dies war so ziemlich die komplexeste Funktion, alle anderen werden einfacher sein. Es fehlen noch einige Funktionen welche hier benutzt werden.

Weiter gehts mit dem Rest vom grundlegenden Graphikaufbau (Teil 2.1_2).