Реактивное введение в программирование Game Boy Advance (часть 2 из 8)

Пиксельные видеорежимы…

Оглавление


Часть 1: Инструментарий, основы, кнопки, таймеры
Часть 2: Пиксельные видеорежимы
Часть 3: Тайловые видеорежимы
Часть 4: Спрайты
Часть 5: Вращающиеся фоны и прозрачность
Часть 6: Прерывания, DMA
Часть 7: Звук (Direct Sound)
Часть 8: Сохранения

4. Пиксельные видеорежимы


Итак, пришло время вывести что-нибудь на экран GBA. LCD-экран аппарата имеет физическое разрешение 240x160 пикселей и способен отображать 15-битный (High Color) цвет формата 5:5:5. 59.73 раз в секунду (в точности 280896 тактов ЦП) видеоадаптер обновляет содержимое экрана содержимым видеопамяти и памяти спрайтов. Каждое обновление экрана состоит из 160 обновлений строк (этот период в целом называется VDraw), за которыми следуют как бы 68 «невидимых» строк — период когда видеоконтроллер бездействует (он в свою очередь называется VBlank). Каждое обновление строки экрана в свою очередь разбито на период обновления пикселей в строке (HDraw), который длится 1004 тактов за которым следует короткий период бездействия длиной 228 тактов (HBlank).
GBA имеет 6 разных видеорежимов (MODE_0-5) из которых мы сейчас рассмотрим 3 последних — так называемых «пиксельных» видеорежимов. Они являются самыми простыми для первых попыток что-либо отобразить. Рассмотрим их по порядку:

  • Режим 3 имеет разрешение 240x160x15. Начинается с адреса 0x06000000 (VID_RAM_START). Каждый пиксель занимает 2 байта 15-битного RGB-цвета. Из-за большой величины видеобуфера не имеет второй страницы. Если завести макрос #define VID_BUFFER ((u16 *) VID_RAM_START), то можно адресовать отдельные пиксели как VID_BUFFER[ x + 240 * y ], где x — номер пикселя по горизонтали от 0 до 239, а y — по вертикали (сверху-вниз) от 0 до 159.
  • Режим 4 имеет разрешение 240x160x8. Начинается с адреса 0x06000000, имеет вторую страницу по адресу 0x0600A000. Переключение между видеостраницами контролируется битом MODE_PAGE_2 регистра REG_DISPCNT, что позволяет реализовать быстрое переключение страниц. Однобайтовые пиксели хранят индекс в 16-битной палитре из 256 ячеек по адресу BGR_PALETTE, таким образом одновременно на экране не может быть отображено больше 256 вариантов цветов, но какие именно цвета могут быть отображены одновременно — контролируются в массиве палитры.
  • Режим 5 имеет разрешение 160x128x16. Начинается с адреса 0x06000000, из-за пониженного разрешения тоже имеет вторую страницу по адресу 0x0600A000.

Раскладка памяти более чем классическая — пиксели описываются строками от левого верхнего угла экрана слева-направа-сверху-вниз по порядку.
Здесь, однако, возникает очень важное замечание: вся видеопамять (VID_RAM) обладает очень существенной особенностью: в неё нельзя записать меньше, чем 2 байта (16 бит) за раз. Контроллер видеопамяти устроен таким образом, что попытка записать одиночный байт в видеопамять приведет к дублированию его записи в смежный по чётности байт. Любопытно, но с чтением такой особенности не возникает, а вот запись то ли для скорости (что иногда сомнительно), то ли для сокращения количества проводов всегда осуществляется 16-битными обращениями. Для видеорежимов 3 и 5 это не страшно — пиксели там и так двухбайтные и с байтами возится не надо. Но 8-битный палитровый режим 4 хранит по байту на каждый пиксель и выходит, что записывать/обновлять мы можем только по 2 соседних пикселя за раз. Чтобы обновить отдельный пиксель нужно считать значение пары, в зависимости от четности обновить его и записать обратно. Это довольно таки дорого, поэтому есть смысл иметь эту особенность ввиду.

