BMP2HIRES

Data

W poniższym tekście podejmiemy wyzwanie konwersji i wyświetlenia pliku w formacie BMP o wymiarach 320x200 w 2 kolorach na C64 – koderski level easy. Format pojawił się pierwotnie na systemach OS/2 i przeżył ten system prawdopodobnie ze względu na swoją prostotę i brak obciążeń patentowych.

No to otwieramy dowolny program graficzny na współczesnej maszynie. Ładujemy tam jakieś zdjęcie z wakacji z ulubionym psem albo dziewczyną i zmieniamy wymiary zdjęcia do 320x200 oraz jego głębię do 1 bit. Oczywiście warto zastosować konwersję przez rozproszenie pikseli. Teraz zapisujemy naszą fotkę w formacie BMP i ów plik ładujemy na C64. Co da się zauważyć od razu, to fakt, że nasz plik ładuje się pod adres $4D42. Dzieje się tak dlatego, że pierwsze dwa bajty pliku BMP utworzonego na systemie innym niż OS/2 w ASCII oznaczają „BM”. To fantastyczny zbieg okoliczności, gdyż pierwsze dwa bajty pliku PRG na C64 interpretowane są jako adres ładowania, a $4D42 to niemal początek drugiego banku pamięci VIC-II, który standardowo nie jest używany. Pasuje nam to idealnie, bo wiemy już, gdzie nasza procedura konwertująca ma szukać pliku w pamięci. Jednak to nie koniec uproszczeń. Kolejne 2 bajty pliku oznaczają jego wymiary razem z nagłówkiem i w naszym przypadku będzie to $1F7E. Dokładnie są to 4 kolejne bajty, ale pliki o głębi kolorów do 256 okupują i tak tylko pierwsze dwa. Wszystkie te bajty zapisane są w pliku w kolejności: mniej znaczący bajt najpierw, co też jest dla nas, programistów asemblera 65xx uproszczeniem. Tak więc znajdując od $4D42 kolejno #$7E i #$1F wiemy, że mamy do czynienia z plikiem BMP o pożądanych przez nas wymiarach i głębi.

LDA #$7E CMP $4D42 BNE error LDA #$1F CMP $4D43 BNE error ...

Oczywiście możemy sobie utworzyć plik o rozdzielczości i liczbie kolorów, które sumarycznie dadzą z nagłówkiem taki sam rozmiar pliku, ale hej, nie będziemy się oszukiwać. Wiedząc, że bitmapa 320x200x1 zajmuje $1F40 bajtów oraz mając świadomość, że podczas ładowania pliku na C64 został on skrócony o adres ładowania (2 bajty), możemy sobie wyliczyć dokładny koniec pliku: $4D42+$1F7E-$2=$6CBE. Ostatni bajt naszej bitmapy do odczytu znajduje się pod adresem $6CBD, ale na tym uproszczenia się kończą, ponieważ ostatni bajt nie jest wcale ostatnim bajtem macierzy pikseli w grafice. Ze względu na historyczną kompatybilność z menadżerem prezentacji systemu OS/2 od IBM nasza macierz pikseli w pamięci zapisana jest do góry nogami. Po prostu ktoś w IBM wymyślił sobie, że fajniej będzie się kreśliło wykresy, gdy adres będzie zwiększał się wraz ze współrzędnymi układu kartezjańskiego. Ech ci matematycy... Tak więc grafika z pliku jest wczytywana od dołu do góry do bufora ramki na PC. Każdy, kto dysponował przeglądarką SEA pod MS-DOS oraz odpowiednio dużym plikiem BMP i odpowiednio wolnym komputerem, widział ten proces na własne oczy. Możemy więc rozpocząć wczytywanie do banku wideo albo od początku pliku i dostaniemy obrazek odwrócony do góry nogami, albo od końca pliku i dostaniemy obrazek odbity lustrzanie. Wszystko to jednak jedynie przy organizacji liniowej bufora ramki. Niestety, VIC-II w naszym C64 interpretuje w trybie bitmapowym grafikę tak, jak tekst, czyli 1000 bloków po 8 bajtów każdy następujących kolejno po sobie liniowo, a nie 8000 bajtów następujących kolejno po sobie liniowo. Stąd drugie podejście będzie w tym wypadku łatwiejsze do zaprogramowania. Czyli czytamy plik od tyłu, jak leci bajt po bajcie i zapisujemy od góry, lecz z prawej do lewej w organizacji kafelkowej. Dzięki temu żadna operacja na bitach w kopiowanych bajtach nie jest konieczna:

LDA #$3B ;tryb graficzny HIRES STA $D011 LDA #$18 STA $D018 LDY #8 ;jeden kafelek ma 8 bajtów LDX #$28 ;jedna linia ma 40 bajtów source LDA $6CBD ;odczyt zaczynamy od końca pliku BMP target STA $2138 ;zapis zaczynamy od końca 1 linii HIRES LDA source+1;zmniejsz adres BMP o 1 bajt BNE no1 DEC source+2 no1 DEC source+1 LDA target+1 ;zmniejsz adres HIRES o 8 bajtów SEC SBC #8 BCS no2 DEC target+2 no2 STA target+1 DEX BNE source LDA target+1 ;następna linia – zwiększ adres HIRES CLC ADC #$41 BCC no3 INC target+2 no3 INC target+2 STA target+1 DEY BNE source-2 LDA target+1 ;następne 8 linii – zwiększ adres HIRES CLC ADC #$38 BCC no4 INC target+2 no4 INC target+2 STA target+1 LDA target+2 ;czy koniec bufora ramki? CMP #$40 BNE source-4 RTS

Całość zajmuje niewiele ponad 80 bajtów i wykonuje się w ok. 1 sekundę. Czego chcieć zatem więcej? Programu, który zrobi to za nas. Ale o tym już niebawem.

Data/Tropyx