Scroll pionowy — optymalizacja

Autor: Wojciech Muła
Dodany:9.03.2002

Treść

Wprowadzenie

W artykule pokażę jak zminimalizować ilość przesyłanych danych przy przesuwanych w pionie napisach. Oczywiście można analogicznie postąpić przy scollach w poziomie.

Poniżej zostały zdefiniowane wszystkie stałe i zmienne które będą wykorzystywane w przykładach.

const unsigned int img_width;  // rozmiar
const unsigned int img_height; // obrazka

const unsigned int text_height;// wysokość tekstu

typedef pixel scanline[img_width]; // pojedyncza linia obrazu

scanline image[img_height];  // bufor obraz
scanline text [text_height]; // bufor dla 1 linii tekstu

// funkcja wyświetla generuje napis w buforze 'text'
void render_text(const char* string);

Typowy scroll

W poniższym pseudokodzie obraz jest przesuwany do góry.

int text_scanline = text_height;

...
while (stop == 0)
  {
   for (int i=0; i<img_height-1; i++) // przesuń obraz o 1 linię do góry
       image[i] = image[i+1];         // czasochłonne

   if (text_scanline == text_height)  // "wysunięto" już całą linię tekstu
      {                               // należy wygenerować nowy tekst
       render_text(...);
       text_scanline = 0;
      }

   image[img_height-1] = text[text_scanline++]; // przepisz do ostatniej linii
                                                // obrazu jedną z linii tekstu

   screen = image; // wyświetl obraz
  }

Przesunięcie image o 1 linię wymaga przesłania (img_height-1)* img_width pikseli i tego należy się pozbyć.

Optymalizacja

Proponuję potraktować image jako bufor okrężny scanlinów.

int text_scanline = text_height; // licznik wyświetlonych linii tekstu
int top_line      = 0;           // wskaźnik początku bufora okrężnego

while (stop == 0)
  {
  if (text_scanline == text_height)  // "wysunięto" już całą linię tekstu
      {                               // należy wygenerować nowy tekst
       render_text(...);
       text_scanline = 0;
      }

   // przepisanie do ostatniej linii obrazu jednej z linii tekstu
   // ostatnia w buforze okrężnym nie tablicy!
   image[top_line] = text[text_scanline++];

   / należy kopiować scanliny z bufora ekranu w trochę innej kolejności
   n = 0;
   for (i=top_line; i<img_height; i++) // najpierw kopiujemy górną część
       screen[n++] = image[i];

   for (i=0; i<top_line; i++)          // a następnie dolną
       screen[n++] = image[i];

   // zwiększamy top_line
   top_line += (top_line+1) % img_height;
  }

W przypadku gdy obliczenie reszty z dzielenia będzie kłopotliwe (np. pisząc w asemblerze) można użyć prostszego kodu:

if (++top_line == img_height) top_line=0;

Podsumowanie

Przyrost prędkości będzie znaczny, zostało wyeliminowane praktycznie jedno przesyłanie bufora bardzo niewielkim kosztem.

Poniżej zestawienie liczby przesłań scanlinów w obu metodach:

Teoretycznie można więc liczyć na około 200% wzrost prędkości.