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) ;exxld l/hl,nnnext_ild sp,iyjp (ix)...ld-pushjp (hl)...nnnext_iinc hxadd iy,bcexxld (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) ;exxld l/hl,nnnext_ild sp, ;надо две копии для рисования 0..39 или 1..40 столбцов (sp+1) *2 копии для +0/0x2000jp (ix)...ld-pushjp N ;худший случай (2/3 позиций скролла, т.к. экранный буфер на 55% шире экрана)...ld-pushjp (hl)...nnnext_iinc hxexxld (hl),e;0x11/0xc3 ;ld de/jp NNinc h;73t/line * 4 layers = 58400tпорядок столбцов экрана:layer0000layer4000layer2000layer6000UVSCROLL_WID=1024UVSCROLL_SCRWID=320UVSCROLL_NPUSHES=UVSCROLL_WID/2/4/2UVSCROLL_SCRNPUSHES=UVSCROLL_SCRWID/2/4/2xscroll = 0..511если xscroll = 0, то:layer0000 выводим столбцы 39..0, конец графики0layer4000 выводим столбцы 39..0, конец графики1layer2000 выводим столбцы 39..0, конец графики2layer6000 выводим столбцы 39..0, конец графики3если xscroll = 1, то:layer0000 выводим столбцы 39..0, конец графики1layer4000 выводим столбцы 39..0, конец графики2layer2000 выводим столбцы 39..0, конец графики3layer6000 выводим столбцы 40..1, конец графики0-4, столбец 0 подрисовка конец графики0-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;dесли xscroll = 2, то:layer0000 выводим столбцы 39..0, конец графики2layer4000 выводим столбцы 39..0, конец графики3layer2000 выводим столбцы 40..1, конец графики0-4, столбец 0 подрисовка конец графики0-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;dlayer6000 выводим столбцы 40..1, конец графики1-4, столбец 0 подрисовка конец графики1-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;dесли xscroll = 3, то:layer0000 выводим столбцы 39..0, конец графики3layer4000 выводим столбцы 40..1, конец графики0-4, столбец 0 подрисовка конец графики0-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;dlayer2000 выводим столбцы 40..1, конец графики1-4, столбец 0 подрисовка конец графики1-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;dlayer6000 выводим столбцы 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 ;dlayer4000 выводим столбцы 40..1, конец графики1-4, столбец 0 подрисовка конец графики1-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;dlayer2000 выводим столбцы 40..1, конец графики2-4, столбец 0 подрисовка конец графики2-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;dlayer6000 выводим столбцы 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 ;dlayer4000 выводим столбцы 40..1, конец графики2-4, столбец 0 подрисовка конец графики2-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;dlayer2000 выводим столбцы 40..1, конец графики3-4, столбец 0 подрисовка конец графики3-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;dlayer6000 выводим столбцы 39..0, конец графики0-4если xscroll = 6, то:layer0000 выводим столбцы 40..1, конец графики2-4, столбец 0 подрисовка конец графики2-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;dlayer4000 выводим столбцы 40..1, конец графики3-4, столбец 0 подрисовка конец графики3-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;dlayer2000 выводим столбцы 39..0, конец графики0-4layer6000 выводим столбцы 39..0, конец графики1-4если xscroll = 7, то:layer0000 выводим столбцы 40..1, конец графики3-4, столбец 0 подрисовка конец графики3-4 + (UVSCROLL_SCRNPUSHES*4) + 2 ;dlayer4000 выводим столбцы 39..0, конец графики0-4layer2000 выводим столбцы 39..0, конец графики1-4layer6000 выводим столбцы 39..0, конец графики2-4если xscroll = 8, то:layer0000 выводим столбцы 39..0, конец графики0-4layer4000 выводим столбцы 39..0, конец графики1-4layer2000 выводим столбцы 39..0, конец графики2-4layer6000 выводим столбцы 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) ;exxld sp, ;надо две копии для рисования 0..39 или 1..40 столбцов (sp+1) *2 копии для +0/0x2000jp (ix)...ld-pushjp N ;при любой позиции скролла по X (при нулевой входим прямо в jp N) - т.е. ширина ldpush равна ширине экрана!!!...ld-pushjp (hl)...nnnext_iinc hxinc hexxld (hl),e;0x11/0xc3 ;ld de/jp NNinc h;70t/line * 4 layers = 56000t;-4t при отдельном патче и распатчедля удобства хранения лучше переходы хранить в следующем окне, чтобы не тратить место в каждой паге графики (так и переключить пагу проще), они же переходят сами на нужное место графики в новой пагелучше менять ix, а hl пусть не меняется (вызывалка пусть всегда одинаковая)0x0000: im10x4000: screen page0x8000: gfx page0xc000: в начале переходы на следующую 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 bcinc h ;адрес следующего ldpush для патчаа) страница не от началаб) страница целикомв) страница не до концавсё можно через одну процедуру, вызываемую с разных адресов:UVscroll_unpatchld d,0x01 ;d=patch byte ld bcjr UVscroll_patch_dUVscroll_patchld a,4 ;layer 0..3 + 4;a=layer 0..3 + 4ld d,0xe9 ;d=patch byte jp (hl)UVscroll_patch_dld hl,(xscroll) ;0..511 for 0..1022 pixelsadd a,lld l,aadc a,hsub lrrald a,lrr l ;l=(xscroll+layer+4)/2exx;and 3 ;a=(xscroll+layer+4)&3ld hl,(yscroll) ;0..511add hl,hladd hl,hladd hl,hladd hl,hl ;h=yscroll/16xor hand 3xor h ;a=(xscroll+layer)&3 + ((yscroll/64)*4)ld hl,tpushpgsadd a,lld l,aadc a,hsub lld h,aexx ;hl'=список страниц графики =f((xscroll+layer)&3 + ((yscroll/64)*4))ld a,(yscroll) ;0..511and 63add a,0x80ld h,ald a,land 0xfcadd a,+(UVSCROLL_SCRNPUSHES*4)-1ld l,ainc 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_SCRHGTexxld a,(hl)SETPG32KHIGHexxxor asub hadd a,a ;a=0..64*2ld (UVscroll_patcher_patch0),ald a,UVSCROLL_SCRHGTadd a,hld e,aUVscroll_patcher_patch0=$+1call UVscroll_patcherUVscroll_patcher0exxinc hlld a,(hl)SETPG32KHIGHexxld h,0xc0ld a,eadd a,hjr nc,UVscroll_patcher0q ;a=-64..-1ld e,acall UVscroll_patcherjp UVscroll_patcher0UVscroll_patcher0qadd a,a ;a=-128..-2and 0x7fld (UVscroll_patcher_patch1),aUVscroll_patcher_patch1=$+1call UVscroll_patcherretalign 256UVscroll_patcherdup 63ld (hl),dinc hedupld (hl),dret;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;edupuvscroll_nextgfxpg;sp=screxxld a,(hl) ;gfx pagesinc hlSETPG32KLOWexxld hx,0x80jp (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&15x (настоящий и назависимый от allscroll) - без него не найти позицию в картеможно обойтись без tilemap (подкачивать и сразу рисовать, максимум буфер на 1 столбец и 1 строку для подрисовки второй половины на следующем скролле)но его можно использовать для физики (правда, враги не смогут вне экрана)физику можно делать и по metatilemap (нереально в длинной гонке и в других процедурных картах)