?login_element?

Subversion Repositories NedoOS

Rev

Rev 964 | Blame | Compare with Previous | Last modification | View Log | Download

сейчас на начальном выстреле от 2 врагов:
68000 перекладывание спрайтов (end_set_sprites())
372400 рисование фона (drawscroll())
214800 рисование спрайтов (swap_screen_scroll())

TODO:
повесить музыку на системное прерывание
переписать перекладывание спрайтов на асме
убрать параметр pal при выводе спрайта
клипирование
звуки
[для вертикального скролла push bc заменить на push de? или отчего мигает справа?]
можно сэкономить ещё страницы: 1) страницу sndpage загнать в главную, 2) музыку упаковать в одну страницу, которую совместить с последней страницей кода, 3) грузить страницу шрифта?

-исправлена буква y
-исправлены тексты
-исправлена форма круга врагов

В 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)

в результате оптимизации сделаны вычисления везде от allscroll = xscroll+(512*yscroll) (это число правильно зацикливается), а +4 убрано (allscroll=0 соответствует нижнему правому углу карты)



если рисуем снизу вверх, то нужна только одна подрисовка для нечётных
при меньшей ширине надо ещё затирание справа для нечётных, а обработчик прерывания должен сам уметь писать 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

если мы зациклены по горизонтали, то надо, чтобы ловушка после страницы переходила не на следующую строку, а на 0x8000

;256x64 tiles = 2048x512 pixels = мало!!! сразу пересчитывать из метатайлов?
;нужна текущая карта метатайлов (также для коллизий) 21x14
;её можно двигать прямо ldir, время пренебрежимо малое (для сравнения, карта тайлов 41x26 = 17056 тактов ldi, т.е. 5% от отрисовки)
;или пока обойдёмся тайлами?
;карта из метатайлов 2x2 тайла, разложена по страничкам? при размере 16x8 экранов это 16*20*8*12 = 30720 байт, лучше строчки по 2^N
;нас пока устроит 256x64 metatiles = 4096x1024 pixels = 16K

пусть у нас есть большая карта метатайлов
и маленькая карта тайлов (текущая видимая область), которая делается из большой карты

наша задача - правильно подкачивать и подрисовывать тайлы при скролле
подкачиваем при скролле на 16x по любой оси
подрисовываем при скролле на 8x по любой оси

для этого надо хранить:
allscroll - текущая позиция отображения (из неё можно достать абсолютно верный x&63, но нельзя достать верный y&15!)
y (настоящий и назависимый от allscroll) - без него не найти позицию в карте и y&15
x (настоящий и назависимый от allscroll) - без него не найти позицию в карте

можно обойтись без tilemap (подкачивать и сразу рисовать, максимум буфер на 1 столбец и 1 строку для подрисовки второй половины на следующем скролле)
но его можно использовать для физики (правда, враги не смогут вне экрана)
физику можно делать и по metatilemap (нереально в длинной гонке и в других процедурных картах)