Установка видеорежимов и самых важных параметров видеоадаптера производится через запись в порт REG_DISPCNT. Нижние 3 его бита численно равны выставленному видеорежиму (от 0 до 6). Включение 4-го (нумерация с нуля!) бита переключает дисплей на отображение второй видеостраницы пиксельных видеорежимов. А биты с 9 по 12 включают отображение задних фонов (backgrounds) от BG0 до BG3. Эти биты в основном нужны в тайловых видеорежимах, которые мы пока не рассматриваем, но видеоадаптер в пиксельных видеорежимах ведет себя так, как будто карта пикселей это задний фон BG2 и нам его надо включить, иначе на экране ничего не появится.
Вторым важным сейчас для нас видеопортом является REG_VCOUNT в котором видеоадаптер поддерживает текущий номер обновляемой строки экрана. Это значение периодически увеличивается от 0 до 159 во время VDraw, потом еще 68 раз увеличивается во время VBlank, после чего цикл повторяется. Это позволяет нам легко реализовать т.н. VSync.

Вкратце интерфейс работы с пиксельными видеорежимами можно описать вот так:


// Порты ввода-вывода видеоадаптера
// Макрос RGB показывает раскладку цветов 15-битного цвета.
#define RGB(r,g,b)  (r+((g)<<5)+((b)<<10)) 

// *** РЕГИСТР КОНТРОЛЯ ВИДЕОРЕЖИМА
#define REG_DISPCNT (*((volatile u32 *) 0x4000000))
// Нужные нам битовые флаги
#define MODE_3      0x3
#define MODE_4      0x4
#define MODE_5      0x5
// Бит 4: для пиксельных режимов переключает отображение на вторую страницу.
#define MODE_PAGE_2     0x0010
// Включение заднего фона от 0 до 3. Пиксельные видеорежимы считаются задним фоном BG2.
#define BG0_ENABLE      0x0100
#define BG1_ENABLE      0x0200
#define BG2_ENABLE      0x0400
#define BG3_ENABLE      0x0800

// *** РЕГИСТР ТЕКУЩЕЙ ВЫВОДИМОЙ НА ЭКРАН СТРОКИ ПИКСЕЛЕЙ
#define REG_VCOUNT  (*((volatile u16 *) 0x4000006))

#define BGR_PALETTE ((u16 *) BGR_PAL_RAM_START)
#define SPR_PALETTE ((u16 *) SPR_PAL_RAM_START)
#define VID_BUFFER ((u16 *) VID_RAM_START)


Ну и вот теперь мы готовы создать первую осмысленную нашу программу под GBA, использующую кнопки, таймеры и пиксельные видеорежимы.
Для отрисовки текста нам понадобится какой никакой, но шрифт. Проще всего быстро набросать его как массив и подключать потом при необходимости его прямо в тело программы.

Для начала мы сделаем вот что — создадим заголовочный файл gba_defs.h и добавим в него весь код что мы описывали выше, включая предыдущую главу (в исходниках он уже присутствует в полном объёме по всем урокам). Этот файл в итоге составит как бы API для работы с GBA, весь код с макросами описывающими порты ввода-вывода попадёт в него.

Далее создадим файл microfont.cpp и заполним его следующим кодом:


#include "gba_defs.h"

