Войти
ФлеймФорумЖелезо

Блеск и нищета 8/16-битных консолей и ПК (59 стр)

Страницы: 158 59 60 6182 Следующая »
#870
(Правка: 10:24) 10:22, 30 янв. 2020

P.S.
Я вообще смотрел тут обзор тулзов: http://hype.retroscene.org/blog/282.html
И в принципе Nesicide хорош для быстрого старта, но ввиду вышеописанных глюков я переползу таки на прямое использование ca65 (ассемблер) из пакета cc65 (си), там в целом всё уже стало понятно примерно.
И самая мякотка Nesicide - встроенный отладчик, судя по всему не такой уж и безальтернативный вариант, ибо вот здесь: https://github.com/bbbradsmith/NES-ca65-example в проект вложен скрипт на питоне генерирующий отладочную информацию для FCEUX, что в принципе уже хлеб похоже что.


#871
10:31, 30 янв. 2020

=A=L=X=
> Что-то совсем уж старое,

nesasm c гитхаба посвежее

#872
12:26, 30 янв. 2020

Ааа, на обеде еще раз запустил и понял что Nesicide не нравилось когда проект состоит из нескольких исходников.
На самом деле подглючивает его в момент когда ты дебагом идёшь по программе шагами по F8 и доходишь до макроса определение которого находится в другом файле.
Вот тут его переглючивает и он по нескольку раз открывает окно этого файла с поломанным форматированием и на каждый шаг еще по два открывает снова и снова при этом точки выполнения всё-равно не видно и в общем это выбивает из колеи.
Но если не пытаться отлаживать пошагово макрос или он находится в текущем модуле компиляции - всё нормально работает без нареканий.

И это опять возвращает Nesicide в список приоритетов. Насколько я понял отладка прямо в IDE по настоящему коду который тут же пишешь - это просто полное отсутствие конкуренции. У отладки через FCEUX всё-таки только метки будет видно в ассемблерном листинге, а код программы со всеми константными идентификаторами и т.п. станет невидно.
Так что надо только придумать как жить без русских комментариев... Хм...

#873
(Правка: 12:28) 12:28, 30 янв. 2020

=A=L=X=
> Так что надо только придумать как жить без русских комментариев... Хм...

;eto o4en prosto

#874
(Правка: 3 фев. 2020, 4:47) 12:36, 30 янв. 2020

0iStalker
> ;eto o4en prosto

Вообще не парило бы, если бы я уже сейчас не задумывал это как серию уроков наподобие GBA-шной. А там вся суть была обильно обмазанном комментарии коде.
...
Понятно кажется всё. Заглянул на гитхабе в исходники - Nesicide использует в качестве редактора компоненту QsciScintilla и нигде не вызывает у неё setUtf8( true).
А как гласит документация:

Sets the current text encoding. If cp is true then UTF8 is used, otherwise Latin1 is used.

Мде. Неужели никто во всём мире на такое не обратил внимания?

P.S.
А, логично, Latin-1 это же когда европейские всякие закорючки над буквами есть во второй половине 8-битной кодировки, поэтому охват у него изначально получился широчайший.
Ладно, отправил как issue, посмотрим на волшебную силу опенсорца в действии...

P.P.S.
Таки да, сообщил куда следует и автор пообещал, что пофиксит к следующему релизу.

+ Показать

#875
(Правка: 6:38) 6:36, 3 фев. 2020

Невероятные приключения скроллинга на Famicom/NES/Денди

