«Чтение» графического экрана в сборке 13ч в режиме - PullRequest
0 голосов
/ 22 мая 2018

Есть ли способ «прочитать» экран режима 13h в сборке (emu8086)?

Что я хочу сделать, это нарисовать фигуру в режиме 13h (в цвете A), а затем попросить пользователяпопытайтесь проследить это (в цвете B), эффективно перерисовывая другие пиксели.После этого я хочу «прочитать» экран, чтобы проверить, сколько пикселей в цвете А присутствуют.Предполагая, что пользователь выполнил приличное отслеживание работы, в большинстве случаев будет меньше пикселей A-цвета, чем пикселей моей исходной формы, благодаря этой метрике я получу оценку пользователя.

Есть ли способ проверить экран на наличие цветных пикселейИли вы предлагаете другой способ достижения цели «сравнения» следов.

Заранее спасибо.

1 Ответ

0 голосов
/ 22 мая 2018

13-часовой режим VGA в реальном режиме 16b (BIOS / DOS) имеет видеопамять, расположенную по адресу A000:0000, не стесняйтесь читать / писать по своему усмотрению.

Также вам нужен более сложный алгоритм длявыигрыш, потому что просто отслеживание количества «A» не скажет вам, сколько пользователь пролил «B» на другие области (то есть, пользователь, просто заполнивший весь экран B, выиграет, потому что A = 0).

Пример манипуляции с видео-плунжером в 13-часовом режиме VGA (синтаксис TASM):

;filename: so_13h.asm
.model small
.code
start:
    mov  ax,13h     ; ah = 0 set mode, al = 13h 320x200 256col mode
    int  10h        ; set gfx mode
    push 0A000h
    pop  es         ; es = A000 (video ram segment)
    ; fill video ram with some pattern
    xor  di,di
    mov  bp,200
lines_loop:
    mov  dx,64
    mov  ax,1010h
shade_loop:
    stosw           ; write 5 pixels
    stosw
    stosb
    ; modify colours to create sort of "dither" pattern
    xchg al,ah
    inc  ah
    dec  dx
    jnz  shade_loop ; write 320 pixels with different shades
    ; write 200 lines
    dec  bp
    jnz  lines_loop
    ; read pixel back example
    mov  di,(13*320 + 56) ; read pixel from [x, y] = [56, 13]
    mov  al,es:[di]
    ; here AL = 16h (colour of pixel at [56, 13] position)
    ; wait for any key
    xor  ax,ax
    int  16h
    ; restore text mode
    mov  ax,3       ; ah = 0, al = 3 (text mode 80x25)
    int  10h
    ; terminate code
    mov  ah,4Ch
    int  21h
end start

Для сборки + запуска под dosbox я использовал:

tasm so_13h.asm
tlink /x so_13h.obj
so_13h.exe

edit: есть также BIOSсервис для int 10h «Чтение пикселя графики в координатах» :

ввод:

AH = 0D
BH = page number, see VIDEO PAGES
CX = column number (zero based)
DX = row number (zero based)

при возврате:

AL = color of pixel read

Но, как правило, службы BIOS работают очень медленно из-за снижения производительности самого вызова int, плюс BIOS должен снова вычислить смещение каждого пикселя с нуля, в то время как, например, ваше "отслеживание оценки" может использовать некоторые "ожидаемые"экран "буфер" для сравнения пикселей последовательно повторное использование выключенныхи т. д. из предыдущего, чтобы перейти к следующему, избегая излишних вычислений.

Поэтому вы должны попытаться создать нечто похожее на способ заполнения экрана в примере, обрабатывая пиксели в «пакетном режиме».

Даже чтение, оптимизированное для слова (два пикселя) по сравнению с байтом (один пиксель), помогло на реальном HW в эпоху 386 года, но это, вероятно, слишком усложняет вашу задачу, JFYI, что даже такие тонкие детали имели значение тогда.


edit2: об алгоритме подсчета очков:

Зависит от того, как именно вы хотите забить, но вы можете сделать это:

  • имеют оригинальное "A"буфер в памяти
  • рассчитать количество «A» на экране = toPaint
  • позволить пользователю рисовать с «B»
  • вычислить количество «A» на экране = notPaint
  • вычислить «B» из экрана над «0» в буфере = overPaintL1
  • повторно запустить внутри внутреннего буфера [0,0] .. [maxX-2,, maxY-2] и изменитькаждый пиксель в «А», если есть «А» на правой или нижней стороне текущего рixel = это сделает форму "A" более толстой (возможно, будет выполнена дважды в два раза, чтобы перекрыть + -2 или + -3 пикселя)
  • вычислить "B" над 0 в буфере = overPaintL2
  • сделать "A" еще раз толще
  • вычислить "B" над 0 в буфере = overPaintL3

Теперь итоговый результат может быть примерно таким:

счет = w0* (toPaint - notPaint) + w1 * overPaintL1 + w2 * overPaintL2 + w3 * overPaintL3

, где w0..w3 - «веса» бонуса / малуса, w0 должен быть самым сильным, так как это количество пикселей-безупречно пользователь рисовал (например, 50 ... также каждый пропущенный пиксель равен -50), w1 должен быть очень маленьким мальчиком, например -1 (это только 1 пиксель), w2 может быть что-то вроде -5 (2 пикселя)off), w3 может быть что-то вроде -10 (пиксели полностью не соответствуют форме).

Так что, если пользователь имеет форму ~ 200 пикселей (квадрат 50x50 пикселей), и он переопределяет 184 пикселя: notPaint = 16и в основном поражает почти везде + -1 пиксель (создавая квадрат шириной 2 пикселя): overPaintL1 = 200 и сомВременами он уходит немного дальше: overPaintL2 = 15, overPaintL3 = 35

Затем оценка = 50 * (200-16) + -1 * 200 + -5 * 15 + -10 * 35 = 8575 (идеально)в этом примере оценка составляет 50 * 200 = 10000).

Может быть, вам нужно будет перенастроить веса и сгущения, но я думаю, что этот подход может сработать в конце.


edit: еще одно замечание о сгущении ... вы должны сгущать во всех направлениях одинаково, чтобы сделать перерасход "B" дорогостоящим в каждом направлении в равной степени, поэтому моя первоначальная проверка справа / снизу не действительна, но выполняется в 4-х направленияхпроверка в одном буфере тоже невозможна.Так что либо вам нужно будет ввести второй внутренний буфер, сгущаясь от одного к другому, либо выполнить двухпроходное сгущение, сначала идущее вперед и расширяющееся вправо + внизу, второе идущее назад и расширяющееся влево + вверх, либо вы можете рисовать форму с помощью "A "во внутренний буфер в позициях [-N .. + N, -N .. + N], чтобы охватить + -N пикселей вокруг оригинального дизайна.

Вероятно, проще всего кодировать обнаружение двух "буферов" в любой сетке 3x3 в исходном буфере для текущей позиции назначения.

Мое первоначальное описание сгущало форму A только в направлении слева + сверху, поэтомуоверрейд внизу / справа будет более наказуемым, чем оверрейд слева / вверху.

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

...