GBA ASM - День 9: Простой бэкграунд — Архив WASM.RU

Все статьи

GBA ASM - День 9: Простой бэкграунд — Архив WASM.RU

Что мы собираемся сделать сегодня

Во-первых и главным образом вам потребуется понять DMA, так как теперь я буду делать всю загрузку с помощью DMA. Во-вторых, вам потребуется следующее:

Инструменты, необходимые для бэкграундов:

  1. GBA Map Editor Beta 4 - Он багованный, но работает, если вы попробуете несколько раз :).
  2. Gifs2Sprites - у вас уже должна быть эта утилита, так как мы использовали её для конвертации тайлов.
  3. Картинка для использования в качестве тайлов - вы можете использовать спрайт и Дня 5. Вы увидите позже, как это сделал я.
  4. CtoASM.exe - все наши инструменты выводят конечный результат в формате C, используйте мою программу, что получить ассемблерный код.
  5. Вот и всё, что вам нужно для бэкграундов - много рисования, но мало программирования.

Создание бэкграундов на самом деле не слишком сложно, как это может показаться, прочитав соответствующий туториал на ThePernProject. Просто 3 загрузки и установка 2-х регистров и вуаля - мгновенный бэкграунд. В следующей секции мы подготовим тайлсет.

Подготовка тайлсета

Для подготовки тайлсета (т.е. тайлов, которые образуют карту/бэкграунд) используйте .gif-файл из Дня-5 или можете нарисовать свой собственный тайлсет в MS Paint. Запустите GBA Map Editor. В окне "Tool" кликните по меню "Tiles" и выберите "Load Tiles". У вас должен открыться следующее диалоговое окно.

Поскольку у нас gif-файл, вам придётся заменить "Files of type" на "All Files" (я пометил это на картинке). Сделайте это и откройте gif. Теперь картинка должна отображаться у вас в окне "Tool" в прокручивающемся фрейме, который называется "Choose Tile". Вы заметите, что там есть маленький красный квадрат. Кликните в любом месте картинки и этот квадрат переместится на этот тайл. Вы всегда можете выяснить, какой тайл используется в настоящий момент, посмотрев на окно "Tool" под "Selected Tile".

Теперь сделаем карту. В окне большего размера откройте меню "File" и кликните "New". Появится окно "Map Properties". Напечатайте в поле "Map Name" слово "simple", потому что эта карта будет очень проста (от англ. simple - "простой", прим. пер.), так как сейчас нам нужно лишь научиться делать карты и только. Убедитесь, что выбранный размер карты равен 256x256 и нажмите кнопку "OK" внизу окна.

В следующей секции рисуем карту!

Создание карты

Вы можете заметить опцию "Block Select" и решить, чтобы было бы неплохо её испльзовать. Как я сказал раньше, GBA Map Editor beta 4 - это очень багованная программа. Когда я использовал эту опцию, то в конце концов карта была обрезана. Этого не случится, если вместо опции "Block Select" вы пойдёте в меню "Tools" большого окна, наведёте мышью на "Tile Size" и кликните "16x16". Теперь красный квадрат в 4 раза больше, что не является полноценной заменой опции "Block Select", но на данный момент сгодится. Нарисуйте карту в большом чёрном квадрате/прямоугольнике/чём-бы-это-ни-было в большом окне. Это не должно быть чем то очень красивым, но мне понадобилось добрых пять минут, чтобы сделать из GIF'а из Дня 5 улыбающееся лицо. Вот как выглядит моё большое окно:

Давайте сохраним карту на тот случай, что редактор сглючит и не экспортирует нашу карту корректно. Откройте меню 'File" и кликните "Save". Сохраните под именем "simple.map". Хорошо.

Теперь мы экспортируем нашу карту в C. Идите в меню "File" в большом окне и поместите мышь над пунктом "Tools" и выберите "Export to C". Появится диалоговое окно сохранения файла. Сохраните под именем "simple.c". Теперь, перед тем как закрывать редактор карт, посмотрите на размер simple.c. Если размер меньше 5kb, то редактор сглючило (это происходит в половине случаев). Если это случилось, то либо попытайте сохранить снова и снова, либо закройте и запустите редактор карт заново - и так, пока не получите то, что вам нужно.

Другой путь определить корректность экспорта - это открыть simple.c. Вы увидите, что на первой строке говорится что-то вроде "32*32". Это значит, что должно быть 32 ряда и 32 колонки чисел. Просто посчитайте количество линий. Зачастую там будет 17, что неправильно. Используйте метод, приведённый выше, чтобы добиться нужного результата.

Ещё одна конвертация Gif в C