Как игровая консоль денди конечно же должна была поддерживать аппаратный скроллинг и делала это.
Но с этим связано несколько подводных камней которые мне показались достаточно забавными чтобы написать о них тут.
Видеочип консоли обладал собственным изолированным от основного процессора пространством памяти (VRAM) в котором нас сейчас интересуют две вещи:
а) первые 8Кб VRAM (от $0000 до $1FFF) содержали 512 изображений тайлов размером 8x8 пикселей цветностью 4 цвета (2 бита) на пиксель. Одна половина этих тайлов обычно служила источником изображения для плиток фона, а другая - для подвижных спрайтов. В играх первого поколения (Galaxian, Pacman, Bomberman и т.п.) эти 8Кб обычно маппились прямо на микросхему ПЗУ в картридже (это - Pacman):
Изображение
Здесь она справа.
б) а с адреса $2000 располагались в VRAM четыре экранных области плиток фона (nametables) каждой из которых хватало чтобы полностью замостить один экран изображения неким фоном.
Это 256x240 пикселей изображения или 32x30 плиток тайлов, но надо учитывать, что не все пиксели по вертикали попадали на экран телевизора (особенно в системе телевидения NTSC).
Геометрически эти четыре области/страницы были пристыкованы друг к другу следующим образом:

     (0,0)     (256,0)     (511,0)
       +-----------+-----------+
       |           |           |
       |           |           |
       |   $2000   |   $2400   |
       |           |           |
       |           |           |
(0,240)+-----------+-----------+(511,240)
       |           |           |
       |           |           |
       |   $2800   |   $2C00   |
       |           |           |
       |           |           |
       +-----------+-----------+
     (0,479)   (256,479)   (511,479)
Если задействовать аппаратный скроллинг, то камера как бы летает над этим полем тайлов бесшовно "прокручиваясь" через края, что позволяет реализовать бесконечный скроллинг. Есть только большое "но" - конкретно в денди для экономии нижние две таблицы были выпилены и по сути в силу игнорирования адресной линии просто маппились на верхние (зеркалировались), при этом перестановкой линий адреса с картриджа можно было управлять между вертикальным и горизонтальным зеркалированием - для вертикальных и горизонтальных скроллеров удобны были разные режимы.
Сами эти страницы были устроены достаточно просто: сперва в них располагалась область из 32x30 (960) байт где каждый байт выбирал одно из изображений тайлов вышеописанных тайловых данных, а последние 64 байта страницы содержали биты выбора одной из четырёх палитр для каждого блока 2x2 тайла страницы. В один байт было запаковано четыре таких селектора палитр, поэтому каждый байт хранил цветовые атрибуты блока 4x4 тайла или 32x32 пикселя. Поэтому в том же супермарио размер макроблоков был как раз 4x4 тайла - это просто удобно.
Итак мы подходим к главному - эти два килобайта содержимого видеостраниц фона в денди должен был обновлять процессор.
Но прямого доступа к ним он не имел, поэтому всё взаимодействие с ними осуществлялось через порты ввода-вывода, а конкретно PPUADDR (ячейка памяти $2006 в адресном пространстве процессора) и PPUDATA ($2007).
Процессор записывает в PPUADDR подряд два байта адреса в VRAM (причём сперва старший, а потом младший), а потом записывает в PPUDATA байты которые попадут в VRAM или читает из PPUDATA байты из неё. Правда чтение осуществляется с задержкой в одно чтение из-за промежуточного регистра-буфера, но запись идёт сразу. Для скорости адрес в PPUADDR автоматически увеличивается на 1 или 32 в зависимости от бита 2 (нумерация с нуля) в управляющем регистре PPUCTRL ($2000).
Так и только так обновляются плитки фона в денди и есть одно важное ограничение: делать это можно только когда видеочип не рисует картинку, а отдыхает в коротком промежутке времени между построениями кадра - так называемый период VBlank.

Вернёмся к скроллингу - штатным способом скроллить изображение в денди является порт ввода-вывода PPUSCROLL ($2005) и два нижних бита в уже упомянутом управляющем регистре PPUCTRL ($2000). В некоторых руководствах часто пишут, что нижние 2 бита PPUCTRL как бы выбирают какая из четырёх видеостраниц с рисунка выше является "базовой", от которой скроллинг отталкивается, а две подряд идущих записи в PPUSCROLL выставляют сперва значение горизонтального скроллинга (0-255) в этой области, а потом вертикального (0-239). Под значением скроллинга понимается координата пикселя который будет левым-верхних на экране.
Но мне нравится другая трактовка - что в двух нижних битах PPUCTRL как бы находятся самые значащие верхние биты "координат прокрутки" от 0 до 512 в едином четверном пространстве видеопамяти (но для вертикальных надо иметь ввиду пропуск в середине где заканчиваются 30 вертикальных строк тайлов первых видеостраниц).
Всё кажется просто и логично? Но сейчас пойдут мелочи в которых кроется дьявол.

