- •Московский институт электронной техники
- •!!!! Замечание.
- •Введение.
- •Графические вставки из bmp-файлов в dos программах.
- •Графические вставки из bmp-файлов в win программах.
- •Графические вставки из bmp-файлов в dos программах в режиме работы с видеостраницами.
- •Графические вставки из bmp-файлов в win программах в режиме работы с оперативной памятью.
- •Перемещение по экрану графических вставок из bmp-файлов в dos программах.
- •Перемещение по экрану графических вставок из bmp-файлов в win программах. Использование двух контекстов памяти.
- •Использование набора bmp-файлов для создания эффекта движения. Чтение bmp-файлов из ресурсов программы.
- •Использование набора bmp-файлов для создания эффекта движения. Загрузка bmp-файлов в контекст памяти.
- •Задание к выполнению работы.
Графические вставки из bmp-файлов в win программах в режиме работы с оперативной памятью.
Возьмем за основу программу mov05.cpp. В этой программе уберем движение стрелки, уберем фон в виде зеленого эллипса, добавим фон в виде зеленого поля и голубого неба изbmp-файла. Новую программу поместим в файлmov08.cpp. Работа программыmov08.cppбудет во многом похожа на работу программыmov07.cpp. Но будут свои особенности, на которые обратим внимание.
В программе mov05.cppзадержка в движении графических объектов осуществляется с помощью системного таймера. В функцииMove_OnTimer(),которая обрабатывает сообщения от таймера, работа построена следующим образом.
Создается контекст памяти, совместимый с контекстом экрана.
Растровое изображение, в виде битовой караты, загружается из ресурса в память.
Битовая карта связывается с контекстом памяти.
Выполняется рисование графических объектов в памяти на битовой карте. По сути дела рисование происходит на фоне, взятом из bmp-файла.
После этого изображение из контекста памяти копируется в контекст экрана с помощью функции BitBlt().
Затем все повторяется как в программе mov05.cpp. Ниже приводится измененный код функцииMove_OnTimer().
//функция обрабатывает сообщение WM_TIMER
void Move_OnTimer(HWND hwnd)
{
//получаем идентификатор контекста экрана
HDC hdcWin = GetDC(hwnd);
//создаем контекст памяти hdcMem, совместимый с контекстом экрана hdc
HDC hdcMem = CreateCompatibleDC(hdcWin);
//загружаем в память bitmap-ресурс из модуля exe-файла
//hInstApp - идентификатор экзепляра приложения
//"BitmapShip" - идентификатор bitmap-ресурса (в файле ресурсов)
//hBitmap - идентификатор загруженного bitmap-ресурса
HBITMAP hBitmap = LoadBitmap(hInstApp, "BitmapField");
//выбираем bitmap-объект hBitmap в контекст памяти hdcMem
HBITMAP hBitmapOld = (HBITMAP)SelectObject(hdcMem, hBitmap);
tP += dtP;
dtP *= 0.99115;
xP2 = TrajP(tP).x;
yP2 = TrajP(tP).y;
fiP2 =atan2l(yP2-yP1,xP2-xP1);
//рисуем фигуру в точке (x2, y2)
TracP(hdcMem, tP, dtP);
Plain(hdcMem,PtP,7,xP1,yP1,xP2,yP2,fiP1,fiP2,kxP,kyP);
xP1 = xP2; yP1 = yP2; fiP1 = fiP2;
//копируем изображение из контекста памяти hdcMem в контекст экрана hdc
BitBlt(hdcWin, nLeft,mTop, nRight-nLeft, mBottom-mTop, hdcMem, 0, 0, SRCCOPY);
DeleteObject(hBitmap); //убираем растровое изображение из памяти
SelectObject(hdcMem, hBitmapOld); //востанавливаем контекст памяти
DeleteDC(hdcMem); //убираем контекст памяти
ReleaseDC(hwnd,hdcWin); //освобождаем контекст экрана
}
Компилируем, запускаем программу mov08.exe, и результат работы этой программы будет таким же, как и на Рис.35. Правда качество изображения будет несравненно выше. Кроме того, скорость работыWINпрограммы значительно выше, чем уDOSпрограммы.
Рис. 37.
Результат работы программы mov08.cpp.
Перемещение по экрану графических вставок из bmp-файлов в dos программах.
Можно заставить отдельные фрагменты изображения из bmp-файла перемещаться по экрану, создавая различные эффекты анимации. Будем использовать изображение, записанное в оперативную память.
Возьмем за основу программу mov08DOS.cpp. Новую программу назовемmov09DOS. Изображение изbmp-файла разбиваем на небольшие блоки и помещаем в оперативную память. Это можно сделать с помощью конструктора классаScreenMemory. Приведем соответствующую строчку кода.
//копируем изображение в оперативную память по блокам 10x10
ScreenMemory ScMem(10,10,0,0,640,350);
Здесь размер элементарного блока выбран 1010 пикселей. Внизу на условной схеме элементарные блоки памяти это маленькие квадратики. Заметим, что схема расположения блоков в оперативной памяти соответствует расположению изображения на экране.
Теперь берем блок памяти, составленный из нескольких элементарных блоков. На схеме этот блок слева обведен жирной линией. Затем этот блок изображения, надо вывести в какое то место на экране. Новое положение блока изображения показано на схеме в виде прямоугольника, сдвинутого на вектор. Заметим, что новое положение блока не обязано точно ложиться на сетку элементарных блоков.
Для осуществления указанной операции добавим в класс ScreenMemoryеще одну член-функцию (метод класса).
//выводим блок изображение на экран
void ViewScreenLock(int i0, int j0, int nx, int ny, int x, int y);
Здесь i0, j0 – координаты левого верхнего угла, выделенного блока на сетке элементарных блоков. Для случая показанного на схеме эти координаты равныi0=0, j0=1. Далее параметрыnx, ny– это размеры блока по горизонтали и вертикали на сетке элементарных блоков. Для случая показанного на схеме эти размеры равны nx=2, ny=3. Наконец, параметрыx, y– это координаты левого верхнего угла, выделенного блока в новом положении, на растровой сетке. Для случая показанного на схеме эти координаты равныx=52, y=32пикселей.
Ниже приводится код этой функции.
//функция выводит блок изображения из памяти на экран
void ScreenMemory::ViewScreenLock(int i0, int j0,
int nx, int ny, int x, int y)
{
int dx = x - xp[i0], dy = y - yp[j0];
for(int j=j0; j<j0+ny; j++)
for( int i=i0; i<i0+nx; i++)
putimage(dx+xp[i], dy+yp[j], saucer[i][j], COPY_PUT);
}
Для примера будем моделировать движение вагона поезда. Пассажир будет находиться перед открытым окном вагона, за которым проплывают поля.
Поэтому нужно выделить блок растрового изображения размером с окно. Этот блок надо выбирать из разных участков картины и помещать все время в то место экрана, где будет находиться окно. Ниже показан фрагмент кода моделирующего движение растрового изображения за окном.
//копируем блок изображения размером hx,hy из памяти на экран
ScMem.ViewScreenLock(ix,10,hx,hy,xn1,yn1);
ix++;
if(ix+hx>ScMem.xBlk-1)
ix = 0;
Здесь индекс ixбежит по сетке изображения в памяти от левой границы изображения до правой границы изображения. Когда блок изображения добегает до правой границы растрового изображения, то этот блок прыжком переносится к левой границе изображения. Этому соответствует условиеix = 0.
Добавим в программу статический объект – окно вагона. Для этого введем функциюWindowWagon()которая рисует это окно и некоторые детали вагона.
Добавим также динамический объект – занавеску на окне вагона. Занавеска колыхается при движении вагона. Аффинные преобразования над занавеской не совершаются. Просто углы занавески меняют свое положение по определенным законам с течением времени. Движение занавески описывается функциейCurtain().
Ниже приводится код этой функции.
//рисует занавеску по вершинам Pt
void Curtain( Point *Pt, int N, double t)
{
Pt[2].x = PtC0[2].x + 0.5*sin(3*t);
Pt[3].y = PtC0[3].y + 0.7*cos(2.5*t);
Pt[4].x = PtC0[4].x - 0.3*sin(t);
Pt[4].y = PtC0[4].y + 0.3*sin(t);
int Poly[12];
for(int i=0; i<2*N; i++)
if((i % 2) == 0)
Poly[i] = xn(Pt[i/2].x);
else
Poly[i] = ym(Pt[i/2].y);
setlinestyle(SOLID_LINE,0,1);
setcolor(14);
setfillstyle(1, 15);
fillpoly(N,Poly);
moveto(xn(Pt[0].x),ym(Pt[0].y));
lineto(xn(Pt[3].x),ym(Pt[3].y));
}
Компилируем, запускаем программу mov09DOS.exe, и результат работы этой программы показан на Рис.38.
Рис. 38.
Результат работы программы mov09DOS.cpp.