static const unsigned char micro_font[] =
// 32
"      "
"      "
"      "
"      "
"      "
"      "
// 33
"  X   "
"  X   "
"  X   "
"      "
"  X   "
"      "
// 34
"XX XX "
"      "
"      "
"      "
"      "
"      "
// 35
" X X  "
"XXXXX "
" X X  "
"XXXXX "
" X X  "
"      "
// 36
"  X   "
" XXXX "
"  X   "
"XXXX  "
"  XX  "
"      "
// 37
"XX  X "
"XX X  "
"  X   "
" X XX "
"X  XX "
"      "
// 38
" XX   "
"X X X "
" X X  "
"X X   "
" X X  "
"      "
// 39
"  X   "
"  X   "
"      "
"      "
"      "
"      "
// 40
"  X   "
" X    "
" X    "
" X    "
"  X   "
"      "
// 41
"  X   "
"   X  "
"   X  "
"   X  "
"  X   "
"      "
// 42
"      "
" X X  "
"  X   "
" X X  "
"      "
"      "
// 43
"      "
"  X   "
" XXX  "
"  X   "
"      "
"      "
// 44
"      "
"      "
"      "
"      "
"   X  "
"  X   "
// 45
"      "
"      "
" XXXX "
"      "
"      "
"      "
// 46
"      "
"      "
"      "
"      "
"  X   "
"      "
// 47
"      "
"    X "
"   X  "
"  X   "
" X    "
"      "
// 48
" XXX  "
"X   X "
"X X X "
"X   X "
" XXX  "
"      "
// 49
"   X  "
"  XX  "
" X X  "
"   X  "
"   X  "
"      "
// 50
" XXX  "
"X   X "
"   X  "
" XX   "
"XXXXX "
"      "
// 51
" XXX  "
"    X "
"  XX  "
"    X "
" XXX  "
"      "
// 52
" X  X "
" X  X "
" XXXX "
"    X "
"    X "
"      "
// 53
"XXXX  "
"X     "
"XXXX  "
"   XX "
"XXXX  "
"      "
// 54
"XXXXX "
"X     "
"XXXX  "
"X   X "
" XXX  "
"      "
// 55
" XXXX "
"    X "
"   X  "
"  X   "
"  X   "
"      "
// 56
" XXX  "
"X   X "
" XXX  "
"X   X "
" XXX  "
"      "
// 57
" XXX  "
"X   X "
" XXXX "
"    X "
" XXX  "
"      "
// 58
"      "
"  XX  "
"      "
"  XX  "
"      "
"      "
// 59
"      "
"  XX  "
"      "
"  XX  "
"   X  "
"      "
// 60
"      "
"  X   "
" X    "
"  X   "
"      "
"      "
// 61
"      "
" XXXX "
"      "
" XXXX "
"      "
"      "
// 62
"      "
"  X   "
"   X  "
"  X   "
"      "
"      "
// 63
" XXX  "
"   X  "
"  X   "
"      "
"  X   "
"      "
// 64
" XXX  "
"X  XX "
"X XXX "
" XXXX "
" XXX  "
"      "
// 65
"  XX  "
" X  X "
" XXXX "
" X  X "
" X  X "
"      "
// 66
" XX   "
" X X  "
" XXX  "
" X  X "
" XXX  "
"      "
// 67
" XXX  "
"X   X "
"X     "
"X   X "
" XXX  "
"      "
// 68
"XXXX  "
"X   X "
"X   X "
"X   X "
"XXXX  "
"      "
// 69
" XXXX "
" X    "
" XX   "
" X    "
" XXXX "
"      "
// 70
" XXXX "
" X    "
" XXX  "
" X    "
" X    "
"      "
// 71
" XXX  "
"X     "
"X  XX "
"X   X "
" XXX  "
"      "
// 72
"X   X "
"X   X "
"XXXXX "
"X   X "
"X   X "
"      "
// 73
" XXX  "
"  X   "
"  X   "
"  X   "
" XXX  "
"      "
// 74
"  XXX "
"   X  "
"   X  "
" X X  "
"  X   "
"      "
// 75
" X  X "
" X X  "
" XX   "
" X X  "
" X  X "
"      "
// 76
" X    "
" X    "
" X    "
" X    "
" XXXX "
"      "
// 77
"X   X "
"XXXXX "
"X X X "
"X   X "
"X   X "
"      "
// 78
"X   X "
"XX  X "
"X X X "
"X  XX "
"X   X "
"      "
// 79
" XXX  "
"X   X "
"X   X "
"X   X "
" XXX  "
"      "
// 80
" XXX  "
" X  X "
" XXX  "
" X    "
" X    "
"      "
// 81
" XXX  "
"X   X "
"X X X "
"X  X  "
" XX X "
"      "
// 82
" XXX  "
" X  X "
" XXX  "
" X X  "
" X  X "
"      "
// 83
" XXX  "
" X  X "
"  X   "
"X  X  "
" XXX  "
"      "
// 84
"XXXXX "
"  X   "
"  X   "
"  X   "
"  X   "
"      "
// 85
" X  X "
" X  X "
" X  X "
" X  X "
"  XX  "
"      "
// 86
"X   X "
"X   X "
" X X  "
" X X  "
"  X   "
"      "
// 87
"X   X "
"X   X "
"X X X "
"X X X "
" X X  "
"      "
// 88
"X   X "
" X X  "
"  X   "
" X X  "
"X   X "
"      "
// 89
"X   X "
" X X  "
"  X   "
"  X   "
"  X   "
"      "
// 90
"XXXXX "
"   X  "
"  X   "
" X    "
"XXXXX "
"      "
// 91
" XXX  "
" X    "
" X    "
" X    "
" XXX  "
"      "
// 92
"      "
" X    "
"  X   "
"   X  "
"    X "
"      "
// 93
" XXX  "
"   X  "
"   X  "
"   X  "
" XXX  "
"      "
// 94
"   X  "
"  X X "
"      "
"      "
"      "
"      "
// 95
"      "
"      "
"      "
"      "
" XXXX "
"      "
// 96
" XX   "
"   X  "
"      "
"      "
"      "
"      "
// 97
"  XX  "
" X  X "
" XXXX "
" X  X "
" X  X "
"      "
// 98
" XX   "
" X X  "
" XXX  "
" X  X "
" XXX  "
"      "
// 99
" XXX  "
"X   X "
"X     "
"X   X "
" XXX  "
"      "
// 100
"XXXX  "
"X   X "
"X   X "
"X   X "
"XXXX  "
"      "
// 101
" XXXX "
" X    "
" XX   "
" X    "
" XXXX "
"      "
// 102
" XXXX "
" X    "
" XXX  "
" X    "
" X    "
"      "
// 103
" XXX  "
"X     "
"X  XX "
"X   X "
" XXX  "
"      "
// 104
"X   X "
"X   X "
"XXXXX "
"X   X "
"X   X "
"      "
// 105
" XXX  "
"  X   "
"  X   "
"  X   "
" XXX  "
"      "
// 106
"  XXX "
"   X  "
"   X  "
" X X  "
"  X   "
"      "
// 107
" X  X "
" X X  "
" XX   "
" X X  "
" X  X "
"      "
// 108
" X    "
" X    "
" X    "
" X    "
" XXXX "
"      "
// 109
"X   X "
"XXXXX "
"X X X "
"X   X "
"X   X "
"      "
// 110
"X   X "
"XX  X "
"X X X "
"X  XX "
"X   X "
"      "
// 111
" XXX  "
"X   X "
"X   X "
"X   X "
" XXX  "
"      "
// 112
" XXX  "
" X  X "
" XXX  "
" X    "
" X    "
"      "
// 113
" XXX  "
"X   X "
"X X X "
"X  X  "
" XX X "
"      "
// 114
" XXX  "
" X  X "
" XXX  "
" X X  "
" X  X "
"      "
// 115
" XXX  "
" X  X "
"  X   "
"X  X  "
" XXX  "
"      "
// 116
"XXXXX "
"  X   "
"  X   "
"  X   "
"  X   "
"      "
// 117
" X  X "
" X  X "
" X  X "
" X  X "
"  XX  "
"      "
// 118
"X   X "
"X   X "
" X X  "
" X X  "
"  X   "
"      "
// 119
"X   X "
"X   X "
"X X X "
"X X X "
" X X  "
"      "
// 120
"X   X "
" X X  "
"  X   "
" X X  "
"X   X "
"      "
// 121
"X   X "
" X X  "
"  X   "
"  X   "
"  X   "
"      "
// 122
"XXXXX "
"   X  "
"  X   "
" X    "
"XXXXX "
"      "
// 123
" XXX  "
" X    "
"XX    "
" X    "
" XXX  "
"      "
// 124
"  X   "
"  X   "
"  X   "
"  X   "
"  X   "
"      "
// 125
" XXX  "
"   X  "
"   XX "
"   X  "
" XXX  "
"      "
// 126
" X X  "
"  X X "
"      "
"      "
"      "
"      "
// 127
"X X X "
" X X  "
"X X X "
" X X  "
"X X X "
"      "
;