Первое что должно нас насторожить - это то, что запись в PPUSCROLL разрушает содержимое регистра PPUADDR и по официальной документации выставление скроллинга должно быть последним действием после всех записей в VRAM.
Второе - это когда мы захотим поменять значение скроллинга прямо в середине построения кадра - это может быть полезно для реализации сплит-скрина или HBlank-отсечения, о котором уже есть статья. Тут выясняется, что запись в PPUSCROLL даже во время HBlank может изменить только величину горизонтального скроллинга, но вертикальный может сменится только в конце VBlank когда видеочип приступает к отрисовке нового кадра.
Например так можно сделать скроллинг в игре Bomberman где содержимое видеостраниц в VRAM выглядит вот так:
Изображение
А на экране телевизора после скроллинга и наложения спрайтов уже вот так:
Изображение
Здесь как раз горизонтальный разрыв в принципе может быть сделан через запись в PPUSCROLL. Но в огромном количестве игр эксплуатирующих HBlank-отсечение нужно еще уметь менять вертикальную прокрутку и вот чтобы понять как это сделать и что тут вообще происходит нужно опустится в глубины того чада и угара как прокрутка реализована в кишках денди.

#876
(Правка: 6:55) 6:36, 3 фев. 2020

(продолжение...)

А в кишках денди можно выделить четыре интересующих нас регистра (согласно статье по предыдущей ссылке):
v - 15 бит текущего адреса VRAM (PPUADDR)
t - 15 бит временного адреса VRAM
w - 1 бит признака второй записи
x - 3 бита попиксельного скроллинга по горизонтали внутри тайла

Шина адреса VRAM 14-битная, но v и t имеют размер в 15 бит по причинам описанным ниже, в любом случае эффективны из них только 14 нижних бит. Когда я буду говорить про "верхний байт" регистров v или t я на самом деле буду иметь 7 верхних бит.
При записи байта в PPUADDR сперва анализируется бит w - если он равен 0 (первая запись), то байт записывается в верхний байт t с занулением верхнего бита (т.е. из записанного байта попадают в регистр нижние 6 бит) и бит w выставляется в 1. А если при записи w=1, то запись производится в нижний байт t и сразу после этого t копируется в v.
Таким образом запись в PPUADDR довольно прямолинейно выставляет адрес в t и v с занулением верхнего (неэффективного) бита №15, которое, как говорится в статье, непонятно зачем сделано и только вставит нам палку в колёса ниже.

Запись в PPUSCROLL под капотом пишет в те же самые регистры v и t, но делает это более изощрённо и так же затрагивает регистр x.
Но чтобы перейти к объяснению надо еще вспомнить про нижние биты в управляющем регистре PPUCTRL которые управляли в какой из четырёх видеостраниц располагается базис текущего экрана.
Когда мы пишем в PPUCTRL кроме всего остального нижние два его бита записываются в биты t следующим образом:
t: ---XY-- --------  ; биты обозначенные как - не меняются
При первой записи (опять таки она определяется по общему флагу w и я больше про него упоминать не буду) байта (прокрутки по X) в PPUSCROLL его биты (пронумеруем их как '76543210') попадают в t так:
t: ------- ---76543 ; т.е. биты с 7 по 3 попадают в нижние биты t
x: 210 ; и при этом нижние 3 бита откладываются в регистре x
Опять таки биты помеченные как - не меняются.
И вот при второй записи в PPUSCROLL байта прокрутки по Y его биты попадают в t уже так:
t: 210--76 543-----
И больше ничего не происходит - регистр v не вообще трогается. Такая замысловатая разброска бит на самом деле просто выставляет в t адрес того байта с которого надо начать рисовать плитки фона в VRAM и кроме того откладывает горизонтальные и вертикальные смещения внутри одного знакоместа/тайла в регистр x и в верхние 3 бита регистра t. Тут надо сразу заметить, что верхние 3 бита регистра v действительно будут использоваться как вертикальное смещение внутри тайла и при чтении из VRAM участвовать в адресе не будут.

