PDA

Просмотр полной версии : Мыcли о видео-режимах Апогея.



vinxru
14.12.2012, 16:27
Как таковых видеорежимов у Апогея нет. Есть несколько изменяемых параметров видеоадаптера (микросхем КР580ВГ75/i8275 и КР580ВТ57/i8257) и специальные символы обозначающие конец строки и конец кадра. Но в итоге вариантов настройки видеоадаптера очень-очень много. Это всё позволяет реализовать плавную прокрутку, гигаскрин, складывать экран из двух различных областей памяти.

Если каждое сочетание выделить в видеорежим, то получится несчетное количество вариантов. Но я все таки попробовал выделить основные и написал простую библиотеку под это дело. Я долго искал, что же оставить. Хотелось с одной стороны быть последовательным, а с другой показать наиболее интересные режимы.

И я начал с самого простого.

Текстовые режимы 64x25 (совместимые с BIOS)

apogeyScreen0() Стандартный режим 64x25 символов, шрифт с межстрочным отступом, то есть графика будет распадаться на линии, атрибуты рассматриваются как пробелы.

apogeyScreen0b() Аналогичен прошлому, но в нем используются скрытые атрибуты. Что бы из за скрытых атрибутов не съезжала графика, конец каждой строки содержит значение EOL. В этом режиме каждая строка имеет запас в 5 байт. То есть допускается 0..5 изменений цвета на строку.

apogeyScreen1() Аналогичен apogeyScreen0, но отключен межстрочный интервал. Частота кадров увеличилась с ~50Гц до ~60Гц. Этот режим для ленивых людей, которые хотят получить слитную псевдографику.

apogeyScreen1b() Аналогичен прошлому, но в нем используются скрытые атрибуты и используется EOL. Так же допускается 0..5 изменений цвета на строку.

Текстовые режимы 64x31 (не совместимые с BIOS)

Все режимы ниже используют технологию экономии памяти. Изображение генерируемое видеоадаптером Апогея не может целиком отображено на экране монитора или телевизора. Края изображения находятся за краями экрана. Поэтому программисты используют только центральную часть экрана. А остальная видеопамять пропадает.

Но видеоадаптер позволяет частично сэкономить на невидимых участках. Длина строки может быть сокращена до 1 байта, если в конце строки будет находится символ КОНЕЦ СТРОКИ (EOL). Таким же образом можно сэкономить на правой невидимой части экрана, используя EOL. А вместо нижних строк можно вообще указать символ КОНЕЦ КАДРА (реально он называется СТОП ПДП).

Но эти режимы не совместимы с BIOS.

Режим экономии сильно мешает реализовать плавную прокрутку.

Во всех режимах ниже межстрочный интервал отключен.

apogeyScreen2a() Режим 64x31 символов. Атрибуты рассматриваются как пробелы. Используется стандартная видеопамять.

Во всех режимах ниже в качестве видеопамяти используется верхушка основного ОЗУ.

apogeyScreen2b() Режим 64x31 символов. Используются скрытые атрибуты и EOL. Допускается 0..5 изменений цвета на строку.

apogeyScreen2с() Режим 64x31 символов. Используются скрытые атрибуты. Строка всегда должна содержать 16 атрибутов. То есть допускается 16 изменений цвета на строку и атрибуты необходимо размещать даже если смена цвета не нужна. Для удобства программирования можно разместить 16 атрибут равномерно по экрану, то есть управлять цветом 4-ок символов.

16 атрибут на строку - это максимум видеоадаптера, включая символ EOL. Но даже если бы мы использовали 15 атрибут на строку, то разместить EOL было бы все равно не возможно. Строка изображения должна быть 69 видимых символов (с учетом EOL и 8 невидимых символов слева). То есть строка без атрибутов не может быть больше 69 байт. Когда мы добавляем в эту строку 15 атрибутов, то получаем всего 54 видимых символа. То есть справа у нас будет 10 пробелов.

Поэтому и рождается 2 основных варианта функций B и C. Переменное кол-во атрибутов, максимум атрибутов. Но пользователь может создать свой режим. Как это сделать описано ниже.

Псевдографические режимы 192x102 (не совместимые с BIOS)

Во всех режимах ниже используется альтернативный знакогенератор, который позволяет реализовать псевдографический режим 192x102. Букв этот знакогенератор не содержит. Но зато содержит некоторые варианты символов, позволяющих получить псевдографическое разрешение 384x204.

apogeyScreen3a() Режим 64x51 символов. Атрибуты рассматриваются как пробелы.

apogeyScreen3b() Режим 64x51 символов. Используется скрытые атрибуты и EOL. Допускается 0..5 изменений цвета на строку.

apogeyScreen3с() Режим 64x51 символов. Используются скрытые атрибуты. Строка всегда должна содержать 16 атрибутов. То есть допускается 16 изменений цвета на строку и атрибуты необходимо размещать даже если смена цвета не нужна. Для удобства программирования можно разместить 16 атрибут равномерно по экрану, то есть управлять цветом 4-ок символов.

Собственные режимы

Все эти режимы закодированы двумя функциями (макросами) с 9-ю параметрами. Пользователь может настроить свой режим:



void apogeyScreen0() {
// MEM_ADDR, FULL_HEIGHT, HEIGHT, TOP_INVISIBLE, FONT, BPL, FILL_EOL, HIDDEN_ATTRIB, CHAR_GEN
APOGEY_SCREEN_STD(0xE1D0, 30, 25, 3, 0x99, 78, 0, 0, 0);
}