// Вывод текста микрошрифта 6x6 в видеорежиме 0x4.
void draw3_micro_text( int x, int y, const char *text )
{
	u16 *buf = VID_BUFFER + x + 240 * y; // Адрес для вывода текущего символа
	char c;
	while ( c = *text )
	{
		if ( (c < 32) || (c > 127) )
			c = 127;	// все символы кроме ASCII будут "решеткой"
		c -= 32;
		// находим опорный адрес символа в микрошрифте
		const u8 *base = micro_font + 6 * 6 * c;
		u16 *cur = buf;
		for ( int l = 0; l < 6; l++ )
		{
			for ( int w = 0; w < 6; w++ )
				cur[ w ] = *base++;
			cur += 240;
		};
		buf += 6;
		x += 6;
		// Проверим выход за правый край экрана и вернем его
		// в начало следующей строки при необходимости.
		if ( x >= 240 )
		{
			x -= 240;
			buf += 240 * 5;
		};
		text++;
	};
};

// Вывод текста микрошрифта 6x6 в видеорежиме 0x4.
// В связи с тем, что запись в видеопамять должна
// производится 16-битными порциями приходится "паковать"
// соседние пиксели в пары при записи.
void draw4_micro_text( int x, int y, const char *text )
{
	x = x & (~1u); // Координата по X должна быть чётной!
	u16 *buf = VID_BUFFER + x + 120 * y; // Адрес для вывода текущего символа
	char c;
	while ( c = (*text) )
	{
		if ( (c < 32) || (c > 127) )
			c = 127;	// все символы кроме ASCII будут "решеткой"
		c -= 32;
		// находим опорный адрес символа в микрошрифте
		const u8 *base = micro_font + 6 * 6 * c;
		int soffs = 0;
		for ( int l = 0; l < 6; l++ )
		{
			// Выводим строку пикселей пакуя соседние пары в u16 для записи.
			buf[ soffs + 0 ] = (base[ 1 ] << 8) + base[ 0 ];
			buf[ soffs + 1 ] = (base[ 3 ] << 8) + base[ 2 ];
			buf[ soffs + 2 ] = (base[ 5 ] << 8) + base[ 4 ];
			soffs += 120;
			base += 6;
		};
		buf += 3;
		x += 6;
		// Проверим выход за правый край экрана и вернем его
		// в начало следующей строки при необходимости.
		if ( x >= 240 )
		{
			x -= 240;
			buf += 120 * 5;
		};
		text++;
	};
};