Но за всем этим пока еще не видно собственно скроллинга. А происходит он вот как:
1. в конце VBlank перед тем как начать рисовать новый кадр PPU копирует биты ответственные за координату Y из t в v, а конкретно эти биты: XXXX-XX XXX----- (опять же минусы - значит не копируются)
2. по мере отрисовки сканлайна PPU читает из VRAM по адресу v инкрементируя адрес вдоль координаты x (с прокруткой через страницы и пропуском атрибутных зон)
3. когда отрисовка текущего сканлайна завершается PPU нужно восстановить в v изначальное положение по X и перейти к следующей строке.
для этого сперва из t копируется часть бит ответственных за координату X, а именно: ----X-- ---XXXXX
тут надо понимать, что существует один сканлайн выполняющий это до первой эффективной строки пикселей - в нём делается много других важных предустановок, но в т.ч. и эта и таким образом вместе с пунктом (1) в v оказывается полная копия t перед тем как изображение начинается рисоваться
4. переходя от сканлайна к сканлайну PPU увеличивает в v адресную часть ответственную за координату Y

Так вот что тут происходит - мы действительно не можем через PPUSCROLL поменять вертикальную прокрутку в середине кадра, т.к. её биты попадают из t в v только в конце VBlank перед тем как изображение начинает рисоваться. При этом в t как бы и образуется правильный адрес, но на v он может повлиять только битами ответственными за X.
При этом заметьте, что если мы попытается просто выставить сразу нужный адрес через запись напрямую в PPUADDR, то из-за того, что глупая железка зачем то обнуляет верхний бит адреса, то может оказаться поломанным пиксельное смещение по Y внутри знакоместа/тайла.
Какой то прям замкнутый круг?
Однако инженерная мысль обошла эти подводные камни мутных вод программирования 8-битной консоли с лёгкостью и изяществом достойным упоминания тут.
Достаточно сделать четыре записи в PPUSCROLL и PPUADDR в "неправильном" порядке - сперва одна запись в PPUADDR, потом две записи в PPUSCROLL и потом последняя опять в PPUADDR.
Почему это работает: во первых т.к. бит второй записи w общий на все операции, то записи и не обязаны быть попарными, но все действия будут легко предсказуемыми.
В результате сложилась следующая схема (всё взято из статьи):
1. в PPUADDR пишем номер страницы помноженный на 4 (т.е. одно из значений: 0, 4, 8 или 12)
2. в PPUSCROLL пишем байт прокрутки внутри страницы по Y
3. в PPUSCROLL пишем байт прокрутки внутри страницы по X
4. в PPUADDR пишем нижний байт адреса который вычисляется как ((Y & $F8) << 2) | (X >> 3)
Размотать при этом какие биты куда попадают кто захочет может уже самостоятельно, но главное что при такой последовательности и насильно зануляемый бит оказывается переписан правильным значением и регистр v получит в себя копию из t не только бит ответственных за координату X, но и Y.

#877
11:44, 4 фев. 2020

И это тоже ZX Spectrum, 16 цветов, 2 на знакоместо. Я в шоке

Запустить видео по клику - Как делать игрыЗапустить видео по клику - Как делать игры
#878
12:13, 4 фев. 2020

0iStalker
> И это тоже ZX Spectrum, 16 цветов, 2 на знакоместо
А как это работает? Во время обратного хода луча меняют атрибуты знакоместа?

#879
12:18, 4 фев. 2020

Статья с разбором техник демосцены NES - https://shiru.untergrund.net/articles/nes_high_hopes.htm

