Rev 861 | Blame | Compare with Previous | Last modification | View Log | Download
TODO: при экране Уже 320 справа рисуются лишние столбцы, спрайты тоже усекаются неправильно. и центровка не там?
В Nedodemo 2 скролл по 1 пикс. для этого две копии экрана, разложенного в ld de:push. выход патчится jp (hl), потом распатчивается (хотя там не нужно, т.к. скролл только влево)
это 1 байт на пиксель 16ц *2, т.е. 2 байта на пиксель
для экрана 512x512 потребуется более 512K ОЗУ под фон (т.к. ещё выход jp (hl)). или можно ровно 512К, если выход может накладываться на другие данные или следующее окно памяти
при этом на экране рисовать неудобно - каждую точку надо ставить два раза.
Worms потребует 1M ОЗУ только под фон.
можно делать скролл по 2 пикс - тогда 1 байт на пиксель, пиксель ставим только один раз. Worms потребует 512K ОЗУ под фон
одна строка 512 пикс занимает 512 байт, состоит из 4 подстрок 128+1 байт (в Nedodemo 2 была ширина 920 пикс, состояло из 4 подстрок по 240+1 байт).
это годится и для гонок, где строки по-разному сдвинуты (или сдвигается по горизонтали весь экран)
на таком экране нельзя делать бесконечно большой скролл, т.к. строки не зациклены.
но можно на его основе попробовать это сделать, если вызывать (патч, jp, анпатч) отдельно левую и правую половинку (как в Супер Марио).
сначала правую, чтобы правая не запорола левую при прерывании.
потом маскировать края экрана.
в простейшем случае маскируем (или прямо выводим???) всегда один знакоместный столбец - 0-й (при этом выводим либо 0..39, либо 1..40, с заходом на следующую строку)
плюс в прерывании восстанавливаем стек из de (занулять нельзя - запорем один байт на краю экрана).
что будет при прерывании в конце строки (т.к. когда sp в крайнем левом положении и всё уже отрисовал)? там мы можем запороть противоположный край экрана или вторую половинку! прерывание должно быть умное и доставать запоротые данные из графики ld:push?
маскировка столбца - это просто ld (),a = 13t/line = 2600t * 4 layers
отрисовка столбца (из графики в ld:push) - это ld a,(de):inc d:ld (),a = 24t/line = 4800t * 4 layers (надо подключить графику в 0x8000..0xffff и рисовать оттуда 64 строки за раз)
само мясо вывода занимает 160*10.5*200 = 336000t
этот способ не может оптимизировать скорость отрисовки выкидыванием ld.
обвязка для расстояния между подстроками 128 байт (рисуем в 2 приёма - чётные и нечётные строки, то же с отрисовкой столбца для маскировки)
для рисования отдельно левой и правой половинок лучше такой вариант:
ld (hl),d;0xe9 ;jp (hl) ;
exx
ld l/hl,nnnext_i
ld sp,iy
jp (ix)
...
ld-push
jp (hl)
...
nnnext_i
inc hx
add iy,bc
exx
ld (hl),e;0x11 ;ld de ;
inc h
;73t/line * 2 halves * 4 layers = 116800t - слишком жирно!
если же экран реально зациклен внутри (как в The Board II), то надо иметь jp NNN в конце строки, то есть в 128 байтах будет зациклено не 512 пикс, а 124*4 = 496 пикс
нам-то достаточно 320 пикс, но... придётся не считать x mod scrbufwid, а при скролле независимо обновлять позицию сдвига в данных графики
ld (hl),d;0xe9 ;jp (hl) ;
exx
ld l/hl,nnnext_i
ld sp, ;надо две копии для рисования 0..39 или 1..40 столбцов (sp+1) *2 копии для +0/0x2000
jp (ix)
...
ld-push
jp N ;худший случай (2/3 позиций скролла, т.к. экранный буфер на 55% шире экрана)
...
ld-push
jp (hl)
...
nnnext_i
inc hx
exx
ld (hl),e;0x11/0xc3 ;ld de/jp NN
inc h
;73t/line * 4 layers = 58400t
порядок столбцов экрана:
layer0000
layer4000
layer2000
layer6000
UVSCROLL_WID=1024
UVSCROLL_SCRWID=320
UVSCROLL_NPUSHES=UVSCROLL_WID/2/4/2
UVSCROLL_SCRNPUSHES=UVSCROLL_SCRWID/2/4/2
xscroll = 0..511
если xscroll = 0, то:
layer0000 выводим столбцы 39..0, конец графики0
layer4000 выводим столбцы 39..0, конец графики1
layer2000 выводим столбцы 39..0, конец графики2
layer6000 выводим столбцы 39..0, конец графики3
если xscroll = 1, то:
layer0000 выводим столбцы 39..0, конец графики1
layer4000 выводим столбцы 39..0, конец графики2
layer2000 выводим столбцы 39..0, конец графики3
layer6000 выводим столбцы 40..1, конец графики0-4, столбец 0 подрисовка конец графики0-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;d
если xscroll = 2, то:
layer0000 выводим столбцы 39..0, конец графики2
layer4000 выводим столбцы 39..0, конец графики3
layer2000 выводим столбцы 40..1, конец графики0-4, столбец 0 подрисовка конец графики0-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;d
layer6000 выводим столбцы 40..1, конец графики1-4, столбец 0 подрисовка конец графики1-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;d
если xscroll = 3, то:
layer0000 выводим столбцы 39..0, конец графики3
layer4000 выводим столбцы 40..1, конец графики0-4, столбец 0 подрисовка конец графики0-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;d
layer2000 выводим столбцы 40..1, конец графики1-4, столбец 0 подрисовка конец графики1-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;d
layer6000 выводим столбцы 40..1, конец графики2-4, столбец 0 подрисовка конец графики2-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;d
если xscroll = 4, то:
layer0000 выводим столбцы 40..1, конец графики0-4, столбец 0 подрисовка конец графики0-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;d
layer4000 выводим столбцы 40..1, конец графики1-4, столбец 0 подрисовка конец графики1-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;d
layer2000 выводим столбцы 40..1, конец графики2-4, столбец 0 подрисовка конец графики2-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;d
layer6000 выводим столбцы 40..1, конец графики3-4, столбец 0 подрисовка конец графики3-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;d
если xscroll = 5, то:
layer0000 выводим столбцы 40..1, конец графики1-4, столбец 0 подрисовка конец графики1-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;d
layer4000 выводим столбцы 40..1, конец графики2-4, столбец 0 подрисовка конец графики2-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;d
layer2000 выводим столбцы 40..1, конец графики3-4, столбец 0 подрисовка конец графики3-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;d
layer6000 выводим столбцы 39..0, конец графики0-4
если xscroll = 6, то:
layer0000 выводим столбцы 40..1, конец графики2-4, столбец 0 подрисовка конец графики2-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;d
layer4000 выводим столбцы 40..1, конец графики3-4, столбец 0 подрисовка конец графики3-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;d
layer2000 выводим столбцы 39..0, конец графики0-4
layer6000 выводим столбцы 39..0, конец графики1-4
если xscroll = 7, то:
layer0000 выводим столбцы 40..1, конец графики3-4, столбец 0 подрисовка конец графики3-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;d
layer4000 выводим столбцы 39..0, конец графики0-4
layer2000 выводим столбцы 39..0, конец графики1-4
layer6000 выводим столбцы 39..0, конец графики2-4
если xscroll = 8, то:
layer0000 выводим столбцы 39..0, конец графики0-4
layer4000 выводим столбцы 39..0, конец графики1-4
layer2000 выводим столбцы 39..0, конец графики2-4
layer6000 выводим столбцы 39..0, конец графики3-4
признак нечётности (столбцы 40..1 + подрисовка):
для layer0000: (xscroll+0)&4
для layer4000: (xscroll+1)&4
для layer2000: (xscroll+2)&4
для layer6000: (xscroll+3)&4
адрес подрисовки для нечётных = адрес графики + (UVSCROLL_SCRNPUSHES*4) + 2 ;d
адрес графики:
для layer0000: конец - ((xscroll+4)/2&0xfc)
для layer4000: конец - ((xscroll+5)/2&0xfc)
для layer2000: конец - ((xscroll+6)/2&0xfc)
для layer6000: конец - ((xscroll+7)/2&0xfc)
;конец (крайнее правое положение L при вызове) = 256-(UVSCROLL_SCRNPUSHES*4)
адрес графики: конец - ((xscroll+4+layer)/2&0xfc)
адрес патча выхода = адрес графики + (UVSCROLL_SCRNPUSHES*4)
если рисуем снизу вверх, то нужна только одна подрисовка для нечётных
при меньшей ширине надо ещё затирание справа для нечётных, а обработчик прерывания должен сам уметь писать 0 в стек (достаточно обычного обработчика с de=0)
для нечётных что выгоднее - затирать лишний столбец, выведенный ld-push, или рисовать меньше в ld-push и отрисовывать это вручную?
затирать лишний столбец, выведенный ld-push = 21+13 = 34 t/line
рисовать меньше в ld-push и отрисовывать это вручную = 24 t/line выгоднее
общий выигрыш до 10(t/line)*4(layers)*200(lines) = 8000t
для равномерности делать нечётную ширину, чтобы везде подрисовка (либо слева, либо справа)?
как переходить по страницам?
[для вывода 200 строк (из них 100 подряд) надо пройти 2 или 3 страницы!
при этом должна быть подключена одна страница экрана и какая-то страница с im 1
сделать подряд только 50 строк, чтобы пройти не более 2 страниц кода?
0x0000 - im 1, вызывалка
0x4000 - страница экрана
0x8000,0xc000 - две страницы кода
то есть выводилка одного слоя экрана (а всего 4 слоя) должна содержать 4 вызова - чётные строки верх, низ, нечётные строки верх, низ
так можно зациклить экран по вертикали на N*128 пикселей]
а что если вызывалка лежит в отдельной странице с шагом 128 или 256 (каждая строка вызывалки связана со строкой графики по адресу +0x4000), так что сама может контролировать выход из страницы?
что если каждая строка графики при любом скролле (даже нулевом) проходит через jp N, а этот jp N (на последней строке) может перенастроить hl или ix для перехода на ветку с переключением страницы?
тогда можно сделать набор вызывалок через 256, привязанный к экрану (не привязанный к коду графики):
ld (hl),d;0xe9 ;jp (hl) ;
exx
ld sp, ;надо две копии для рисования 0..39 или 1..40 столбцов (sp+1) *2 копии для +0/0x2000
jp (ix)
...
ld-push
jp N ;при любой позиции скролла по X (при нулевой входим прямо в jp N) - т.е. ширина ldpush равна ширине экрана!!!
...
ld-push
jp (hl)
...
nnnext_i
inc hx
inc h
exx
ld (hl),e;0x11/0xc3 ;ld de/jp NN
inc h
;70t/line * 4 layers = 56000t
;-4t при отдельном патче и распатче
для удобства хранения лучше переходы хранить в следующем окне, чтобы не тратить место в каждой паге графики (так и переключить пагу проще), они же переходят сами на нужное место графики в новой паге
лучше менять ix, а hl пусть не меняется (вызывалка пусть всегда одинаковая)
0x0000: im1
0x4000: screen page
0x8000: gfx page
0xc000: в начале переходы на следующую gfx page, потом вызывалка
можно такой же метод и без скролла по X: последняя строка в странице (или первая строка после окончания страницы) состоит из jp на переключалку страниц и перехода в нужное место новой страницы (тогда патч-распатч надо отдельно!)
(но для гонки неудобно подрисовывать графику при скролле по 8 пикс за кадр, удобно иметь таблицу строк и их сдвигов. там вызывалка совсем другая!!!)
Для скролла незацикленной картинки 1024xHGT можно проще:
UVSCROLL_WID=1024
;0x0000: im1
;0x4000: screen page
;0x8000: gfx page
;0xc000: в начале переходы на следующую gfx page, потом вызывалка
;patch:
ld (hl),d;0x01 ;ld bc
inc h ;адрес следующего ldpush для патча
а) страница не от начала
б) страница целиком
в) страница не до конца
всё можно через одну процедуру, вызываемую с разных адресов:
UVscroll_unpatch
ld d,0x01 ;d=patch byte ld bc
jr UVscroll_patch_d
UVscroll_patch
ld a,4 ;layer 0..3 + 4
;a=layer 0..3 + 4
ld d,0xe9 ;d=patch byte jp (hl)
UVscroll_patch_d
ld hl,(xscroll) ;0..511 for 0..1022 pixels
add a,l
ld l,a
adc a,h
sub l
rra
ld a,l
rr l ;l=(xscroll+layer+4)/2
exx
;and 3 ;a=(xscroll+layer+4)&3
ld hl,(yscroll) ;0..511
add hl,hl
add hl,hl
add hl,hl
add hl,hl ;h=yscroll/16
xor h
and 3
xor h ;a=(xscroll+layer)&3 + ((yscroll/64)*4)
ld hl,tpushpgs
add a,l
ld l,a
adc a,h
sub l
ld h,a
exx ;hl'=список страниц графики =f((xscroll+layer)&3 + ((yscroll/64)*4))
ld a,(yscroll) ;0..511
and 63
add a,0x80
ld h,a
ld a,l
and 0xfc
add a,+(UVSCROLL_SCRNPUSHES*4)-1
ld l,a
inc hl
;jp UVscroll_patchpp
;конец (крайнее правое положение L при вызове) = 256-(UVSCROLL_SCRNPUSHES*4)
;адрес входа графики: конец - ((xscroll+layer+4)/2&0xfc)
UVscroll_patchpp
;d=patch byte
;h=0x80+(yscroll&63)
;l=f(xscroll+layer) ;L = адрес патча выхода = адрес входа графики + (UVSCROLL_SCRNPUSHES*4) (возможен переход на следующий сегмент H!!!)
;hl'=список страниц графики =f((xscroll+layer)&3 + ((yscroll/64)*4))
;ld e,UVSCROLL_SCRHGT
exx
ld a,(hl)
SETPG32KHIGH
exx
xor a
sub h
add a,a ;a=0..64*2
ld (UVscroll_patcher_patch0),a
ld a,UVSCROLL_SCRHGT
add a,h
ld e,a
UVscroll_patcher_patch0=$+1
call UVscroll_patcher
UVscroll_patcher0
exx
inc hl
ld a,(hl)
SETPG32KHIGH
exx
ld h,0xc0
ld a,e
add a,h
jr nc,UVscroll_patcher0q ;a=-64..-1
ld e,a
call UVscroll_patcher
jp UVscroll_patcher0
UVscroll_patcher0q
add a,a ;a=-128..-2
and 0x7f
ld (UVscroll_patcher_patch1),a
UVscroll_patcher_patch1=$+1
call UVscroll_patcher
ret
align 256
UVscroll_patcher
dup 63
ld (hl),d
inc h
edup
ld (hl),d
ret
;0xc103/43/83/c3:
;ld sp, ;надо две копии для рисования 0..39 или 1..40 столбцов (sp+1) *2 копии для +0/0x2000
;jp (ix)
;...
;ld-push ;всего их UVSCROLL_NPUSHES
;jp (hl) ;наш патч вместо ld de
...
;nnnext_i
;inc hx ;адрес следующего ldpush
;inc h ;адрес следующего nnnext_i
;56t/line * 4 layers
;в последней строке страницы вызывалки (0xffxx) вместо этого:
;nnnext_i
;ld sp, ;надо две копии для рисования 0..39 или 1..40 столбцов (sp+1) *2 копии для +0/0x2000 - копии можно разместить в тех же страницах, но с другими L адресами
;ld a,N
;SETPG32KHIGH
;inc hx ;адрес следующего ldpush
;inc h ;адрес следующего nnnext_i
;jp (ix)
;в последней строке экрана вместо всего этого:
;jp UVscroll_endofscreen
;...
;UVscroll_endofscreen
;ld sp,0
;ret
;после последней строки графики (0xc0xx) вместо ld-push (в любой странице вызывалки!):
;dup UVSCROLL_NPUSHES
;jp uvscroll_nextgfxpg
;nop
;edup
uvscroll_nextgfxpg
;sp=scr
exx
ld a,(hl) ;gfx pages
inc hl
SETPG32KLOW
exx
ld hx,0x80
jp (ix)
Можно на основе простого незацикленного скролла сделать зацикленный с подрисовкой с боков? типа мы имеем просто матрицу ld-push, текущее окно может пересекать границу сегментов
для этого надо зациклить блок ld-push по вертикали через uvscroll_nextgfxpg
----------------
было так:
видим 1:
- рисуем фон 0
- рисуем спрайты 0
- двигаем координаты
- меняем логический номер экрана
- логика (меняет координаты 1)
[ожидаем, что прошло прерывание с момента смены логического номера экрана]
видим 0:
- рисуем фон 1
- рисуем спрайты 1
- двигаем координаты
- меняем логический номер экрана
- логика (меняет координаты 0)
[ожидаем, что прошло прерывание с момента смены логического номера экрана]
Когда нет скролла, можно не перерисовывать фон
Допустим, будем восстанавливать фон под спрайтами с другого экрана
видим 1:
- восстанавливаем фон под спрайтами B или перерисовываем фон 0 (если сдвинулась камера по сравнению с прошлым 0)
- составляем список спрайтов A
- рисуем спрайты A на 0
- двигаем координаты
- меняем логический номер экрана
- логика (меняет координаты B)
[ожидаем, что прошло прерывание с момента смены логического номера экрана]
видим 0:
- восстанавливаем фон под спрайтами C на 1 или перерисовываем фон 1 (если сдвинулась камера по сравнению с прошлым 1)
- составляем список спрайтов B
- рисуем спрайты B на 1
- двигаем координаты
- меняем логический номер экрана
- логика (меняет координаты C)
[ожидаем, что прошло прерывание с момента смены логического номера экрана]
видим 1:
- восстанавливаем фон под спрайтами A или перерисовываем фон 0 (если сдвинулась камера по сравнению с прошлым 0)
- составляем список спрайтов C
- рисуем спрайты C на 0
- двигаем координаты
- меняем логический номер экрана
- логика (меняет координаты A)
[ожидаем, что прошло прерывание с момента смены логического номера экрана]