- •Московский институт электронной техники
- •!!!! Замечание.
- •Введение.
- •Графические вставки из bmp-файлов в dos программах.
- •Графические вставки из bmp-файлов в win программах.
- •Графические вставки из bmp-файлов в dos программах в режиме работы с видеостраницами.
- •Графические вставки из bmp-файлов в win программах в режиме работы с оперативной памятью.
- •Перемещение по экрану графических вставок из bmp-файлов в dos программах.
- •Перемещение по экрану графических вставок из bmp-файлов в win программах. Использование двух контекстов памяти.
- •Использование набора bmp-файлов для создания эффекта движения. Чтение bmp-файлов из ресурсов программы.
- •Использование набора bmp-файлов для создания эффекта движения. Загрузка bmp-файлов в контекст памяти.
- •Задание к выполнению работы.
Графические вставки из bmp-файлов в dos программах в режиме работы с видеостраницами.
Как мы знаем, в задачах анимации работа программы становится более качественной, если использовать режим видеостраниц. Пока первая фаза движения изображена на первой видеостранице, вторая фаза движения рисуется на второй видеостранице. После некоторой задержки изображение второй видеостранице выбрасывается на экран, а следующая фаза движения рисуется снова на первой видеостранице. Затем процесс периодически повторяется.
Чтобы картину, полученную из bmp-файла выводить то на одну то на другую видеостраницу, необходимо эту картину где-то хранить. Для хранения будем использовать оперативную память.
Здесь возникает определенная трудность, связанная с сегментацией оперативной памяти в DOS. Программа, работающая вDOS, может использовать оперативную память только определенными порциями, блоками в 64 килобайта. Оказывается, что для больших картин, все изображение может не поместиться в блоке в 64 килобайта. Поэтому надо предусмотреть ситуацию, когда изображение изbmp-файла будет храниться в нескольких отдельных блоках оперативной памяти.
Код программы, которая поместит изображение в оперативную память по блочно, будет это изображение выводить на экран в нужный момент, и в конце работы очистит оперативную память, лучше всего организовать в виде класса.
Поместим этот код в класс ScreenMemory, и пусть этот класс находится в файлеclassmem.cpp. Ниже приводится определение этого класса.
//класс для чтения изображения с экрана в оперативную память
//и затем вывода этого изображения на экран
class ScreenMemory
{
public:
int xBlk, yBlk;
//конструктор
ScreenMemory(int hx0, int hy0, int x1, int y1, int x2, int y2);
void ViewScreen(); //выводим изображение на экран
~ScreenMemory(); //деструктор
private:
int *xp, *yp;
void ***saucer;
int *hx, *hy;
double **size;
};
//конструктор, копирует часть изображения с экрана в
//оперативную память по блочно
//hx0, hy0 - размеры блоков для записи изображения в память
//x1,y1,x2,y2 - размеры копируемой части изображения на экране
ScreenMemory::ScreenMemory(int hx0, int hy0,
int x1, int y1, int x2, int y2)
{
xBlk = (x2 - x1)/hx0;
yBlk = (y2 - y1)/hy0;
//если выбранные блоки не полностью покрывают изображение на экране
//то вводятся дополнительные блоки с размерами dxBlk, dyBlk
int dxBlk = (x2 - x1) - xBlk*hx0;
int dyBlk = (y2 - y1) - yBlk*hy0;
int xflag = 0, yflag = 0;
//находим число блоков полностью закрывающих экран
if(dxBlk>0)
{
xBlk++; xflag = 1;
}
if(dyBlk>0)
{
yBlk++; yflag = 1;
}
//выделяем память под массив шагов между блоками по горизонтали
hx = new int[xBlk];
if(hx == NULL)
{
closegraph();
printf("Error of allocation of memory - hx");
exit(1);
}
//выделяем память под массив шагов между блоками по вертикали
hy = new int[yBlk];
if(hy == NULL)
{
closegraph();
printf("Error of allocation of memory - hy");
exit(1);
}
//вычисляем массив шагов между блоками по горизонтали
for(int i=0; i<xBlk; i++)
{
if((xflag == 1) && (i == xBlk-1))
hx[i] = dxBlk;
else
hx[i] = hx0;
}
//вычисляем массив шагов между блоками по вертикали
for(int j=0; j<yBlk; j++)
{
if((yflag == 1) && (j == yBlk-1))
hy[j] = dyBlk;
else
hy[j] = hy0;
}
//выделяем память под массив узловых точек между блоками по горизонтали
xp = new int[xBlk+1];
if(xp == NULL)
{
closegraph();
printf("Error of allocation of memory - xp");
exit(1);
}
//выделяем память под массив узловых точек между блоками по вертикали
yp = new int[yBlk+1];
if(yp == NULL)
{
closegraph();
printf("Error of allocation of memory - yp");
exit(1);
}
//вычисляем массив узловых точек между блоками по горизонтали
xp[0] = x1;
for( i=1; i<=xBlk; i++)
xp[i] = xp[i-1] + hx[i-1];
//вычисляем массив узловых точек между блоками по вертикали
yp[0] = y1;
for( j=1; j<=yBlk; j++)
yp[j] = yp[j-1] + hy[j-1];
//выделяем память под двойной массив размеров блоков
size = new double* [xBlk];
if(size == NULL)
{
closegraph();
printf("Error of allocation of memory -size");
exit(1);
}
for(i=0; i<xBlk; i++)
{
size[i] = new double[yBlk];
if(size[i] == NULL)
{
closegraph();
printf("Error of allocation of memory -size");
exit(1);
}
}
//выделяем память под двойной массив указателей адресов блоков
saucer = new void** [xBlk];
if(saucer == NULL)
{
closegraph();
printf("Error of allocation of memory -*sauser");
exit(1);
}
for(i=0; i<xBlk; i++)
{
saucer[i] = new void* [yBlk];
if(saucer[i] == NULL)
{
closegraph();
printf("Error of allocation of memory -*sauser");
exit(1);
}
}
for( j=0; j<yBlk; j++)
for(int i=0; i<xBlk; i++)
{
//вычисляем размер блока [i][j]
size[i][j] = imagesize(xp[i], yp[j], xp[i+1],yp[j+1]);
//выделяем память под блок [i][j]
saucer[i][j] = new [size[i][j]];
if(saucer[i][j] == NULL)
{
closegraph();
printf("Error of allocation of memory - saucer[i][j]");
exit(1);
}
//копируем блок изображения в блок памяти
getimage(xp[i], yp[j], xp[i+1],yp[j+1], saucer[i][j]);
}
}
//функция выводит изображение из памяти на экран по блочно
void ScreenMemory::ViewScreen()
{
for(int j=0; j<yBlk; j++)
for( int i=0; i<xBlk; i++)
{
putimage(xp[i], yp[j], saucer[i][j], COPY_PUT);
}
}
//деструктор, освобождает выделенную память
ScreenMemory::~ScreenMemory()
{
//освобождаем память, занятую блоками [i][j]
for(int j=0; j<yBlk; j++)
for( int i=0; i<xBlk; i++)
delete saucer[i][j];
//освобождаем память, занятую массивами hx[] hy[]
delete [] hx;
delete [] hy;
//освобождаем память, занятую массивами xp[] yp[]
delete [] xp;
delete [] yp;
//освобождаем память, занятую массивом size[][]
for(int i=0; i<xBlk; i++)
delete [] size[i];
delete [] size;
//освобождаем память, занятую массивом saucer[][]
for(i=0; i<xBlk; i++)
delete [] saucer[i];
delete [] saucer;
}
Возьмем, за основу, программу mov05DOS.cpp, В этой программе моделируется движение самолета и вращающейся стрелки. Уберем стрелку, уберем фон в виде зеленого эллипса. В качестве фона будем использовать картину зеленого поля и голубого неба изbmp-файлаfield_16.bmp. Новую программу назовемmov08DOS.cpp.
В заголовке файла добавим две строчки.
#include "view.cpp"
#include "classmem.cpp"
В главной функции main() добавим следующую строчку вызова функцииViewBMP().
ViewBMP("field_16.bmp");
Уберем строчки вызова стрелки, траектории стрелки, фона.
Далее создадим объект класса ScreenMemory.
//копируем часть изображения в оперативную память по блокам 300x200
ScreenMemory ScMem(300,200,0,0,630,326);
Вызываем функцию ViewScreen()для объекта ScMem.
//копируем изображение из памяти на экран
ScMem.ViewScreen();
Компилируем, запускаем программу mov08DOS.exe, и результат работы этой программы показан на Рис.36.
Рис. 36.
Результат работы программы mov08DOS.cpp.