В этот раз мы должны использовать 256 цветов. Предположив, что ваш файл называется "sprit.gif", вот команда, которую вы должны напечатать:

Gifs2sprites 256 sprit.h sprit.gif

Обратите внимание, что имя создаваемого заголовочного С-файла задаётся первым, а уже ПОТОМ имя gif(ов). На выходе у вас должен получиться "sprit.h".

Итак, теперь у вас есть следующее:

  1. sprit.gif - картинка, которую вы использовали в качестве исходной.
  2. siple.map - карта, которую можно в случае чего отредактировать в редакторе.
  3. simple.h - C-код для чисел тайлов в карте.
  4. sprit.h - C-код для изображения sprit, которое мы использовали для тайлов.

Теперь нам нужно сконвертировать C-код в ассемблер!

Конвертация в ассемблер

Убедитесь, что у вас находятся 2 .h-файла и CtoASM.exe в одной директории, и запустите CtoASM.exe. Напечатайте "simple.h" в верхнем боле и "simple.asm" в нижнем. Нажмите кнопку "GO". Вы должны получить файл "simple.asm". Теперь закройте CtoASM. Вы его точно закрыли? (да-да, закрыли - прим. пер.) Теперь запустите его снова. Я попросил вас это сделать, потому что тестировал программу по конвертации за запуск, и не уверен насчёт её стабильности, если конвертировать несколько файлов подряд. Теперь напечатайте "sprit.h" и "sprit.asm" в соответствующих полях. Нажмите "GO". Если всё прошло успешно, то теперь у вас есть файл "sprit.asm".

Я надеюсь, что моя Windows-программа (я люблю XP и до сих пор не видел, чтобы она упала, пока :) ) пригодиться вам.

Регистры, о которых нам нужно знать

Есть 2 регистра о которых нам действительно нужно знать. Я начну с самого простого под названием REG_DISPCNT. Да, этот тот же регистр, что контролирует режим экрана. С его помощью нам нужно включить режим бэкграунда №2. Если вы заметили, что мы делали это всегда и до этого, то не волнуйтесь, поэтому я и сказал, что это будет просто! Другое, что вам нужно знать - это то, что сегодня мы будем использовать режим экрана №1, а не №3. Таким образом, в регистр REG_DISPCNT мы загрузим значение (MODE_1|BG2_ENABLE).

Другой регистр REG_BG2CNT чуть более сложен в понимании. Во-первых, если вы хотите использовать другой бэкграунд, включите его в регистре режима экрана, а затем замените '2' в 'REG_BG2CNT' на номер бэкграунда. REG_BG2CNT требует много информации, но для наших целей (простой бэкграунд) нам нужно загрузить в него всего лишь 4 вида данных.

Необходимая информация для REG_BG2ENABLE при 256 цветах 256x256 переменном (rotation) бэкграунде.

  1. Size - будет равен ROTBG_SIZE_256x256.
  2. Цвет - будет равен BG_COLOR_256. Переменные бэкграунды не могут использовать 16 цветов.
  3. Базовый блок экрана (Screen Base Block), далее SBB - куда вы поместите карту. Посмотрите на туториал о бэкграунда на ThePernProject, чтобы узнать больше информации об экране и базовых блоках символов (Char Base Blocks), чем даю здесь я.
  4. Базовый блок символов (Char Base Block), далее CBB - куда вы поместите сами битмапы тайлов (это и правда перевод с английского? - прим. пер.)

Есть 4 CBB и 32 SBB, но они пересекаются друг с другом, поэтом вам нужно поместить карту в блок, не находящийса в середине выбранного CBB. Все эти блоки в VRAM, поэтому мы не можем использовать такой битмап-режим как №3, потоу что иначе у нас на экране будет мусор.

Начинаем кодить!

Давайте же начнём кодить! Как обычно, я буду приводить код блоками, а потом его пояснять. И как обычно, мои комментарии будут приведены в вероятно большем количестве, чем требуется.

Теперь скачайте заголовочный файл бэкграундов backg.h.

Первый блок:

;;--- КОД НАЧИНАЕТСЯ ---;;
@include screen.h  ; всякие подсобные данные
@include dma.h     ; нужно для использования DMA
@include backg.h   ; содержатся необходимые данные для бэкграудов

b start   ; перепрыгиваем через бэкграунды и тайлы
@include simple.asm    ; наша карта, имеет метку objB0
@include sprit.asm     ; наш тайл с меткой obj
start    ; метка 

;устанавливаем режим экрана и включаем бэкграунд 2
ldr r1,=REG_DISPCNT
ldr r2,=(MODE_1|BG2_ENABLE)
str r2,[r1]       ; обратите внимание, что инструкция str сохраняет 
                  ; первый операнд во втором в отличии от инструкции ldr,
                  ; которая помещает второй в первый

