Доброго времени суток, уважаемые подписчики.
Внимание, если в вашем почтовом клиенте не видны рисунки, то откройте страницу из броузера
Сегодня мы продолжим разбираться в структуре команд процессора. Я считаю, следует привести один пример к прошлому уроку:
Такую структуру имеют команды условного перехода и условной пересылки данных. "Условие" может принимать следующие значения:
0000 | o |
0001 | no |
0010 | c/b/nae |
0011 | nc/nb/ae |
0100 | e/z |
0101 | ne/nz |
0110 | be/na |
0111 | nbe/a |
1000 | s |
1001 | ns |
1010 | p/pe |
1011 | np/po |
1100 | l/nge |
1101 | nl/ge |
1110 | le/ng |
1111 | lne/g |
Этот тип команд, как и другие похожие (рассмотренные на прошлом уроке), являются достаточно простыми для раскодировки (простая проверка статической части). Для понятия следующих типов команд, нам нужно понять структуру байта следующего за статической частью команды (так называемый
ModR/M байт). Он содержит три секции,
R/M (register/memory usage, биты 2-0),
R/O (register/opcode, биты 5-3) и
MOD (биты 7-6). Начнём с конца, Mod содержит тип информации байта ModR/M, он принимает следующие значения:
00 | используется адрес без смещения(например [esi]) |
01 | адресация с 8 байтным смещением(например [esi+x], где -128<x<127) |
10 | используется адресация с полным смещением(например [esi+x]) |
11 | R/M содержит код регистра |
Поле R/O содержит либо дополнительные три бита статической команды, либо код регистра.
Поле R/M может содержать следующие значения:
код | 16 бит | 32 бита |
000 | [bx+si] | [eax] |
001 | [bx+di] | [ecx] |
010 | [bp+si] | [edx] |
011 | [bp+di] | [ebx] |
100 | [si] | используется SIB |
101 | [di] | [ebp] |
110 | [bp] | [esi] |
111 | [bx] | [edi] |
Байт SIB, если он нужен, находится сразу за ModR/M, он является расширением ModR/M и появляется только при 32-битной адресации. Так как он не представляет никакого интереса с точки зрения идентификации команды, его мы рассмотрим позже. Как вы могли догадаться, я только что объяснил вам строение очередного типа команды (один или больше байт команды и описание адресации). Всё это хорошо и легко понятно, но, к сожалению, это не всё. Следующий тип команд, на мой взгляд, самый странный. Вначале приведу пару примеров:
Команда | код |
adc eax,5 | 83 D0 05 |
add ecx,5 | 83 C1 05 |
and edx,5 | 83 E2 05 |
cmp ebx,5 | 83 FB 05 | |
or esi,5 | 83 CE 05 |
sbb edi,5 | 83 DF 05 |
sub ebp,5 | 83 ED 05 |
xor esp,5 | 83 F4 05 |
Посмотрите, выходит у команд одинаковый статический код?! Как же тогда компьютер определяет что ему делать с регистром? В этом случае биты 5-3 байта ModR/M (секция R/O). Это означает, что даже при одинаковой части "кода" статический код может отличаться:
В принципе остальные команды отличаются лишь длинной статического кода, поэтому я думаю следует приступить к следующему шагу, разработке алгоритма декодировки команд.. Этим и займёмся в следующем уроке.
А теперь вернёмся к проекту игры. Следующим шагом после создания окна должно быть создание фигур в окне. Так как мы будем работать с числами с плавающей запятой, то нам может пригодиться следующий файл констант:
_1 equ 03f800000h
_2 equ 040000000h
_3 equ 040400000h
_4 equ 040800000h
_5 equ 040a00000h
_6 equ 040c00000h
_7 equ 040e00000h
_8 equ 041000000h
_9 equ 041100000h
_10 equ 041200000h
_11 equ 041300000h
_12 equ 041400000h
_m1 equ 0bf800000h
_m2 equ 0c0000000h
_m3 equ 0c0400000h
_m4 equ 0c0800000h
_m5 equ 0c0a00000h
_m6 equ 0c0c00000h
_m7 equ 0c0e00000h
_m8 equ 0c1000000h
_m9 equ 0c1100000h
_m10 equ 0c1200000h
_m11 equ 0c1300000h
_m12 equ 0c1400000h
|
То есть если мы хотим передать функции OpenGL определённый числовой параметр, то, так как в большинстве случаев параметр должен быть числом с плавающей запятой, мы будем должны знать заранее, какое значение имеет определённое число... Но вернёмся к выводу объектов на экран OpenGL. Создание объекта в OpenGL происходит следующим образом:
- вызываем функцию glBegin, передавая её код того, что мы хотим нарисовать
- с помощью функций glVertex**(v) задаём вершины объекта
- для завершения рисования объекта вызываем glEnd
Функция glBegin поддерживает следующие параметры:
GL_POINTS | Рисует точки |
GL_LINES | Линии |
GL_LINE_STRIP | Рисует несколько соединённых линий |
GL_LINE_LOOP | Рисует несколько соединённых линий, последняя точка соединяется с первой |
GL_TRIANGLES | Рисует треугольники |
GL_TRIANGLES_STRIP | Рисует несколько треугольников так, что каждые два имеют одну общую сторону |
GL_TRIANGLE_FAN | Рисует несколько треугольников с общей вершиной |
GL_QUADS | Рисует квадраты |
GL_QUAD_STRIP | Рисует несколько квадратов так, что каждые два имеют общую сторону |
GL_POLYGON | Рисует полигон, то же что и GL_LINE_LOOP, только заполнен изнутри |
Функция, а вернее функции, glVertex**(v) имеет достаточно интересный синтаксис и её можно записать как glVertex
XTV, где "X" может принимать значения от 2 до 4, "T" может принимать несколько буквенных значений, а "V" всегда имеет значение 'v', но её присутствие необязательно. Что же всё это значит?! Дело в том, что для облегчения использования OpenGL работает с множеством типов данных, тип данных задаётся переменной "T" и может принимать следующие значение:
d | double | qword* |
f | float | dword* |
i | int | dword |
s | short | byte |
* - числа с плавающей запятой
"Х" - определяет кол-во указанных осей, а "V" указывает, передаются переменные или лишь указатель на переменные.
Наиболее разумно вставлять функции создания объектов в нашу процедуру DrawGLWindow (смотри прошлый урок). Нарисуем обычный треугольник:
DrawGLScene proc
push esi
null esi
run glClear, GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT
run glLoadIdentity
run glTranslatef, esi, esi, _m5
run glBegin, GL_TRIANGLES
run glVertex3f, _m1, _m1, esi
run glVertex3f, esi, _1, esi
run glVertex3f, _1, _m1, esi
run glEnd
run glLoadIdentity
pop esi
ret
DrawGLScene endp
|
Чтоб всё это работало правильно следует добавить обработку сообщения
WM_SIZE в нашей процедуре окна, то есть следует дописать следующее:
...
mov eax,[ebp+0ch]
cmp eax,WM_SIZE
je size_proc
cmp eax,WM_DESTROY
...
jmp short Pass_Message
size_proc:
mov eax,[ebp+14h]
mov ecx,eax
cwde
shr ecx,16
mov width_,eax
mov height_,ecx
run ReSizeGLScene
key_proc:
...
|
Ассемблерный код можно скачать
здесь, а откомпилированную программу
здесь.
На сегодня это всё. Если есть какие вопросы, пишите. Пишите на Dark_Lord@RusFAQ.ru или Dark_Lord@land.ru.
Или свяжитесь со мной по ICQ, мой номер 126222874!