#880
12:35, 4 фев. 2020

0iStalker
> Статья с разбором техник демосцены NES -
> https://shiru.untergrund.net/articles/nes_high_hopes.htm

lda #$00 ;два регистра устанавливаются в 0, потому что горизонтальное смещение в этом эффекте не меняется
sta $2006
stx $2005
sta $2005 ;эту и следующую запись нужно выполнить во время HBlank
sty $2006
Как раз та самая "неправильная" попарно запись в PPUSCROLL ($2005) и PPUADDR ($2006) про которые я выше писал. :)
#881
(Правка: 12:48) 12:48, 4 фев. 2020

0iStalker
> https://shiru...

Кстати, когда вот взялся за Famicom/NES/Денди в плане и самому попробовать и руководство для начинающих настрочить, то начал всё больше сталкиваться с тем глубоким следом который Shiru оставил в программистской ретротусовке.
Так, например, на хабре есть цикл статей про программирование на cc65 (Си и тулчейн для широкого спектра машин на базе MOS 6502 и его наследников) на NES: https://habr.com/ru/post/348022/
Это прям нечто того что я хочу чтобы у меня получилось, но для ассемблера входящего в состав cc65 - ca65 и в среде Nesicide.
Так вот это на самом деле перевод англоязычных статей от Nesdoug: https://nesdoug.com/
Который в первых же вариантах статьи от 2018 года (которые и переведены) сразу же пишет: https://nesdoug.files.wordpress.com/2018/07/introduction-e28093-nesdoug.pdf

As far asI know, there are no other tutorials for cc65 (not counting the example games over at Shiru’s site.)

:)

#882
6:53, 10 фев. 2020

=A=L=X=
> shiru

Лол, тот чувак что пилит среду Nesicide сейчас участвует в джеме (игра за 2 дня): https://globalgamejam.org/2020/games/super-city-mayor-3
И чтобы вы думали?

Credits:
Music by Shiru from the Famitone library.

:)

#883
(Правка: 8:25) 8:25, 11 фев. 2020

Хехе, Shiru ответил мой комментарий об этом: http://hype.retroscene.org/blog/967.html#comment25049

Лет десять назад я сделал три вещи, которые оказались весьма востребованными в тот момент, и с помощью которых с тех пор была создана добрая половина homebrew для NES:

— Конвертер-редактор графики и экранов, а впоследствии также и составных спрайтов — NES Screen Tool, с довольно корявым, но вполне человеческим лицом. До этого были только редакторы тайлов типа Tile Layer Pro и YY-CHR, а также дикие утилиты под DOS, что очень затрудняло подготовку графики для игр. Альтернативы ему не появилось до сих пор (а надо).

— Библиотеку FamiTone, которая позволила легко и просто добавлять музыку и (решающий фактор) звуковые эффекты в игры, делая их в человеческом FamiTracker. В этом также большая заслуга jsr, Gradualore и rainwarrior, которые добавили и развили поддержку кастомных экспортёров из FamiTracker. До этого не было готового плеера, который можно было просто взять и вставить — все либо изобретали велосипед, обязательно включающий написание музыки в hex-кодах, либо приватно делились кодом. К тому же, в тот момент предпочтения в комьюнити касательно кросс-ассемблеров делились на три равные части, NESASM/asm6/CA65, код между которыми переносить довольно затруднительно, а я поддержал все три сразу. С тех пор появилось несколько альтернатив (в том числе форков моего кода), FamiTone ещё в лидерах, но его начинает теснить решение от Gradualore, которое встроили в NES Maker.

— Библиотеку neslib, которая позволила легко и просто писать на C. Ранее на сцене ходили настроения, что ничего путного сделать на C невозможно, не стоит даже и пытаться — никто и не пытался. А я видел, что делают Mojon Twins с компилятором C на ZX (как известно, ныне чурерра заполонила), и показал, что так можно было. Также я привлёк самих Mojon'ов, чтобы они показали класс (Sir Ababol и другие игры). Это в свою очередь сподвигло nesdoug'а не только самому начать писать на C, но и сделать серию туториалов, которые потом перевели на русский.

