GBA ASM - День 5: Помещение спрайта на экран — Архив WASM.RU
Введение
Этот день посвящён спрайтам, а если более точно тому, как вывести его на экран. Да, именно так - всё, что мы будем делать сегодня - это выведем на экран 16-ти цветный спрайт размером 32x32 на экран.
Конвертирование изображения
Так же, как и когда мы помещали на экран изображение, нам необходимо сконвертировать его во что-то понимаемое Goldroad'ом. В этот раз мы будем использовать GIFs2SPRITEs.exe, который может конвертировать GIF'ы в C-код. Теперь посмотрим, как Goldroad будет обрабатывать C-файл. Давай поиграем в короткий ответ/длинный ответ! Короткий ответ: он не умеет этого делать. Длинный ответ: мне пришлось сделать программу на VB, конвертирующую вывод GIFs2SPRITEs.exe в Goldroad'овские @DCW-выражения. Вы можете скачать GIFs2SPRITEs.exe здесь (он заархивирован). Теперь моя программа: CtoASM.exe.
Теперь нарисуйте в MSPaint'е (лучше в Photoshop'е - прим.пер.) картинку размером 32x32, сохраните её как GIF-файл под названием sprit.gif в Goldroad'овской папке "tools". Теперь откройте DOS-подсказку и делайте следующее:
Код (Text):
> cd Полный путь к папке, где находятся sprit.gif и gifs2sprites.exe > gifs2sprites 16 sprit.h sprit.gif > ctoasmОбратите внимание, что это Windows-программа. Выберите sprit.h, в диалоге сохранения файла напишите "sprit.asm". Затем нажмите на кнопку GO и нажмите на ОК, когда появится предпуреждение, что весь процесс может занять определённое количество времени.
Теперь, я надеюсь, у вас есть файл sprit.asm. Я знаю, что моя программа не эффективна, но тем не менее она работает.
OAM (Object Attribute Memory)
Если вы программировали под GBA на C раньше, то вы, возможно, знаете, что OAM - это где вы сообщаете GBA всё о вашем спрайте, например: размер, форма, цвета (16/256), X-позиция, Y-позиция, номер тайла (tile)/чара (char). OAM находится по адресу 0x7000000. OAM состоит из 128 элементов (0-127), т.е. GBA может отслеживать 128 спрайтов в OAM.
Помните, что вы также ограничены доступной памятью для изображений спрайтов. Каждый элемент OAM 8 байтов размеров, где 4 (0-3) аттрибута по два байта. Аттрибуты следующие:
*ПРИМЕЧАНИЕ: перечислены только важные части. Идите на The Pern Project за полным перечнем.
Код (Text):
Аттрибут 0 : Форма | Глубина цвета | Y-позиция Квадратный | COLOR_16 | (позиция на экране по вертикали) Высокий | COLOR_32 | Широкий | Аттрибут 1 : Size | X-позиция Size_8 | (позиция на экране по горизонтали) Size_16 | Size_32 | Аттрибут 2 : Номер тайла размером 8x8 в памяти для спрайтов, с которого начинается данный спрайт. Аттрибут 3 : Я думаю, что #3 предназначен для чего-то, связанного со вращением спрайтов. Поэтому здесь о нём не будет рассказываться.Давайте начнём писать код! Скачайте sprites.h.
Код (Text):
;;-- Начало кода --;; @include screen.h @include sprites.h b start ; перепрыгиваем через данные @include sprit.asm ; это наша сконвертированная картинка start: ; я начал помещать двоеточия, когда понял, что это ; лучше чем так, как это позволяет делать Goldroad Init_Sprites ; макрос в sprites.h, инициализирующий все x-позиции спрайтов ; в значение 300 ldr r1,=REG_DISPCNT ; делаем r1 указателем на регистр контроля экрана ldr r2,=(MODE_0|BG2_ENABLE|OBJ_ENABLE|OBJ_MAP_1D) str r2,[r1] ; устанавливаем режим экрана 0 с бэкграундом 2, ; включёнными спрайтами (OBJs) и мэппингом спрайтов 1d ; (чтобы это ни было - прим. пер.) (кто захочет делать ; вложенные циклы на ассемблере, если мы можем этого ; избежать!) ;;-- Хватит копировать --!!Я собираюсь объяснить эту часть, затем я покажу остальной код. Если вы думаете, что комментарии сами по себе всё хорошо объясняют, то всё равно прочитайте это . Во-первых, мы подключаем все необходимые файлы, потом вызываем макрос (который я великодушно накодил для вас), чтобы инициализировать спрайты. Далее мы помещаем экран в режим 0, что вы можете найти довольно необычным, так как большинство программерских туториалов, которые я видел, используют режим 3 или 4. Я использовал режим 0, потому что это тайл-режим (tiled mode), а битмэп-режимы (3 или 4) разделят память под спрайты и используют половину для экрана или буфера.
Одновременнос с установлением режима 0 мы разрешаем использование спрайтов и бэкграунда. Также мы устанавливаем загрузку спрайтов в 1D. Если бы мы поставили 2D, то нам бы пришлось отслеживать x и y. Следующая часть кода:
Код (Text):
;;-- Код продолжается --!! ldr r0,=OAM ; делаем r0 указателем на OAM (0x7000000) ldr r1,=(SQUARE|COLOR_16|10)|((SIZE_32|10)<<16) ; выше мы помещаем все аттрибуты 0 и 1 в r1, ниже будет ; подробное объяснение str r1,[r0]+4! ; помещаем аттрибуты 0 и 1 в OAM и увеличиваем значение ; указателя в OAM так, чтобы он указывал на аттрибут 2 ldr r1,=0 ; аттрибут 2 - это номер тайла, а наш спрайт начинается с первого: 0 str r1,[r0] ; помещаем его в OAM. Если вы хотели другой спрайт, вам ; нужно было сделать "+4!" ; to get the OAM pointer (r0) past Attribute 2 and past rotation stuff in Attribute 3 and to ; the start of the next sprite's OAM entry ; чтобы получить указатель OAM (r0), пропустите аттрибут 2, ; то, что относится к вращению и перейдите к началу ; следующего элемента OAM ;;-- Заканчивайте копировать здесь --!!Теперь нужно сделать некоторое объяснение, в основном того, что касается второй строки:
Код (Text):
ldr r1,=(SQUARE|COLOR_16|10)|((SIZE_32|10)<<16)Обратите внимание, что так как каждый аттрибут длиной 2 байта, мы можем заполнить 32-х битный регистр двумя аттрибутами. Поэтому первые 3 вещи сORенные друг с другом - это аттрибут 0, а вторые две - это аттрибут 1. Аттрибут 1 сдвигается налево, чтобы быть в первых 16-ти битах регистра. Я понимаю, что внешне это выглядит наоборот, потому что кажется, что код помещает аттрибут 1 перед 0. Сначала я думал, что первые три сORенные вещи должны быть в первых 2-х байтах, это не заработало, поэтому я изменил код так, каким он является сейчас, и он работает.
"не чините то, что работает"
Палитра (цвета спрайтов)
Есть две палитры, одна для бэкграундов и одна для спрайтов (0x500200). Палитра - это куда помещаются цвета спрайтов. Также я должен сказать, что в C вы би использовали цикл FOR, который бы пробегал 256 раз, используя 16-ти битный указатель. В ассемблере все указатели ВСЕГДА 32-х битны, поэтому мы загружаем двойное количество данных за раз, обращаясь к памяти в два раза меньше (128 раз). Вот код, чтобы загрузить палитру из нашего сконвертированного GIF-файла.
Код (Text):
;;-- Код продолжается --!! ldr r1,=OBJPAL ; r1 указывает на палитру спрайтов (0x500200) ldr r2,=128 ; 128 - число раз, которое мы обращаемся к палитре ldr r3,=pallete ; палитра задана sprit.asm, который мы получили после ; конвертирования palloop: ; этот цикл - типичный пример кода загрузки ldr r7,[r3]+4! ; он помещает 4 байта из палитры в r7, а потом str r7,[r1]+4! ; сохраняет 4 байт в палитру спрайтов. Каждый раз используется ; "обратная запись" каждого регистра на 4 subs r2,r2,1 ; эта строка вычитает из количества обращений к палитре 1 bne palloop ; и делает так, чтобы флаги представляли состояние РАВНО ; if r2 = 0 (r2==0, это для любителей C). Это BNE-выражение выполнится если ; состояние флагов НЕ РАВНО, поэтому выполнение цикла остановится, когда мы ; закончим ;;-- Заканчивайте копировать здесь --!!Я думаю, что в этот раз комментарии к коду действительно выполняют свое предназначение, поэтому переходим к следующей секции.
CHARMEM (Sprite Picture Memory)
SPM начинается с 0x6010000. Если бы мы были в битмапном режиме экрана (3 или 4), тогда бы нам пришлось начать с 512 тайла вместо 0. Вот почему мы в режиме 0.
Код (Text):
;;-- Код продолжается --!! ldr r1,=CHARMEM ; смотрите описание ниже ldr r2,=128 ldr r3,=obj0 sprloop: ldr r7,[r3]+4! str r7,[r1]+4! subs r2,r2,1 bne sprloop ;;-- Заканчивайте копировать здесь --!!Это тот же загружающий код, изменились только указатели (спрайт в CHARMEM), а obj0 - это наш сконвертированный спрайт, находящийся в sprit.asm.
Конец кода и этого дня
Конец кода делает бесконечный цикл и это всё.
Код (Text):
;;-- CODE CONTINUE --!! infiniteloop b infiniteloop ;;-- END OF CODE --!!"Кому-то нужны объятия..."
- Ryan Stiles, "Whose line is it anyway?" © Mike H, пер. Aquila
GBA ASM - День 5: Помещение спрайта на экран
Дата публикации 14 авг 2003