; помещаем в регистр управления бэкграундами необходимую информацию
ldr r1,=REG_BG2CNT
ldr r2,=(ROTBG_SIZE_256x256|BG_COLOR_256|(28<<SCREEN_SHIFT))
str r2,[r1]
;;--- СТОП КОПИРОВАНИЕ ---;;

Вы можете спросить, что за (28<<SCREEN_SHIFT) был использован в последней инструкции ldr. SCREEN_SHIFT задаётся в backg.h, и мы сдвигаем 28 на значение SCREEN_SHIFT, чтобы поместить это число в место в регистре, где содержится номер SBB. Как вы можете видеть, мы используем 28-ой SBB и 0-й CBB. Мы не обязаны использовать именно 0-й, но это дефолтное значение, поэтому зачем усложнять себе жизнь? Мне кажется, что SBB №28 далековато располагается от CBB №0, но пока они не пересекаются друг с другом, это не должно нас волновать. Вот загрузка карты и тайла:

;;--- КОД ПРОДОЛЖАЕТСЯ ---;;
;теперь загружаем тайл с помощью DMA
ldr r1,=REG_DMA3SAD  ; \
ldr r2,=obj     ; - Адрес источника - obj, заданный в sprit.asm
str r2,[r1]     ; /

ldr r1,=REG_DMA3DAD    ; \
LoadCharBlockAddr r2, 0   ; - Подсобный макрос, загружает в r2 адрес CBB #0,
str r2,[r1]           ; являющийся нашим адресом назначения для этого
                      ; DMA-трансфера

ldr r1,=REG_DMA3CNT          ; \
ldr r2,=(8192|DMA_32NOW)   ; - перемещаем 8192 32-х битных блоков тайла в
                           ; CBB #0
str r2,[r1]               ; /

;------------------------------divider to make reading easier

ldr r1,=REG_DMA3SAD  ; \
ldr r2,=objB0     ; Адрес источника - objB0, заданный в simple.asm
str r2,[r1]     ; /

ldr r1,=REG_DMA3DAD    ; \
LoadScreenBlockAddr r2, 28   ; - подсобный макрос, загружает адрес 
                      ; SBB #28, являющийся адресом назнанчения для этого
str r2,[r1]           ; DMA-трансфера

ldr r1,=REG_DMA3CNT          ; \
ldr r2,=(512|DMA_32NOW)   ; - перемещаем 512 32-х битных блоков карты в 
str r2,[r1]               ; SBB #28
;;--- STOP COPYING ---;;

Обратите внимение, что комментарии начинаются с ';' и игнорируются Goldroad'ом. Не помню, говорил ли я вам об этом раньше, поэтому скажу здесь :).

Теперь я хотел бы объяснить, как я определил, сколько блоко необходимо переместить. В первый раз это было изображение 32x32. Это 1024, умножаем на 32, что является количество байтов в тайле. Получается 32768 блоков по 8 бит. Делим на 4 и получаем 8192 32-х битных блоков, которые необходимо переместить. Я не помню, как я получить 512 во втором случае, но это правильное значение.

Вы помните, что я говорил о трёх загрузках? Третья - это палитра, она загружается в VPAL, которая находится в память до спрайтовой палитры (0x5000000). Таким образом, загрузка палитры и бесконечный цикл будут являться последним блоком кода в этом Дне. Итак:

;;--- CODE CONTINUE ---;; 
ldr r1,=REG_DMA3SAD  ; \
ldr r2,=pallete     ; - Адрес источника - pallete, задано в in sprit.asm
str r2,[r1]     ; /

ldr r1,=REG_DMA3DAD    ; \
ldr r2,=VPAL   ; - Адрес назначения VPAL (палитра для бэкграунда и режима 
               ; экрана 4)
str r2,[r1]            ; /

ldr r1,=REG_DMA3CNT       ; \
ldr r2,=(128|DMA_32NOW)   ; - перемещаем 128 32-х битных блоков кода в VPAL.
str r2,[r1]               ; / Думаю, это будет верно для всех палитр, так
                          ; как в них 256 16-ти битных элементов

infin   ;\
b infin ; - бесконечный цикл
;;--- КОНЕЦ КОДА ---;;

Вот и всё, компилируйте и запускайте свой код!

Обзор этого дня

Не знаю, что и сказать, кроме того, что у меня заняло два выходных написать этот День в отличии от предыдущих, на которые требовалось по одному. Надеюсь, он вам понравился!

2002-2013 (c) wasm.ru