DIY Emulator Teil 2.1.1: Refining EmuGraphicsAdapter
in Unity
Nachdem ich in diesem Artikel gelernt habe, dass schon kleinste Änderungen am Code enorm mehr Speed herausholen können, werden nun erstmal ein paar Speed-Optimierungen gemacht.(Ich mache dann (eventuell :) ) schon mal einen "richtigen" Emulator aber ich muss erst noch rausfinden, wie man einen emulierten (schon programmierten) Chip überhaupt einbaut und benutzt und davor hab ich schon ein bisschen Bammel weil ich wirklich absolut keine Ahnung davon habe. Bitte entschuldigt das andauernde Aufgeschiebe. Diese Tutorials sollen ja auch für mich sein, nicht nur für dich... ;) )
Darum wurde dort die MarkPixelToChangeByIndex-Funktion im EmuGraphicsAdapter (der Klasse aus diesem Artikel) hinzugefügt.
Um noch mehr Speed herauszuholen - denn millionenfache Funktionsaufrufe brauchen dann doch ein bisschen Zeit - werden wir nun noch eine Funktion generieren, die gleich eine gesamte Map (Display) mit der zugehörigen Palette direkt auf der Textur verrechnet, ohne dazu immer extra pro Pixel eine Funktion aufrufen zu müssen.*
[edit]: Wenn dein Emulator Display genau gleich gross ist, wie die Textur und auf 0,0 positioniert wird (also keine "hidden Pixel" hat), ist MarkPixelToChangeByIndex immer noch ein bisschen schneller als die folgende Funktion.*
[edit 2]: Ich bin grüble darüber nach, ob und wie man das mit Shadern "richtig schnell" machen kann. Anders gesagt: Auch wenn hierbei kein Emulator rauskommt, hast du dann trotzdem eine richtig flotte 2D-Pixelzeichungs-Engine parat.
*Desweiteren wird diese Funktion auch das Display des Emulators "korrekt" auf der Textur platzieren:
Einige Systeme haben einen grösseren Display-Speicher als auf dem Bildschirm angezeigt. Eine oder mehrere Linien oder Zeilen sind ausserhalb des sichtbaren Bereiches. Diese "hidden pixel" werden vor allem bei Scrolling-Funktionen benutzt, damit es kein Geflacker gibt.
Wir könnten entweder die Texturgrösse anpassen, oder einfach diese Pixel auslassen. Ich habe mich erstmal für zweiteres entschieden.
Schlussendlich gibt es noch einen paletteModifier, so dass man nicht immer vorher die gesamte Map mit neuen Indexen aufbauen muss, sondern nur diesen Modifier verändert. (Wird durch den plasmaIndex im Placeholder_Emulator bestimmt.)
Also, hier die Funktion: MarkPalettedMapToChange1D in der EmuGraphicsAdapter-Klasse
Die Funktion hat ziemlich viele Parameter, Sorry dafür.
/* Parameters: * map: 1-dimensional array with palette indexes. * mapwidth: width (max-x) of the map to make it 2-dimensional. * mapheight: height (max-y) of the map to make it 2-dimensional. mapheight can be calculated in-function but that wastes processing power. * palette: 1-dimensional array with colors arranged in the right order. * paletteModifier: add this modifier to the palette index on the map to get the right color. * used to not create the whole map with each palette change. * posX: start-position of the map on the display. used for displays with "hidden pixels". * posY: start-position of the map on the display. used for displays with "hidden pixels". */ // define the variables once instead of in each function call. private int tmp_texx, tmp_texy, tmp_texidx, tmp_emux, tmp_emuy, tmp_emuidx; private int tmp_palsize, tmp_palindex; private int tmp_spritewidth, tmp_spriteheight, tmp_mapsize; public void MarkPalettedMapToChange1D(int[] map, int mapwidth, int mapheight, Color[] palette, int paletteModifier = 0, int posX = 0, int posY = 0) { // get spritewidth and height. tmp_spritewidth = (int)m_drawable_sprite.rect.width; tmp_spriteheight = (int)m_drawable_sprite.rect.height; tmp_mapsize = map.Length; tmp_palsize = palette.Length; // go through x and y instead of only the index. // for better calculation of the emulator-display-position. // go through the DISPLAYED texture array: for(tmp_texy=0;tmp_texy < tmp_spriteheight;tmp_texy++) { tmp_emuy = tmp_texy - posY; // y not in bounds, break or continue. if (tmp_emuy < 0) // < 0 = continue continue; if(tmp_emuy >= mapheight) // > height = break break; for (tmp_texx = 0; tmp_texx < tmp_spritewidth; tmp_texx++) { // calculate position on the EMULATOR display: tmp_emux = tmp_texx - posX; // x is not in bounds, break or continue. if (tmp_emux < 0) continue; // continue if smaller. if (tmp_emux >= mapwidth) break; // break if bigger. // calculate the real index on the map. // because x and y are in boundsl, we do not need to check the index itself. tmp_emuidx = (int)((tmp_emuy * mapwidth) + tmp_emux); // get the palette index tmp_palindex = map[tmp_emuidx] + paletteModifier; // maybe we need to adjust the palette index to get it into bounds. while (tmp_palindex >= tmp_palsize) tmp_palindex -= tmp_palsize; // finally set the new color. tmp_texidx = tmp_texy * tmp_spritewidth + tmp_texx; m_cur_colors[tmp_texidx] = palette[tmp_palindex]; } } }
Alle tmp-Variablen werden im Scope der Klasse erstellt, damit sie nicht bei jedem Aufruf der Funktion neu erstellt werden müssen. Die Parameter der Funktion sind die folgenden:
- map: 1-dimensionales Array mit Palette-Indexen.
- mapwidth: Breite einer Zeile der map (x)
- mapheight: Höhe der map (y) (Könnte man auch in der Funktion jedesmal neu berechnen, was jedoch unnötig Prozessorpower verbraucht.)
- palette: 1-dimensionales Array mit den Farben (Color) in der richtigen Reihenfolge.
- paletteModifier: Addiere diese Zahl zu jedem Index auf der map.
- posX: Startposition der map auf der Textur in Pixeln (x).
- posY: Startposition der map auf der Textur in Pixeln (y).
Nun können wir noch die copyDisplay-Funktion im Placeholder_Emulator ändern:
// copy the paletted display colors to the real color array. protected void copyDisplay() { // alt: for(q = 0; ... gfx.MarkPalettedMapToChange1D(m_display, disp_width, disp_height, m_palette, (int)m_plasmaIndex, 0, 0); }
Uuund....weiteres folgt bald. Eventuell.
Das Projekt befindet sich in diesem Git-Repository, im JUMPEE-Verzeichnis.
Keine Kommentare:
Kommentar veröffentlichen