GBA ASM - День 5: Помещение спрайта на экран

Дата публикации 14 авг 2003

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):
  1.  
  2. > cd Полный путь к папке, где находятся sprit.gif и gifs2sprites.exe
  3.  
  4. > gifs2sprites 16 sprit.h sprit.gif
  5.  
  6. > 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):
  1.  
  2. Аттрибут 0 :
  3. Форма      |  Глубина цвета  | Y-позиция
  4. Квадратный |   COLOR_16      | (позиция на экране по вертикали)
  5. Высокий    |   COLOR_32      |      
  6. Широкий    |  
  7.  
  8. Аттрибут 1 :
  9. Size      |  X-позиция
  10. Size_8    | (позиция на экране по горизонтали)
  11. Size_16   |
  12. Size_32   |
  13.  
  14. Аттрибут 2 :
  15. Номер тайла размером 8x8 в памяти для спрайтов, с которого начинается данный
  16. спрайт.
  17.  
  18. Аттрибут 3 :
  19. Я думаю, что #3 предназначен для чего-то, связанного со вращением спрайтов.
  20. Поэтому здесь о нём не будет рассказываться.

Давайте начнём писать код! Скачайте sprites.h.

Код (Text):
  1.  
  2. ;;-- Начало кода --;;
  3.  
  4. @include screen.h
  5. @include sprites.h
  6. b start              ; перепрыгиваем через данные
  7. @include sprit.asm   ; это наша сконвертированная картинка
  8. start:               ; я начал помещать двоеточия, когда понял, что это
  9.                      ; лучше чем так, как это позволяет делать Goldroad
  10. Init_Sprites         ; макрос в sprites.h, инициализирующий все x-позиции спрайтов
  11.                      ; в значение 300
  12.  
  13. ldr r1,=REG_DISPCNT  ; делаем r1 указателем на регистр контроля экрана
  14. ldr r2,=(MODE_0|BG2_ENABLE|OBJ_ENABLE|OBJ_MAP_1D)
  15. str r2,[r1]          ; устанавливаем режим экрана 0 с бэкграундом 2,
  16.                      ; включёнными спрайтами (OBJs) и мэппингом спрайтов 1d
  17.                      ; (чтобы это ни было - прим. пер.) (кто захочет делать
  18.                      ; вложенные циклы на ассемблере, если мы можем этого
  19.                      ; избежать!)
  20.  
  21. ;;-- Хватит копировать --!!

Я собираюсь объяснить эту часть, затем я покажу остальной код. Если вы думаете, что комментарии сами по себе всё хорошо объясняют, то всё равно прочитайте это :smile3:. Во-первых, мы подключаем все необходимые файлы, потом вызываем макрос (который я великодушно накодил для вас), чтобы инициализировать спрайты. Далее мы помещаем экран в режим 0, что вы можете найти довольно необычным, так как большинство программерских туториалов, которые я видел, используют режим 3 или 4. Я использовал режим 0, потому что это тайл-режим (tiled mode), а битмэп-режимы (3 или 4) разделят память под спрайты и используют половину для экрана или буфера.

Одновременнос с установлением режима 0 мы разрешаем использование спрайтов и бэкграунда. Также мы устанавливаем загрузку спрайтов в 1D. Если бы мы поставили 2D, то нам бы пришлось отслеживать x и y. Следующая часть кода:

Код (Text):
  1.  
  2. ;;-- Код продолжается --!!
  3.  
  4. ldr r0,=OAM        ; делаем r0 указателем на OAM (0x7000000)
  5. ldr r1,=(SQUARE|COLOR_16|10)|((SIZE_32|10)<<16)            
  6.                    ; выше мы помещаем все аттрибуты 0 и 1 в r1, ниже будет
  7.                    ; подробное объяснение
  8. str r1,[r0]+4!     ; помещаем аттрибуты 0 и 1 в OAM и увеличиваем значение
  9.                    ; указателя в OAM так, чтобы он указывал на аттрибут 2
  10. ldr r1,=0          ; аттрибут 2 - это номер тайла, а наш спрайт начинается с первого: 0
  11. str r1,[r0]        ; помещаем его в OAM. Если вы  хотели другой спрайт, вам
  12.                    ; нужно было сделать "+4!"
  13.                    ; to get the OAM pointer (r0) past Attribute 2 and past rotation stuff in Attribute 3 and to
  14.                    ; the start of the next sprite's OAM entry
  15.                    ; чтобы получить указатель OAM (r0), пропустите аттрибут 2,
  16.                    ; то, что относится к вращению и перейдите к началу
  17.                    ; следующего элемента OAM
  18.  
  19. ;;-- Заканчивайте копировать здесь --!!

Теперь нужно сделать некоторое объяснение, в основном того, что касается второй строки:

Код (Text):
  1.  
  2. 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):
  1.  
  2. ;;-- Код продолжается --!!
  3.  
  4. ldr r1,=OBJPAL     ; r1 указывает на палитру спрайтов (0x500200)
  5. ldr r2,=128        ; 128 - число раз, которое мы обращаемся к палитре
  6. ldr r3,=pallete    ; палитра задана sprit.asm, который мы получили после
  7.                    ; конвертирования
  8.  
  9. palloop:        ; этот цикл - типичный пример кода загрузки
  10. ldr r7,[r3]+4!  ; он помещает 4 байта из палитры в r7, а потом
  11. str r7,[r1]+4!  ; сохраняет 4 байт в палитру спрайтов. Каждый раз используется
  12.                 ; "обратная запись" каждого регистра на 4
  13. subs r2,r2,1    ; эта строка вычитает из количества обращений к палитре 1
  14. bne palloop     ; и делает так, чтобы флаги представляли состояние РАВНО
  15.  
  16. ; if r2 = 0   (r2==0, это для любителей C). Это BNE-выражение выполнится если
  17. ; состояние флагов НЕ РАВНО, поэтому выполнение цикла остановится, когда мы
  18. ; закончим
  19.  
  20. ;;-- Заканчивайте копировать здесь --!!

Я думаю, что в этот раз комментарии к коду действительно выполняют свое предназначение, поэтому переходим к следующей секции.

CHARMEM (Sprite Picture Memory)

SPM начинается с 0x6010000. Если бы мы были в битмапном режиме экрана (3 или 4), тогда бы нам пришлось начать с 512 тайла вместо 0. Вот почему мы в режиме 0.

Код (Text):
  1.  
  2. ;;-- Код продолжается --!!
  3.  
  4. ldr r1,=CHARMEM   ; смотрите описание ниже
  5. ldr r2,=128
  6. ldr r3,=obj0
  7.  
  8. sprloop:
  9. ldr r7,[r3]+4!
  10. str r7,[r1]+4!
  11. subs r2,r2,1
  12. bne sprloop
  13.  
  14. ;;-- Заканчивайте копировать здесь --!!

Это тот же загружающий код, изменились только указатели (спрайт в CHARMEM), а obj0 - это наш сконвертированный спрайт, находящийся в sprit.asm.

Конец кода и этого дня

Конец кода делает бесконечный цикл и это всё.

Код (Text):
  1.  
  2. ;;-- CODE CONTINUE --!!
  3.  
  4. infiniteloop
  5. b infiniteloop
  6.  
  7. ;;-- END OF CODE --!!

"Кому-то нужны объятия..."
- Ryan Stiles, "Whose line is it anyway?" © Mike H, пер. Aquila


0 907
archive

archive
New Member

Регистрация:
27 фев 2017
Публикаций:
532