Борьба с клешингом в С64

Сразу за релизом С= распишу, как реализован режим мультиколора для С64.

Смотреть/скачать демо

Это стандартный режим видеоконтроллера комодора, и один из любимых на демосцене.

Итак, задача — сконвертировать оригинальный формат экрана С64 в режиме мультиколор для вывода в видеопамять zx enhanced (ts config).
Напомню, что результатом должна быть линейная адресация с тетрадой бит на пиксел, указывающих на цвет точки.
Сразу скажу, что разбирал я стандартный формат, для которого нашлось приличное количество качественной графики в оригинальном формате.

Мультиколорный режим 160х200х16 цветов
Итак, при разрешении 320х200 применяется удлинённый в ширину пиксель, позволяющий иметь 4 цвета из 16 доступных.
Разрешение экрана становится 160х200, и видеопамять в этом режиме разбита на три блока + байт Background Color:
Bitmap RAM — каждый байт хранит 4 пикселя, два бита на пиксель. 4 комбинации битов указывают, каким образом будет получен результирующий цвет для точки:
Bit pair = %00: Pixel has Background Color.
        Bit pair = %01: Pixel color is determined by bits #4-#7 of the corresponding screen byte in Screen RAM.
        Bit pair = %10: Pixel color is determined by bits #0-#3 of the corresponding screen byte in Screen RAM.
        Bit pair = %11: Pixel color is determined by the corresponding color byte in Color RAM.

Цвет точки определяется тетрадой в Screen RAM (что, по сути, является подобием аттрибутов zx spectrum).
Растр занимает 160*200/4 = 8 000 байт

Screen RAM — указатель на цвет для пикселя, две тетрады для левого и правого пикселя. Является номером цвета в палитре из 16 цветов.
Размер аттрибутов — 1000 байт

Color RAM — блок байт, указывающий на цвет точки
Размер блока цветов — 1000 байт

Особенность режима в том, что блок 8х8 точек позволяет отобразить только 4 цвета…
Оказывается, что С64 тоже имеет клешинг! :)

Декодирование
Основной цикл:
устанавливаем цвет бекграунд, начинаем разбор битмап. Результат (16ц, тетрада на пиксел) складываем начиная с адреса #c000:

pic_base		equ #4002

show_pic		ld hl,pic_base+$2710
			ld bc,BORDER
			ld a,(hl)
			and #0f
			out (c),a

			ld h,a
			sla a
			sla a
			sla a
			sla a
			or h
			ld (background_color+1),a

			ld hl,pic_base
			ld de,#c000
			ld ix,pic_base+$1F40
			ld iy,pic_base+$2328

			ld a,200/8
2			exa
			ld b,40
3			push bc
			push de

			exx
			ld e,(ix+0)	; screen ram
0			exx
			ld b,8

1			ld c,(hl)
			inc hl
			push de
			call unpack_pair
			call unpack_pair
			call unpack_pair
			call unpack_pair
			pop de
			inc d
			djnz 1b
			inc ix
			inc iy
			pop de
			pop bc
			inc e
			inc e
			inc e
			inc e
			djnz 3b
			ld e,b
			ld a,d
			add 8
			ld d,a
			jr nz,1f
			push bc
			ld bc,PAGE3
pg			ld a,0
			out (c),a
			ld (cur_page+1),a
			inc a
			ld (pg+1),a
			pop bc
			ld d,#c0
1			exa 
			dec a
			jr nz,2b
			ret


Разбираем пару бит пикселя по озвученному выше принципу, результатом является 1 байт (две точки) в формате 16ц — две тетрады с одинаковым содержимым:

unpack_pair		xor a
			rl c
			rla
			rl c
			rla

			exx
			or a
			jr nz,0f
background_color	ld a,0
			jr 2f

0			dec a	; %01: Pixel color is determined by bits #4-#7 of the corresponding screen byte in Screen RAM.
			jr nz,1f
			ld a,e
			and #f0
			ld c,a
			srl a
			srl a
			srl a
			srl a
			or c
			jr 2f

1			dec a	; %10: Pixel color is determined by bits #0-#3 of the corresponding screen byte in Screen RAM.
			jr z,3f
			ld a,(iy+0)
			jr 4f

3			ld a,e
4			and #0f
			ld c,a
			sla a
			sla a
			sla a
			sla a
			or c

2			exx
			ld (de),a
			inc de
			ret


Готово. Одна картинка на экране.
Неплохо бы сделать галерею…
Компрессирую:
for %%i in (*.koa) do ( start /wait zx7.exe "%%i" );

Собираю бинарник с выводом названия и длины каждого изображения:
@echo off
del img_pack.bin
copy /Y nul: img_pack.bin
for %%I in (*.zx7) do (
 copy /b img_pack.bin+"%%I" img_pack.bin
 @echo %%~zI,
)

Данные для галереи готовы.

PS: Напоследок — бонус.
Минимальный по коду скроллер для тайлового режима!
Готовим шрифты. полотно — размером 512 точек по ширине, для упрощения вычисления положения символа:

Использовать будем нижний, зелёный шрифт, размером 16х16 точек для символа.
А дальше всё элементарно:

scroll		ld a,#0e
		add 2
		and #0f
		ld (scroll+1),a
		ld bc,T1XOFFSL
		out (c),a
		ret nz

Скроллим весь тайловый слой на 2 точки… И сдвигаем в тайловой памяти блок на четыре байта влево (2 байта на тайл, 2 тайла ширина и высота символа):

		ld bc,PAGE3
		ld a,Tile_page
		out (c),a
		ld hl,#dc84
		ld de,#dc80
		ld bc,40*2
		ldir
		ld hl,#dd84
		ld de,#dd80
		ld bc,40*2
		ldir

new_char	ld hl,text
		ld a,(hl)
		inc hl
		or a
		jr nz,1f
		ld hl,text
		ld a," "
1		ld (new_char+1),hl
		cp #60
		jr c,1f
		sub #20
1		

Определяем ряд тайлов в графике по коду символа и постим тайлы символа в память:
ld de,#1080
		ld c," "
		cp "@"
		jr c,1f
		ld de,#1100
		ld c,#40
1		
		sub c
		add a
		ld l,a
		ld h,0
		add hl,de
		ex de,hl
		ld hl,#dc80+40*2
new_char_fill	ld c,l
		call ncf1
		ld a,e
		add #3f
		ld e,a
		inc h
		ld l,c
ncf1		ld (hl),e
		inc l
		ld (hl),d
		inc l
		inc e
		ld (hl),e
		inc l
		ld (hl),d
		ret

Вуаля!
Удачи.

3 комментария

avatar
Мультиколор тут подразумевает, что на C64 они как раз выходят за рамки 4 цвета на знакоместо или что?
Для самого C64 клешинг конечно не был такой проблемой, т.к. были и аппаратные спрайты и даже наполовину аппаратный скроллинг, так что это вам не спектрум, конечно, чтобы оно лезло в глаза в почти любой игре.
avatar
P.S.
А, перечитал еще раз начало и дошло.
avatar
ДядьВов! Ты чё, в коммодорщики подался???
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.