- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания Графика для Windows средствами DirectDraw - Стэн Трухильо
Шрифт:
Интервал:
Закладка:
backsurf->BltFast(curx, cury, cursor, 0, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT);
primsurf->Flip(0, DDFLIP_WAIT);
while (primsurf->GetFlipStatus(DDGFS_ISFLIPDONE)!=DD_OK);
// ничего не делать (ждать, пока закончится
// переключение страниц)
int x, y;
BOOL newclick=FALSE;
int count=mouseclickqueue.GetCount();
while (count--) {
MouseClickData mc=mouseclickqueue.RemoveTail();
if (mc.button==0) {
x=mc.x;
y=mc.y;
newclick=TRUE;
}
}
critsection.Unlock();
//------ Конец синхронизированной секции -------
//------ Сделать паузу в соответствии с выбранной задержкой ----
if (delay_value[dm_index]!=0) Sleep(delay_value[dm_index]);
//------ Обновить меню задержки --------
if (newclick) {
int max_index=sizeof(delay_value)/sizeof(int)-1;
int menux=screen_width-dm_width+dm_margin;
int menuw=dm_width-dm_margin*2;
if (x>=menux && x<=menux+menuw) {
int index=(y-dm_header)/dm_entrysize;
if (index>=0 && index<=max_index && index!=dm_index) {
dm_index=index;
UpdateDelaySurface();
}
}
}
}
Функция DrawScene() состоит из семи этапов:
1. Проверка клавиши Escape.
2. Подготовка нового кадра во вторичном буфере.
3. Обновление курсора (также во вторичном буфере).
4. Переключение страниц.
5. Проверка очереди событий мыши.
6. Проверка очереди событий мыши.
7. Обновление поверхности меню задержки.
Первый этап выполняется функцией GetDeviceState() интерфейса DirectInputDevice. Если будет обнаружено нажатие клавиши Escape, функция посылает сообщение WM_CLOSE, сигнализируя о завершении приложения.
Подготовка вторичного буфера (этап 2) включает его стирание и последующее копирование в него внеэкранной поверхности. Для перебора поверхностей из массива coil используется статическая целая переменная (массив coil подготавливается функцией CustomSurfaces(), которую мы не рассматриваем).
На этапах 3, 4 и 5 программа обращается к ресурсам, используемым потоком ввода, поэтому необходимо воспользоваться критической секцией. Объект класса CCriticalSection (critsection), объявленный в классе CursorWin (см. листинг 7.1), блокируется функцией Lock(). Эта функция пытается получить доступ к критической секции. Если попытка оказывается удачной, функция захватывает критическую секцию и завершается. После этого можно смело работать с совместными ресурсами — поток заведомо обладает монопольным правом доступа к ним. Если функции Lock() будет отказано в доступе (из-за того что критическая секция в данный момент захвачена потоком ввода), функция Lock() блокирует основной поток до освобождения критической секции.
На этапе 3 мы сохраняем содержимое области вторичного буфера, занятой курсором, а затем рисуем курсор в буфере. Обе операции выполняются функцией BltFast() интерфейса DirectDrawSurface.
На этапе 4 выполняется переключение страниц, однако оно происходит сложнее, чем обычно. Это связано с тем, что функция Flip() интерфейса DirectDrawSurface на самом деле не выполняет переключения. Она лишь приказывает видеокарте переключить страницы и после этого завершается. Фактическое переключение страниц происходит после того, как будут закончены все ранее начатые операции блиттинга во вторичный буфер. Для наших целей этого недостаточно. Нам нужно, чтобы переключение страниц было закончено до кода критической секции, потому что в противном случае поток ввода сможет обновить первичную поверхность во время переключения страниц. С помощью цикла while и функции GetFlipStatus() интерфейса DirectDrawSurface мы опрашиваем DirectDraw до тех пор, пока переключение страниц не закончится (в DirectDraw не предусмотрена блокировка по этой операции, но даже если бы она и была, переключение страниц происходит слишком быстро и не оправдывает блокировки потока).
На этапе 5 мы проверяем очередь событий мыши. Элементы извлекаются из очереди, пока она не опустеет. Координаты левой (нулевой) кнопки мыши сохраняются для дальнейшего использования.
На этапе 6 в программе происходит необязательная задержка, выполняемая функцией Sleep() (функция Sleep() блокирует вызвавший поток на заданное количество миллисекунд). Задержка определяется текущей выделенной строкой меню задержек, она имитирует сильную загрузку процессора основным потоком. Например, при воспроизведении сложной трехмерной сцены частота вывода кадров падает. Задержка показывает, что скорость реакции нашего курсора не зависит от частоты генерации кадров.
Этап 6 не требует синхронизации, поэтому мы вызываем функцию CCriticalSection::Unlock(). Если к этому моменту поток ввода был заблокирован и ожидал доступа к своей критической секции, вызов Unlock() позволит ему войти в нее.
На этапе 7 обновляется поверхность меню задержки — хороший пример кода, который следовало бы спрятать в отдельном классе управления меню. Но, как уже говорилось в этой главе, я решил сократить количество функций и классов в этой программе, поэтому большая часть кода осталась «сырой». Так или иначе, на этапе 7 мы проверяем координаты последнего нажатия левой кнопки мыши и в соответствии с ними обновляем меню.
Теперь мы знаем, как происходит обновление экрана в основном потоке. Давайте посмотрим, как работает поток ввода.
Поток вводаЕсли не считать двух вспомогательных функций, весь поток ввода реализован в виде одной функции. Функция MouseThread() приведена в листинге 7.5.
Листинг 7.5. Функция MouseThread()
DWORD CursorWin::MouseThread(LPVOID p) {
TRACE("starting mouse threadn");
CursorWin* win=(CursorWin*)p;
while(TRUE) {
CMultiLock mlock((CSyncObject**)mouse_event, 2);
DWORD event=mlock.Lock(INFINITE, FALSE);
if (event-WAIT_OBJECT_0==quit_event_index) {
TRACE("got quit message: quitting mouse threadn");
return 0;
}
critsection.Lock();
oldcurx=curx;
oldcury=cury;
BOOL buffer_empty=FALSE;
while (!buffer_empty) {
DIDEVICEOBJECTDATA data;
DWORD elements=1;
if (mouse==0) {
TRACE("invalid pointer: quitting mouse threadn");
return 0;
}
HRESULT r=mouse->GetDeviceData(sizeof(data), &data, &elements, 0);
if (r==DI_OK && elements==1) {
static MouseClickData mc;
switch data.dwOfs) {
case DIMOFS_X:
curx+=data.dwData;
break;
case DIMOFS_Y:
cury+=data.dwData;
break;
case DIMOFS_BUTTON0:
if (data.dwData & 0x80) {
mc.x=curx;
mc.y=cury;
mc.button=0;
mouseclickqueue.AddHead(mc);
}
break;
case DIMOFS_BUTTON1:
if (data.dwData & 0x80) {
mc.x=curx;
mc.y=cury;
mc.button=1;
mouseclickqueue.AddHead(mc);
}
break;
}
} else buffer_empty=TRUE;
}
if (curx<0) curx=0;
if (cury<0) cury=0;
if (curx>=screen_width-cursor_width) curx=screen_width-cursor_width-1;
if (cury>=screen_height-cursor_height) cury=screen_height-cursor_height-1;
if (curx==oldcurx && cury==oldcury) {
//----- обновление курсора не требуется ------
goto nevermind;
} else if (abs(curx-oldcurx) >= cursor_width || abs(cury-oldcury) >= cursor_height) {
//----- простой случай: прямоугольники нового
// и старого курсора не перекрываются -----
win->UpdateCursorSimpleCase(curx, cury, oldcurx, oldcury);
} else {
//----- сложный случай: прямоугольники нового
// и старого курсора перекрываются -----
win->UpdateCursorComplexCase(curx, cury, oldcurx, oldcury);
}
nevermind:;
critsection.Unlock();
}
TRACE("leaving mouse threadn");
return 0;
};
Функция MouseThread() имеет один параметр — значение, передаваемое функции AfxBeginThread() при создании потока (см. листинг 7.3). Мы передавали указатель this, поэтому сейчас сможем присвоить его значение указателю на класс CursorWin (переменная win). В функции MouseThread() указатель win будет использоваться для доступа к членам класса CursorWin.
Функция MouseThread() в цикле выполняет блокировку по двум событиям. Класс CMultiLock позволяет блокироваться как по событиям от мыши, так и по событию завершения потока. Фактическая блокировка выполняется функцией CMultiLock::Lock(). По умолчанию функция Lock() блокирует поток до установки всех (в данном случае - двух) заданных событий. Мы изменяем это поведение и передаем FALSE в качестве второго аргумента Lock(), показывая тем самым, что функция должна снимать блокировку при установке хотя бы одного из этих событий.