Теперь создадим программу, которая:
Выводит FPS.
Может включать/выключать VSync (вкл. — кнопка «A», выкл. — кнопка «B»)
Может залить фон однотонным цветом (вкл. заливку — «L», выкл. — «R»)
Может изменять цвет заливки (кнопками Влево-Вправо).
По нажатию на кнопку Вверх переключает видеорежим на 0x3, а по нажатию на кнопку Вниз — 0x4.
Создаём файл 04_bitmap_modes.cpp и заполняем его следующим кодом:


#include <string.h>
#include "gba_defs.h"

// Просто подключим массив микрошрифта в текущий юнит.
#include "microfont.cpp"

// sprintf оказался настолько тормозным, что возникло искушение
// сделать свою функцию по преобразованию int в строку. 
// Обратите внимание, что для большей простоты в буфере уже дожно
// быть достаточно места слева, т.к. вывод цифр идёт как раз
// справа-налево.
void itostr( char *s, int d )
{
	if ( !d )
	{
		*s-- = '0';
		return;
	};
	while ( d )
	{
		int rem = d % 10;
		d = d / 10;
		*s-- = '0' + rem;
	};
};

// Заливка экрана цветом.
// Для режима 0x4 для скорости заливка происходит двухбайтовыми
// значениями, что приводит к появлению вертикальных полосок.
void fill_screen_by_color( bool mode3, u16 color )
{
	u16 *ptr = VID_BUFFER;
	int vidsize = 240 * 160;
	if ( !mode3 )
		vidsize /= 2; // для 8-битного режима видеообласть вдвое меньше.
	for ( int i = 0; i < vidsize; i++ )
	{
		*ptr++ = color;
	};
};