...

void apogeyScreen2a() {
// MEM_ADDR, FULL_HEIGHT, HEIGHT, TOP_INVISIBLE, FONT, BPL, FILL_EOL, HIDDEN_ATTRIB, CHAR_GEN
APOGEY_SCREEN_ECONOMY(0xE1D0, 37, 31, 3, 0x77, 75, 1, 0, 0);
}

...

void apogeyScreen3c() {
// MEM_ADDR, FULL_HEIGHT, HEIGHT, TOP_INVISIBLE, FONT, BPL, FILL_EOL, HIDDEN_ATTRIB, CHAR_GEN
APOGEY_SCREEN_ECONOMY(0xE0FF - 7*2 - 94*51 - 2, 64, 51, 7, 0x33, 94, 0, 1, 1);
}


Сами же функции (точнее макросы) выглядят так:



#define APOGEY_SCREEN_ECONOMY(MEM_ADDR, FULL_HEIGHT, HEIGHT, TOP_INVISIBLE, FONT, BPL, FILL_EOL, HIDDEN_ATTRIB, CHAR_GEN) \
register uchar *v; \
uchar i; \
memset((uchar*)MEM_ADDR, 0, (HEIGHT)*(BPL)+(TOP_INVISIBLE)*2+2); \
for(v=(uchar*)(MEM_ADDR)-1, i=TOP_INVISIBLE; i; --i) \
v+=2, *v = 0xF1; \
if(FILL_EOL) \
for(i = HEIGHT; i; --i) \
v += (BPL), *v = 0xF1; \
((uchar*)MEM_ADDR)[(HEIGHT)*(BPL)+(TOP_INVISIBLE)*2+1] = 0xFF; \
apogeyVideoMem = (uchar*)(MEM_ADDR) + (TOP_INVISIBLE)*2 + 8; \
apogeyVideoBpl = (BPL); \
APOGEY_SCREEN_END(MEM_ADDR, FULL_HEIGHT, FONT, (HEIGHT)*(BPL)+(TOP_INVISIBLE)*2+2, HIDDEN_ATTRIB, CHAR_GEN);

#define APOGEY_SCREEN_STD(MEM_ADDR, FULL_HEIGHT, HEIGHT, TOP_INVISIBLE, FONT, BPL, FILL_EOL, HIDDEN_ATTRIB, CHAR_GEN) \
register uchar *v; \
uchar i; \
memset((uchar*)(MEM_ADDR), 0, (FULL_HEIGHT)*(BPL)); \
if(FILL_EOL) { \
v = (uchar*)(MEM_ADDR)-1; \
for(i = FULL_HEIGHT; i; --i) \
{ v += apogeyVideoBpl; *v = 0xF1; } \
} \
apogeyVideoMem = (uchar*)(MEM_ADDR) + (TOP_INVISIBLE)*(BPL) + 8; \
apogeyVideoBpl = (BPL); \
APOGEY_SCREEN_END(MEM_ADDR, FULL_HEIGHT, FONT, (FULL_HEIGHT)*(BPL), HIDDEN_ATTRIB, CHAR_GEN);

#define APOGEY_SCREEN_END(MEM_ADDR, FULL_HEIGHT, FONT, MEM_SIZE, HIDDEN_ATTRIB) \
VG75[1] = 0; \
VG75[0] = 78-1; \
VG75[0] = (FULL_HEIGHT)-1; \
VG75[0] = (FONT); \
VG75[0] = (HIDDEN_ATTRIB) ? 0x93 : 0xD3; \
VT57[8] = 0x80; \
VT57[4] = (uchar)(MEM_ADDR); \
VT57[4] = (uchar)((MEM_ADDR)>>8); \
VT57[5] = (uchar)((MEM_SIZE)-1); \
VT57[5] = 0x40 | (uchar)(((MEM_SIZE)-1)>>8); \
VT57[8] = 0xA4; \
VG75[1] = 0x27; \
if(CHAR_GEN) asm { ei } else asm { di }


Макросы тут использованы потому что мой компилятор не поддерживает inline функции. А если это скомпилировать как обычную функцию, то получается в 5 раз больше кода.

P.S. В этом коде есть неточности, я уже многое поправил.

tnt23
16.12.2012, 11:20
Текстовые режимы 64x25 (совместимые с BIOS)

apogeyScreen0b() ...
apogeyScreen0b() ...

Наверное, в названии первого режима опечатка (лишнее b).

vinxru
16.12.2012, 11:38
ага

Mick
16.12.2012, 11:54
На мой взгляд неудобно выглядит куча функций, которая делает одно и тоже.
Логичнее обозвать один раз функцию как типа apogeyScreen(unsigned char ucScreenMode) где ucScreenMode - собственно передается номер графического режима. А их описать через define. Так по крайней мере обычно в во всяких API делается.

vinxru
16.12.2012, 14:07
На мой взгляд неудобно выглядит куча функций, которая делает одно и тоже.
Логичнее обозвать один раз функцию как типа apogeyScreen(unsigned char ucScreenMode) где ucScreenMode - собственно передается номер графического режима. А их описать через define. Так по крайней мере обычно в во всяких API делается.

#define apogeyScreen(N) \
switch(N) { \
case 0: apogeyScreen0(); break; \
}

Так можно. Причем, с константой на входе это развернется в единственный вызов.