COOKIES

This site may be using cookies to melk you with your own data. I, ben0bi, am not the owner of this web service and I also do not maintain their servers. But the EU and the owner of this service think, that the user (me) has the responsibility to inform the consumer (you), that this website uses cookies. Again: I, ben0bi, NEVER use cookies. I am not responsible for the setup of this web service. I just present some information here and do not intend to spy on you for whatever reason ever. But (also again), I do not host this website nor do I maintain any servers related to this website nor do I benefit from using the cookies maintained from this service. I hereby give the responsibility for using cookies on blogspot back to the owners of blogspot.

Samstag, 19. Oktober 2019

DIY Emulator Teil 2.1.1: Refining EmuGraphicsAdapter

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).
Es wird, obwohl die Arrays eindimensional sind, trotzdem 2-dimensional durch das Textur-Array hindurch gegangen. Dabei wird jeweils die Position des Pixels auf der map berechnet, und ob diese Position überhaupt auf der map vorhanden ist. Dazu braucht es mapwidth und mapheight. Wenn x oder y auf der map kleiner als 0 ist, wird die Schleife mit continue sofort fortgesetzt, wenn die jeweilige Variable jedoch zu gross ist, wird die zugehörige Schleife sofort mit break gleich ganz verlassen. PS: Einige Checks habe ich wieder herausgenommen, da sie nur unnötig Prozessorzeit verbrauchten und nie "erfüllt" wurden. Dies hier ist die aktuellste Version.

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