int main(void)
{
	// Изначально переключаемся в видеорежим 0x3, запоминаем что находимся в нём и
	// для простоты обработки нажатий кнопок вводим флаг необходимости переключения.
	REG_DISPCNT = MODE_3 | BG2_ENABLE;
	bool mode3 = true, need_mode3 = true;

	// 15-битный формат цвета консоли:
	// 0 BBBBB GGGGG RRRRR
	// F EDCBA 98765 43210
	// Инициализируем палитру так, чтобы 8-битный индекс цвета совпадал с цветовой маской XBBGGGRR
	// (X означает "не влияет")
	//  XBB GGG RR
	//  765 432 10
	for ( int i = 0; i < 256; i++ )
	{
		BGR_PALETTE[ i ] = RGB( (i & 3) << 3, i & 28, (i & 96) >> 2 );
	};

	// Включаем 0-ой таймер на частоту 65536 раз в секунду.
	REG_TM0CNT = TIMER_FREQUENCY_256 | TIMER_ENABLE;
	u16 t_last = REG_TM0D;

	char buf[ 64 ];

	u16 color = 63; // Текущий цвет для заливки экрана.
	bool fill_by_color = false; // Заливать экран текущим цветом или нет.
	bool wait_for_vblank = true;	// Делать VSYNC или нет.

	// Бесконечный цикл
	while ( true )
	{
		// Дождёмся выхода в VBLANK
		if ( wait_for_vblank )
		{   
			while ( REG_VCOUNT < 160 );
		};

		// Вычислим время прошедшее с предыдущего чтения таймера
		// и вычислим FPS.
		u16 t_new = REG_TM0D;
		u16 t_diff = t_new - t_last;
		t_last = t_new;
		float t = 0.0;
		if ( t_diff > 0 )
		{
			t = 65536.0f / t_diff;
		};

		// Отобразим время и FPS на экране:
		strcpy( buf, "Diff:                     " );
		itostr( buf + 15, t_diff );
		if ( mode3 )
			draw3_micro_text( 0, 6 * 12, buf );
		else
			draw4_micro_text( 0, 6 * 12, buf );
		strcpy( buf, "FPS:                      " );
		itostr( buf + 15, (int) t );
		if ( mode3 )
			draw3_micro_text( 0, 6 * 13, buf );
		else
			draw4_micro_text( 0, 6 * 13, buf );

		// Считаем текущее состояние кнопок и сразу
		// инвертируем биты, чтобы нажатые стали единицами.
		int keys = ~REG_KEYS;
		// Реагируем на нажатые кнопки.
		if ( keys & KEY_A )
			wait_for_vblank = true;
		if ( keys & KEY_B )
			wait_for_vblank = false;
		if ( keys & KEY_LEFT )
			color--;
		if ( keys & KEY_RIGHT )
			color++;
		if ( keys & KEY_L )
			fill_by_color = true;
		if ( keys & KEY_R )
			fill_by_color = false;
		if ( keys & KEY_UP )
			need_mode3 = true;
		if ( keys & KEY_DOWN )
			need_mode3 = false;

		// Если возникла необходимость переключить видеорежим - делаем это.
		if ( mode3 != need_mode3 )
		{
			// Переключить видеорежим в 0x3 или 0x4.
			mode3 = need_mode3;
			if ( mode3 )
				REG_DISPCNT = MODE_3 | BG2_ENABLE;
			else
				REG_DISPCNT = MODE_4 | BG2_ENABLE;
			// Очистим экран после переключения
			fill_screen_by_color( mode3, 0 );
		};

		// Если нужно - зальём видеопамять цветом заливки.
		if ( fill_by_color )
		{
			fill_screen_by_color( mode3, color );
		}

		// Доводим синхронизацию по VLANK до конца.
		if ( wait_for_vblank )
		{   
			while ( REG_VCOUNT >= 160 );
		};
	};

	return 0;
}


