Обновить

Частично переписал рейкаст по Брезенхему-Доку (нет, ну правда, «колесо пред-рассчитанных лучей» от @Swamp_Dokдало прямо роскошный буст к скорости) под чистые 8 бит старого доброго 6502-го.

Всё, как и обещал в камменте: 16 бит в первом приближении как бы не быстрее 8 бит, потому что выковыривать нибблы из байта на процессоре, который даже сместить на 4 бита одной командой не может (надо использовать 4 сдвига на 1 бит) — такое себе, а в этих 16 битах старший и младший байты живут в основном самостоятельными жизнями, довольно редко взаимодействуя в переносе (что ещё больше углубляет мой восторг от гениальности алгоритма «Брезентыча», если это вообще возможно). Я уже мысленно собрал уровни из тех замечательных крошек-чанков 16х16 клеточек и даже продумал, как бы нам хранить в одном байте 4 клетки, чтобы пореже из памяти тянуть (итого 2 бита на клетку — пустота, стенка, первый моб и второй моб из двух возможных на один чанк), да и даже как именно нам связывать такие чанки, как анимировать переходы и т. д, но, судя по всему — не пригодится. Не похоже, чтобы было где хранить данные для повторного использования, не похоже, чтобы можно было быстро вытащить нужные биты.

Разберу сейчас подробно один из 8 вариантов ветвления (раньше было два — шаг по X, смещение по Y и наоборот, а сейчас добавились ещё и варианты для разных знаков шага и смещения, ибо индивидуальная обработка каждого случая позволяет ещё кучу тактов сэкономить). Самый простой вариант — первый, X и все в плюс.

Дам этот кейс скрином, ибо.
Дам этот кейс скрином, ибо.

Координаты игрока мы храним нормальными 16-битными, 8 бит на номер клетки и 8 бит на координаты в ней. Работать с ними мы будем один раз — в рамках физики. Для рейкаста они нужны отдельно в виде старшего байта, отдельно в виде младшего. Три из них мы видим в трёх верхних строчках, где они копируются в координаты луча. Четвёртая — чуть ниже, где BrezToStart вычисляется «по-старинке», там я ещё не изжил пекашный код. Зато смещение мы берём (четвёртая строчка) уже из «колеса», расчётов — ноль!

Дальше мы видим, что предыдущее значение координаты смещения стало 8-битным. Дело в том, что нам не нужно значение клетки — мы его и так знаем. А вот пиксельное значение — запомнили.

Дальше мы делаем 8-битное сложение. Первая величина — младший байт координаты смещения POS PIX, вторая — (long)BrezToStart*(long)RayDY/RayDX. Её я тоже пока вычисляю явно — но она, несомненно, напрашивается на табличное представление. В результате имеем новый POS PIX и флаг переноса.

Тут, как я уже намекал, мы можем не проверять память, если не было переноса. Ну, и полного 16-битного суммирования не делаем, максимум — инкремент (в отличие от компилятора, мы знаем, какие бывают суммы, а какие — нет).

Проверка памяти требует вычислить довольно длинный адрес. Тут я хочу пойти на грязный хак: возможно, сделать карту [32][256], чтобы ничего не умножать на 64, и старший байт писать прямо в код, в тело инструкции LDA. Кармак в Wolf3D, помнится, раздухарился ещё жёстче… да, хранение переменной прямо в коде, да ещё в 4 разных местах — тоже потребует копирования её туда-сюда. Но после входа в «основной цикл шагания» обратно мы уже не возвращаемся — возможно, я придумаю способ держать её и в коде, и в одном экземпляре. Это позволит проверять карту простым LDA $DEAD, X (где X — вторая координата, которая до 256, а вместо $DEAD мы подкидываем нашу переменную, в case 0 это будет POS CELL, которая меняется от адреса карты до него же плюс 32<<8). Хотя, возможно, через Indirect я это сделаю ещё быстрее! Не попробуешь — не узнаешь, собственно, почему я и «подсел» на эту задачу. Никакие Factorio рядом не валялись :)

Функция AddToZBuffer8Bit тоже демонстративно отрицает 16-битное суммирование — фишка в том, что переносов там не возникает! Поэтому все аргументы вычисляются через 8-битные суммы.

Ну, и косые стенки я убрал, а смещение всей сцены на доли тайла — вернул. Надо какой-то шлем там нарисовать, который «не успевает за мышкой» :) Тогда можно рефрешить рендер «через кадр», пусть дёргается вместе со статусбаром — типа фича :)

Теги:
Всего голосов 4: ↑4 и ↓0+6
Комментарии16

«Яндекс Go» предложит пассажирам ждать такси 30–40 минут ради скидки

Пассажиры «Яндекс Go» смогут сэкономить на поездке в часы, когда такси заказывают особенно много людей. В такие моменты сервис предложит опцию «Позже»: машина приедет не сразу, зато поездка будет стоить меньше. Скидку даст «Яндекс Go» за свой счёт, она не уменьшит доход водителей.

«Яндекс Go» предложит пассажирам ждать такси 30–40 минут ради скидки

Публикации