Как графика ЧИП 8 отображается на экране?
Код операции DXYN: рисует спрайт с координатами (VX, VY) шириной 8 пикселей и высотой N пикселей. Каждая строка из 8 пикселей читается как битовая кодировка (причем старший бит каждого байта отображается слева), начиная с ячейки памяти I; Значение не меняется после выполнения этой инструкции. Как описано выше, VF устанавливается в 1, если какие-либо пиксели экрана переключаются из установленного в неустановленное при рисовании спрайта, и в 0, если этого не происходит.
По сути, у меня есть массив с именем graphics, который представляет собой двойной массив, построенный из 64 строк новых массивов в каждом с 32 столбцами.
//Creating new double arrays for storing graphics data
graphics = new Array(GFX_WIDTH);
for(var i = 0; i < graphics .length; i++){
graphics [i] = new Array(GFX_HEIGHT);
for(var j = 0; j < graphics [i].length; j++){
graphics [i][j] = 0;
}
}
и внутри этих массивов я храню графические данные, как описано выше. Мой вопрос заключается в том, должен ли я просто нарисовать квадрат, когда элемент массива равен 1, и очистить это пространство, когда он равен 0? Согласно статье в блоге на CHIP8, есть дополнительный массив для набора шрифтов, но как его использовать?
Статья в блоге, которую я упомянул выше
http://www.multigesture.net/articles/how-to-write-an-emulator-chip-8-interpreter/
Спасибо.
1 ответ
Прежде всего, обратите внимание, что пиксели упакованы битом - каждый байт будет содержать 8 пикселей данных спрайта. Другими словами, байт 0xAA является спрайтом высотой в один пиксель с набором первого, третьего, пятого и седьмого пикселей.
При рисовании вашего спрайта, вам нужно перебирать каждый бит. Если бит установлен, вы переворачиваете соответствующий бит на вашем дисплее - 0 становится 1, а 1 становится 0. Это, например, можно сделать, применив операцию XOR (^) к вашему байту дисплея.
Тем не менее, обратите внимание, что VF должен быть установлен в 1, если какие-либо пиксели в процессе обрабатываются от 1 до 0, и 0, если ни один из пикселей не сброшен - так что вам также нужно сделать это. Я считаю, что легче всего читать, если у вас есть if, который проверяет, переворачивать или нет, а затем позаботиться о переключении и VF-обновлении внутри этого if.
Для справки, моя собственная реализация этого кода для Delphi выглядит так:
procedure TChip8CPU.OpcodeD(inst: TInstruction);
var
X, Y, cX, cY, data: byte;
begin
Reg[$F] := 0;
for Y := 0 to inst.NibbleArg - 1 do begin
cY := (Reg[inst.Y] + Y) mod HEIGHT;
data := Memory[AddressI + Y];
for X := 0 to 7 do begin
if (data and ($80 shr X)) <> 0 then begin
cX := (Reg[inst.X] + X) mod WIDTH;
if Display[cY, cX] = 1 then Reg[$F] := 1;
Display[cY, cX] := Display[cY, cX] xor 1;
end;
end;
end;
end;
Обратите внимание, что для спрайтов, которые выходят за границы экрана, они оборачиваются (это делается mod WIDTH
/mod HEIGHT
части). Это упоминается в техническом справочнике Cowgod's Chip-8.