Далее создаём файл build_04_bitmap_modes.bat:

@SET MODULES=
@set PROGNAME=04_bitmap_modes

@call build_gba.bat

Если нигде не допущено ошибок, то должен появится файл 04_bitmap_modes.gba запустив который мы можем наглядно увидеть, что пиксельные видеорежимы 16-мегагерцовым ARM-ом GBA заливаются довольно медленно и их реальное применение в играх очень сильно ограничено. Видеоадаптер больше не может нам с ними ничем помочь — нет аппаратного ускорения блиттинга, как, например, в DirectDraw.
Поэтому по настоящему раскрывается консоль в тайловых видеорежимах, которые по сути являются аппаратным ускорением двумерной графики. Следующая часть будет про них.
Однако есть один забавный момент, который нельзя не отметить в этой новой редакции статьи — в следующих уже главах я обнаружу, что использование вещественных чисел (которая на GBA реализуется программной эмуляцией) насколько сильно роняет производительность даже в примитивных вещах, что даже просто подсчёт fps с их помощью в данном уроке должен сильно исказить достоверный результат — поэтому истинную картину предлагаю вам восстановить самостоятельно.

Продолжение...

4 комментария

avatar
можем наглядно увидеть, что пиксельные видеорежимы 16-мегагерцовым ARM-ом GBA заливаются довольно медленно и их реальное применение в играх очень сильно ограничено

Что-то здесь не то. Такой арм, навскидку, должен в кадре успевать залить такой маленький экранчик несколько раз. А тут либо компилятор сосёт, либо дикие задержки доступа к видеопамяти. Во всяком случае, причина явно не в 16 мегагерцах.
avatar
Когда я дошёл до вращающихся фонов и спрайтов, то обнаружил, что вычисление двух sincos не пролазит в стабильные 60 кадров в секунду. Вещественными лучше вообще не пользоваться и картинка должна несколько улучшится. Но в любом случае — например Doom на этой платформе шевелится еле-еле в ужасном качестве.
avatar
Ну естественно, вещественными лучше не пользоваться, они ж там программные. Не пойму, правда, какая связь sincos и заливки. Как пример, вот на что способен был ARM2 8мгц в двухмерных игрушках без какой-либо аппаратной помощи:
www.youtube.com/watch?v=t4hfPKWM4Mk

Doom в уменьшенном примерно до gba-шного размера окошке сносно шевелился на 386DX40. По моему опыту, уже самые первые армы примерно в 2+ раза эффективней по тактам были. Так что в «ужасном качестве» я склонен виноватить кривые ручки (программистов Дума, компилятора, или разработчиков железа геймбоя). В архимедовских демах, вон, даже воксельный ландшафт бодро бегал:
www.youtube.com/watch?v=bLdpCIfOqmw (с 17:50)
avatar
Проблема теста из этой главы в том, что он использует вещественное деление чтобы вычислить фпс, а это на данной платформе чрезмерно щедрый шаг, могущий это самое фпс уронить. Насколько — мне уже правда неинтересно, ибо 3Д на этой платформе был как раз ровно в той эпохе (по мощности аппаратуры) когда даже захудалое 2D уделывало даже крутое 3D по эстетике. А 2D здесь разумнее реализовывать через «аппаратно ускоренные» тайловые видеорежимы о которых следующая глава. На GBA реально были 3D-игры в пиксельных видеорежимах, но они были не очень в принципе все.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.