А как же: http://vtrdos.ru/system.php#s28
или нужен на пц?
Вид для печати
А как же: http://vtrdos.ru/system.php#s28
или нужен на пц?
deleted
drbars, это не моя процедура :-) Это из книжки "Как написать игру на ассемблере".
По поводу хранения спрайта строками. Фактически переход к следующему байту строки это INC L (INC E), а к следующему байту столбца - INC H (INC D). Равнозначно. От постолбцового вывода выигрыш на спрайтах маленького размера, < 8. На практике таких спрайтов большинство. И наоборот - для вывода больших спрайтов-пейзажей обычно не требуется особая скорость (если требуется - применяются совсем другие методы). Потому что по столбцам во внутреннем цикле гарантированно выводится 8 байт, а по строкам меньше. А LDI использовать нельзя - у нас логические операции.
Oleg N. Cher, следующий этап — сохранение фона перед выводом спрайта, и при последующем выводе восстановление и новое сохранение. В случае использования логических наложений, особенно с маской это обязательно.
Знаю, drbars. Но тут для меня начинается высшая математика и что-то непостижимое. Есть люди, которые самыми неприхотливыми средствами делают настоящие чудеса, я могу только восторгаться или мечтать повторить. С масочными спрайтами работал только один раз, это был вывод пушечного ядра в игре SeaFight, и делался он точками, притом процедурой в ПЗУ.
Oleg N. Cher, вот пример... вывод спрайта с маской без таблиц движения. Делал для игры, но потом переписал под табличный способ.
http://zx-pk.ru/threads/23544-vyvod-sprajta-po-x-y.html
:v2_thumb:
- - - Добавлено - - -
А эффективнее по памяти или по скорости? По скорости таблица вне конкуренции - 32 такта на байт.
- - - Добавлено - - -
Чем-то помочь, рассказать?
- - - Добавлено - - -
Для этого в библиотеке надо поддержать непрямоугольные спрайты, иначе для фигуристых спрайтов будет работать очень медленно и жрать пямять. Вот тут как бы и начинается специфика Спектрума: в одних играх спрайты прямоугольные и такие извращения будут тормозить, в других нудна поддержка непрямоугольных спрайтов, в результате общие библиотеки неэффективны, каждый пишет своё с учетом 1000 и одного нюанса.
Alex Rider, я обязательно воспользуюсь любезным предложением помочь с матчастью: туда дальше вынесу на общую разработку пару своих идей игр, просто не надеюсь, что кто-то захочет присоединиться, из-за чего интерес не очень сильный. А так - художник нужен, музыкант, возможно, хард-кодер ассемблерщик. Но двигаться конечно планирую в своём контексте, т.е. писать на Обероне.
То, что есть специфика, и её надо учитывать - никакой библиотекой не поправишь. И так в любом деле. В книге "Как написать игру на ассемблере" есть вывод спрайтов произвольной конфигурации. И процедура там приводится очень простая. Но она так проста лишь только потому, что там координаты для вывода спрайта знакоместа вшиты в сам спрайт, в каждое его знакоместо. Если там хранить смещения и прибавлять к ним при выводе реальные координаты, пересчитывая их в адреса экрана и атрибутов, угадайте что будет? Правильно - будет довольно тормознуто.
Я просто не собираюсь писать игры со всякими фигурными спрайтами, масками и прочим, отсюда и такой скромный круг задач, которые я перед собой ставлю. Выше головы не прыгнешь - пусть игры делают те, у кого талант. Я со своей стороны буду совершенствовать ZXDev.
Про зеркалирование: конечно интереснее оптимизировать по скорости, но если табличка будет 256 байт, а у меня в игре всего один спрайт, который нужно зеркалить, и он шириной 2 знакоместа, то тут начинается стрельба по воробьям. :) В целом же было бы интересно сделать максимально эффективно по скорости, разумно по памяти, но без таблицы.
ZX_NOVOSIB, как видим, желающих клонировать Буратино не наблюдается. Никому не интересно. :)
P.S. Кстати, я адаптировал к ZXDev пару процедур атрибутного скроллинга из Supercode. То есть, Supercode намечен. Присоединяйтесь.
http://i.piccy_.info/i9/b6d3ca534360.../Supercode.png
deleted
Так может дать возможность выбора разработчику - скорость или размер?
- - - Добавлено - - -
Если нужно развернуть не один байт, а изображение спрайта в памяти,
то обработать попарно можно так (для простоты только внутренний цикл):
Код:col_mirror_loop:
dec hl
ld a, (de)
ld c, (hl)
; ------------------
; byte mirroring
; ------------------
DUP 8
rla
rr c
EDUP
; ------------------
rla
ld (de), a
ld (hl), c
inc de
djnz col_mirror_loop
Слышали анек про работника кроватного завода, который тащил детальки и собирал дома - то автомат получается, то пистолет. ;-) Так и я, не пойдёт мне эта теория впрок. Максимум, что я могу, это написать с её помощью что-то, положить такую процедуру бережно в либу и сдувать с неё пыль. Но к дизайну либы хорошо бы если бы приложил руку более опытный гейммейкер.
drbars, Bedazzle, благодарю. С миррорингом более или менее всё ясно.
Я реализовал AWRV, SL1V, SR1V, WL1V, WR1V. Байтовый (на 8 точек) и битовый (на 1 точку) скроллинг - обычный и циклический - проблем не вызвал. Больше вопросов вызывает горизонтальный скроллинг на 4 бита. Есть идея, как сделать его оптимально? Навскидку приходит на ум только побитовый сдвиг 4 раза и потом логическое наложение AND #F : OR x ( AND #F0 : OR x ).
Ещё как вариант использовать
https://i.imgur.com/SIevaIz.png
Да, действительно. Лучше этих команд ничего и не придумаешь. Годится. :)
Код:void Laser2_SL4V (unsigned char col, unsigned char row, unsigned char len, unsigned char hgt) __z88dk_callee
{
__asm
POP DE
POP BC ; C = col; B = row
CALL _Laser2_XYtoScr
POP BC ; C = len; B = hgt
PUSH DE
LD A, C
DEC A
ADD L
LD L, A
SL4V_HLINE$: PUSH BC
LD D, #8
LD E, L
SL4V_ROLL_LINE8$: LD B, C
XOR A
SL4V_ROLL_LINE$: RLD
DEC L
DJNZ SL4V_ROLL_LINE$
LD L, E
INC H
DEC D
JR NZ, SL4V_ROLL_LINE8$
LD A, L
ADD #0x20 ; Next charline
LD L, A ; If carry then jump to next third of screen
JR C, SL4V_CONT_1_3$
LD A, H
SUB #8 ; HL := HL - 0x0800
LD H, A
SL4V_CONT_1_3$: POP BC
DJNZ SL4V_HLINE$ ; End of loop on charlines (the same third)
__endasm;
} //Laser2_SL4V
Реализовал SL4V, SR4V, WL4V, WR4V, MIRV и MARV. Зеркалирование экрана использует код, предложенный Bedazzle. Для зеркалирования атрибутов удалось использовать команду LDI. Такты не считал, но думаю, получилось хорошо.
Вложение 58292
Мне остался только вертикальный скроллинг окна (вверх и вниз) на произвольное кол-во пикселей, обычный и циклический. И писать его не хочется, с удовольствием слямзил бы готовый.
- - - Добавлено - - -
Всё-таки посчитал такты. Неа, LDI здесь не эффективнее. Такой расклад.
Код:MARV_MIRR_LINE$: LD A, (DE) ; 7
LDI ; 16
DEC L ; 4
LD (HL), A ; 7
INC L ; 4
DEC DE ; 6
DEC E ; 4
DJNZ MARV_MIRR_LINE$ ; 48t, 8 bytes
Код:MARV_MIRR_LINE$: LD A, (DE) ; 7
LD C, (HL) ; 7
LD (HL), A ; 7
LD A, C ; 4
LD (DE), A ; 7
INC L ; 4
DEC E ; 4
DJNZ MARV_MIRR_LINE$ ; 40t, 7 bytes
drbars, код Bedazzle зеркалит сразу 2 байта одним махом. Чего и требуется.
Если я что-то не так понял, прошу объяснить, а не удалять.
- - - Добавлено - - -
drbars, ваш пример оптимальнее для зеркалирования одного байта, и с этим никто даже не собирался спорить. А тут сразу два байта. Если вы внимательно подумаете, то поймёте, что в моём случае (зеркалится окно) код Bedazzle оптимальнее.
Так что зря удалили.
drbars, ну что это за "барышня обиделась"? Восстановите посты, могут кому-то пригодиться. В т.ч. и мне потом, мало ли.
Господа, у кого-то они остались в кэше браузера? Запостите. (У меня нет, долбанный Chrome)
эти?
; mirror byte (example 2)
; 17 bytes, 66 t.
LD C,A
RLCA
RLCA
XOR C
AND %10101010
XOR C
LD C,A
RLCA
RLCA
RLCA
RRC C
XOR C
AND %01100110
XOR C
; Результат = reg A.
Так же, если проблема со свободными регистрами можно использовать только аккумулятор.
18 bytes
LD A,(HL)
RLCA
RLCA
XOR (HL)
AND %10101010
XOR (HL)
LD (HL),A
RLCA
RLCA
RLCA
RRC (HL)
XOR (HL)
AND %01100110
XOR (HL)
LD (HL),A
Вот моя процедура зеркалирования окна. Если вы видите как её оптимизнуть (не для демостроя, без таблиц), то милости прошу. У нас техническая тема, так что по возможности без эмоций, ладно?
Код:void Laser2_MIRV (unsigned char col, unsigned char row, unsigned char len, unsigned char hgt) __z88dk_callee
{
__asm
POP DE
POP BC ; C = col; B = row
CALL __Laser2_XYtoScr
POP BC ; C = len; B = hgt
PUSH DE
LD A, C
LD (MIRV_WIDTH$+1), A
INC A
SRL A
LD (MIRV_WIDTH_DIV2$+1), A
MIRV_HLINE$: PUSH BC ; Begin of loop on charlines
LD A, #8
MIRV_LINE8$: EX AF, AF
LD (MIRV_SCR_ADR$+1), HL
LD A, L
MIRV_WIDTH$: ADD #0
LD E, A
LD D, H
MIRV_WIDTH_DIV2$: LD B, #0
MIRV_COL_MIRROR$: DEC E
LD A, (DE)
LD C, (HL)
; ------------------
; 2 bytes mirroring
; ------------------
RLA
RR C
RLA
RR C
RLA
RR C
RLA
RR C
RLA
RR C
RLA
RR C
RLA
RR C
RLA
RR C
; ------------------
RLA
LD (DE), A
LD (HL), C
INC L
DJNZ MIRV_COL_MIRROR$
MIRV_SCR_ADR$: LD HL, #0
INC H
EX AF, AF
DEC A
JR NZ, MIRV_LINE8$
LD A, L
ADD #0x20 ; Next charline
LD L, A ; If carry then jump to next third of screen
JR C, MIRV_CONT_1_3$
LD A, H
SUB #8 ; HL := HL - 0x0800
LD H, A
MIRV_CONT_1_3$: POP BC
DJNZ MIRV_HLINE$ ; End of loop on charlines (the same third)
__endasm;
} //Laser2_MIRV
Сделал вывод спрайта с отсечением невидимой части, не помещающейся на экране. Кода понадобилось дофига прилично (+ байт 300). В приложенном архиве чудик, выбегающий из-за экрана и убегающий туда же, и двигающийся большой спрайт, которым можно рулить QAOP.
Вложение 58322
Дайте верт. скроллинг знакоместного окна на произвольное к-во пикселов, ну плиз! Так вломы писать! %) Может кто-то расковыривал SCROLL и SCROLLW из Mega Basic?
- - - Добавлено - - -
В Laser2 можно иметь спрайты размером превышающие размер экрана. Как с этим обстоят дела в оригинальном Laser Basic - не знаю. Скорее всего, тоже можно.
Как может выглядеть PIXEL_ADD, адаптированный для работы с экраном (буфером), размещённым по произвольному адресу?
Код:22B0 LD B,A
22B1 AND A
22B2 RRA
22B3 SCF
22B4 RRA
22B5 AND A
22B6 RRA
22B7 XOR B
22B8 AND A,F8H
22BA XOR B
22BB LD H,A
22BC LD A,C
22BD RLCA
22BE RLCA
22BF RLCA
22C0 XOR B
22C1 AND A,C7H
22C3 XOR B
22C4 RLCA
22C5 RLCA
22C6 LD L,A
22C7 LD A,C
22C8 AND A,07H
22CA RET
Искомый PIXEL_ADD, адаптированный для работы с экраном (буфером), размещённым по произвольному адресу.
Старший байт адреса экрана (или буфера) пишется подпрограммой настройки по адресу ScrHighByte+1.Код:; Вычисляем в HL адрес байта в экранной области
ld a,(_X1) ; 13
ld c,a ; 4
rra ; 4
rra ; 4
rra ; 4
and #1F ; 7
ld l,a ; 4
ld a,(_Y1) ; 13
ld b,a ; 4
and #38 ; 7
rla ; 4
rla ; 4
or l ; 4
ld l,a ; 4
ld a,b ; 4
and #07 ; 7
ld h,a ; 4
ld a,b ; 4
and #C0 ; 7
rra ; 4
rra ; 4
rra ; 4
or h ; 4
ScrHighByte: or #40 ; 7
ld h,a ; 4
ret ; 10
В Laser2 я использую модифицированную версию этого кода, чтобы задавать Y в пикселях, а X в знакоместах, так что код получается проще.
Благодарю AzAtom'а за эту процедуру.
Хочу подвести итоги по проекту.
Проект Laser 2 успешно доведён до требуемой кондиции и показал себя в работе хорошо и стабильно. Я реализовал-таки вертикальный нециклический скроллинг вверх и вниз. И ещё циклический скроллинг вверх (с буфером) на 1 пиксель. Перевёл порт игры на Laser 2, и бинарь стал меньше примерно на килобайт.
http://i.piccy_.info/i9/cf309ff1a041...357/Laser2.png
Вроде выигрыш и маловатый, но это же графический движок с кодом высокой плотности. Да, ещё заметил, что Laser 2 заметно быстрее спрайты отрисовывает, чем Laser Михайлова/Мазницы. То, что он и быстрее, и компактнее - это ему плюс. А в дополнение в нём ещё и процедуры хорошо друг от друга изолированы, т.е. отдельно взятый вывод спрайтов или отдельный скроллинг не тянет с собой пол-движка (как в Laser).
Конечно в Laser 2 возможности Laser Basic реализованы далеко не полностью, но жизнь научила не программировать впрок, и того, что сделано, мне вполне достаточно для порта игры Дурак со взгляда перфекциониста. У меня просьба. Если будете что-то делать в этом направлении, давайте скоординируем все изменения. Если будете применять Laser 2 в своих проектах, напишите мне. Это же интересно, в конце концов. :-)
Ещё отличие Laser 2 от Laser: нет никакой проверки координат на выход за пределы экрана. Конечно при выводе спрайтов это учтено (в режиме OUT_OF_SCREEN спрайт может выходить за границы экрана), но во всех остальных случаях никаких проверок не производится. Это сделано для ускорения графического вывода.
Самая свежая версия библиотеки Laser 2 живёт здесь:
молодец
Благодарю! И спасибо всем, кто участвовал в обсуждении.
Игорь, между прочим, именно ваш Laser и сподвиг меня в итоге на порт Дурака, из чего вылился проект ZXDev.
А вот как выглядит интерфейс для работы с Laser 2 на языке Оберон:
Код:DEFINITION Laser2; (* non-portable *)
(***************************)
(* LASER 2 Graphic Engine *)
(* Coded by Oleg N. Cher *)
(* zx.oberon2.ru/forum *)
(***************************)
TYPE
ADR = LONGINT;
BUFFER = ARRAY OF CHAR;
SPRITES = ARRAY OF CHAR;
UBYTE = INTEGER;
(* New procedures: *)
PROCEDURE SCRL (adr: ADR) (* Init sprites *) ;
PROCEDURE SCRLv (adr: ADR) (* in variable *) ;
PROCEDURE SCRLa (buf: BUFFER) (* in array *) ;
PROCEDURE SPRT (adr: ADR) (* Init sprites *) ;
PROCEDURE SPRTv (adr: ADR) (* in variable *) ;
PROCEDURE SPRTa (sprites: SPRITES) (* array *) ;
PROCEDURE SCRN (adr: ADR) (* Set screen *) ;
(* Synonyms for the new procedures: *)
PROCEDURE InitScroll (adr: ADR) ;
PROCEDURE InitScrollV (adr: ADR) (* in var *) ;
PROCEDURE InitScrollA (buf: BUFFER) ;
PROCEDURE InitSprites (adr: ADR) ;
PROCEDURE InitSpritesV (adr: ADR) (* in var *) ;
PROCEDURE InitSpritesA (sprites: SPRITES) ;
PROCEDURE SetScreen (adr: ADR) ;
(* Sprite manipulations: *)
PROCEDURE ATOF ;
PROCEDURE ATON ;
PROCEDURE INVM (spn: UBYTE) ;
PROCEDURE PTBL (col, row: SHORTINT; spn: UBYTE) ;
PROCEDURE PTND (col, row: SHORTINT; spn: UBYTE) ;
PROCEDURE PTNV (col, row: SHORTINT; spn: UBYTE) ;
PROCEDURE PTOR (col, row: SHORTINT; spn: UBYTE) ;
PROCEDURE PTXR (col, row: SHORTINT; spn: UBYTE) ;
(* Screen windows processing: *)
PROCEDURE CLSV (col, row, len, hgt: UBYTE) ;
PROCEDURE INVV (col, row, len, hgt: UBYTE) ;
PROCEDURE MIRV (col, row, len, hgt: UBYTE) ;
PROCEDURE SDNV (col, row, len, hgt, npx: UBYTE) ;
PROCEDURE SUPV (col, row, len, hgt, npx: UBYTE) ;
PROCEDURE SL1V (col, row, len, hgt: UBYTE) ;
PROCEDURE SL4V (col, row, len, hgt: UBYTE) ;
PROCEDURE SL8V (col, row, len, hgt: UBYTE) ;
PROCEDURE SR1V (col, row, len, hgt: UBYTE) ;
PROCEDURE SR4V (col, row, len, hgt: UBYTE) ;
PROCEDURE SR8V (col, row, len, hgt: UBYTE) ;
PROCEDURE WL1V (col, row, len, hgt: UBYTE) ;
PROCEDURE WL4V (col, row, len, hgt: UBYTE) ;
PROCEDURE WL8V (col, row, len, hgt: UBYTE) ;
PROCEDURE WR1V (col, row, len, hgt: UBYTE) ;
PROCEDURE WR4V (col, row, len, hgt: UBYTE) ;
PROCEDURE WR8V (col, row, len, hgt: UBYTE) ;
PROCEDURE WU1V (col, row, len, hgt: UBYTE) ;
(* Attribute windows processing: *)
PROCEDURE AWLV (col, row, len, hgt: UBYTE) ;
PROCEDURE AWRV (col, row, len, hgt: UBYTE) ;
PROCEDURE MARV (col, row, len, hgt: UBYTE) ;
PROCEDURE SETV (col, row, len, hgt: UBYTE) ;
END Laser2.
Исправил досадную ошибку в CLSV и INVV, связанную с некорректным вычислением адреса нижней строки знакомест.
Также пересобрал игру Бега мышей с помощью библиотеки Laser2. Интересно, что я делал ранее прогноз и, как выяснилось, оказался прав:
Ну вот, сегодня всех обрадую: с библиотекой Laser2 игра стала весить 3175 байт. После hrust'а 2607 байт. Это не предел конечно, есть ещё возможности для мелких оптимизаций.Цитата:
Сообщение от Oleg N. Cher
Тема «Графический движок Laser 2 (на концепте Laser Basic)» на Оберон-форуме:
Надо миррорить два байта, а не один, как по твоей ссылке, жерри.
Демострой это определённой набор подходов и принципов, при которых ложат болт на нормальное использование памяти и забивают целые килобайты инструкциями типа LDI, шобы было "во фреймчик". А мне была нужна универсальная библиотека. Да и 256 байт это тоже память.
Ладно, не возражаю. В XDev такие штуки могут быть устроены опционально. Благодаря сишному препроцессору.
Держитесь, пацаны. Через несколько дней вас будут обращать в Оберон.
Аминь
Да ясен пень, я ж и не спорю. Если всех всё устраивает