Соответственно, теперь куда не клюнь — ваш пострел везде поспел.


:)
Еще одна хохма - когда я перетаскивал на тот ресурс свои статьи отсюда из цикла "блеск и нищета", то в одном из обсуждений с Shiru написал ему что натыкался на офигенную статью про то какие проблемы и решения были на Денди с отображением больших титульных экранов - из-за того что есть конкретные ограничения на то сколько тайлов одновременно может быть видно на экране, то там с этим проблемы.
Оказалось в итоге что автор этой статьи - это Shiru. :D

#884
(Правка: 9:46) 9:41, 26 фев. 2020

После статьи про то как непросто в Famicom/NES/Денди было сменить параметры вертикальной прокрутки в середине кадра я только сегодня догадался посмотреть на старые знакомые игры в этом разрезе.
А кто из них это делал?
Опять таки надо иметь ввиду, что смена вертикальной прокрутки в середине кадра нужна была преимущественно для реализации панели статуса - "прилепленной" к верхнему или нижнему краю экрана области со статистикой, очками, жизнями и прочей игровой информацией. Как из статьи выше понятно сделать это по вертикали было довольно проблематично, поэтому игры где скроллинг был не только по горизонтали но и по вертикали должны были применять описанную сложную технику.

Для начала возьмём пример который точно её не применял и где скроллинг был только по горизонтали:
Изображение

Верхние 3 строки на синем фоне с надписями сразу под которыми идут облака - это как раз "намертво приклееный" сменой параметров прокрутки кусок заднего фона который по технике zero-sprite-hit меняет горизонтальный скроллинг. Облака не могут находится выше чем они есть (хотя спрайты могут, в т.ч. сам марио). Интересно, что сам этот нулевой спрайт находится там где монетка - нижняя полоска пикселей в ней это zero sprite и он срабатывает и далее по тактам рассчитанный код подменяет параметры горизонтального скроллинга там где есть такая возможность в HBlank, т.к. эта законная техника. А вот с вертикалью такое не сработает.
Посмотрим на другие известные игры:
Изображение

Чёрный плащ выкручивался довольно легко:
Изображение

Информация о жизнях ГГ и текущем выбранном оружии выводилась несколькими спрайтами которые висят над задним фоном. И всё. Такой игре достаточно 1 раз на кадр выставлять параметры прокрутки и забывать о них до следующего кадра.
Но позвольте, этот же движок, если память мне не изменяет есть суть эволюция движка студии Capcom и на нём базированы такие шедевры как Megaman, Duck Tales, Русалочка, Chip & Dale...
Неужели?...
И правда:
Изображение
Изображение
Изображение
Аха! Ребята явно не захотели сталкиваться со скроллингом и статус-барами одновременно.
Выбивается из этих только Duck Tales:
Изображение

Хм, заинетресовавшись я залез в FCEUX и посмотрел что творится в моменты вертикального скроллинга в видеопамяти - и таки да, они сильно упростили себе задачу.
Статус бар приклеен к первой экранной области, а экраны где происходит скроллинг вверх-вниз всегда выпадают на вторую экранную область. Явно они тут себе подсахарили проблемные места, но, очевидно, до техники всё-таки доросли, хотя и бесшовным этот скроллинг у них не является - вертикальный переход всегда осуществляется как спец-эффект (как и в ЧП) замедляя темп игры, т.к. им приходится проводить массивное обновление VRAM и оно разбросано на несколько кадров чтобы пролезть в VBlank.

В общем далеко не каждая из даже известных игр рисковала сталкиваться одновременно со статус-баром и вертикальным скроллингом! :)
P.S.
Умилительно... Сегодня девелоперы изобретают всякий RTX и как в шейдеры побольше вычислений запихать, а какие то десятки лет назад боролись со статус-барами и скроллингом. xD

Страницы: 158 59 60 6182 Следующая »
ФлеймФорумЖелезо