Студопедия — Управляемая анимация изображения
Студопедия Главная Случайная страница Обратная связь

Разделы: Автомобили Астрономия Биология География Дом и сад Другие языки Другое Информатика История Культура Литература Логика Математика Медицина Металлургия Механика Образование Охрана труда Педагогика Политика Право Психология Религия Риторика Социология Спорт Строительство Технология Туризм Физика Философия Финансы Химия Черчение Экология Экономика Электроника

Управляемая анимация изображения






демонстрируется в следующем примере. Его идея взята из примера OpenGL, множество которых можно найти в MSDN.

¨ Сначала загружаем растровое изображение из bmp -файла и демонстрируем его в окне OpenGL;

¨ Затем мышью указываем произвольное количество точек, которые описывают будущую траекторию движения одной (первой) точки. Траектория определяет цепь последующих трансформаций текстуры;

¨ Запоминаем координаты точек в контейнере STL типа vector;

¨ Для плавности анимации генерируем промежуточные точки, разбивая расстояния между последовательно идущими точками траектории на какое-то число частей. Оно определяется экспериментально и зависит от скорости передачи изображения (rendering), то есть от качества видео-карты;

¨ Двигаясь вдоль всех точек траектории, последовательно изображаем четыре треугольные текстуры, которые, будучи составленными вместе, дают прямоугольное изображение;

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


Чтобы понять что происходит, вообразите рисунок, выполненный на куске резины, из которой делают воздушные шарики. Затем представьте, что произойдет с рисунком, если одну его точку перемещать в плоскости полотна изображения. Изображение будет как-то растягиваться и сжиматься. Следующие 2 рисунка напоминают почтовые конверты. Они показывают 4 треугольника, из которых составлен прямоугольник изображения. Центральная точка движется по некоторой траектории и переходит из одного положения в другое. Начальному положению соответствуют сплошные линии, а следующему — пунктирные. При перемещении одной, выделенной точки в другое положение треугольники трансформируются. Если мы таким же образом трансформируем текстуры, натянутые на них, то получим анимацию, алгоритм которой задает пользователь.

Как видите, алгоритм демонстрации эффекта растяжения текстур достаточно сложен. В связи с этим выделим 4 режима, в которых будет работать приложение (выбор файла с изображением, вывод изображения, ввод точек траектории, анимация изображения). Нам понадобится некоторый набор переменных, который удобно определить глобально. С вершинами треугольников будут ассоциированы координаты двухмерной текстуры, поэтому в класс CVert кроме пространственных координат вершины (v) мы инкапсулировали текстурные координаты (g).

GLUT_RGBImageRec *pImg; // Структура, описывающая RGB-изображение

 

enum eMode // Режим перерисовки

{

eNOP, // Ничего не делаем

eANIMATE, // Запускаем анимацию

ePOINTS, // Рисуем точки траектории

eSTILL // Рисуем весь bitmap

};

 

eMode gMode = eNOP;// Текущий режим

 

class Point2D

{

public:

float x, y;

Point2D () { x=0.; y=0.; }

Point2D (float fx, float fy) { x=fx; y=fy; }

Point2D operator- (const Point2D& pt) { return Point2D (x-pt.x, y-pt.y); }

void operator+= (const Point2D& pt) { x += pt.x; y += pt.y; }

};

 

class CVert

{

public:

Point2D v, g; // Координаты вершины и текстуры в 2D

static Point2D dv; // Сдвиг точки траектории (общий для всех объектов)

 

CVert(): v(), g() {}

CVert (Point2D pv, Point2D pt): v(pv), g(pt) {}

 

CVert& operator= (const CVert& vt)

{

v = vt.v;

g = vt.g;

return *this;

}

void Shift() { v += dv; } // Сдвиг на dv

};

 

Point2D CVert::dv; // Определение статической переменной класса

CVert gVerts[5]; // 5 точек, разделяющих изображение на 4 треугольника

vector<Point2D> gPoints;// Траектория движения первой точки

 

//==== Увеличение количества разбиений gSteps вносит плавность анимации, замедляя ее

int gSteps = 10,// Количество шагов деления интервала между соседними точками траектории

gCX, gCY, // Размеры bitmap

giLast, // Индекс предыдущей точки траектории

giNext, // Индекс следующей точки траектории

giCur; // Индекс текущей точки траектории

 

char szFile[MAX_PATH]; // Файловый путь

 

char* FileDlg (bool bRead) // Работа с файловым диалогом (bRead – режим открытия файла)

{

TCHAR *szFilter = // Фильтр файловых расширений

TEXT("BMP Files (*.bmp)\0*.bmp\0")

TEXT("DIB Files (*.dib)\0*.dib\0");

 

char szCurDir[MAX_PATH]; // Начнем с текущей директории

::GetCurrentDirectory (MAX_PATH-1, szCurDir);

 

OPENFILENAME ofn; // Структура, используемая стандартным диалогом

ZeroMemory (&ofn, sizeof(OPENFILENAME));

 

//====== Параметры настройки диалога

ofn.lStructSize = sizeof(OPENFILENAME);

ofn.hwndOwner = glutGetHWND(); // Окно, которому принадлежит диалог

ofn.lpstrFilter = szFilter;

ofn.nFilterIndex = 1; // Начальный индекс массива строк фильтра равен 1

ofn.lpstrFile = szFile;

ofn.nMaxFile = sizeof(szFile);

ofn.lpstrTitle = "Find a bitmap file";// Заголовок диалога

ofn.nMaxFileTitle = sizeof (ofn.lpstrTitle);

ofn.lpstrInitialDir = szCurDir; // Начальная директория

ofn.Flags = OFN_EXPLORER|OFN_OVERWRITEPROMPT; // Стиль EXPLORER (работает только в Win2K)

ofn.lpstrDefExt = "bmp";

 

//====== Создаем и открываем диалог (при неудаче возвращает 0)

BOOL b = bRead? GetOpenFileName(&ofn): GetSaveFileName(&ofn);

 

return b? ofn.lpstrFile: 0;

}

 

bool Read() // Чтение изображения из файла

{

char *fn;

if ((fn = FileDlg (true))!= 0)

{

pImg = glutDIBImageLoad (fn); //или glutRGBImageLoad

//==== Размеры bitmap в OpenGL должны быть степенью двойки

gCX = int(pow (2., int(log (pImg->sizeX)/log(2.))));

gCY = int(pow (2., int(log (pImg->sizeY)/log(2.))));

return true;

}

else

return false;

}

 

void DrawImage()

{

glRasterPos2i(0, 0);

glDrawPixels (pImg->sizeX, pImg->sizeY,GL_RGB,GL_UNSIGNED_BYTE, pImg->data);

}

 

void DrawPoint()

{

glColor3f(1.0, 0.0, 1.0);

glPointSize(3.0);

 

glBegin(GL_POINTS);

for (int i = 0; i < gPoints.size(); i++)

glVertex2f(gPoints[i].x, gPoints[i].y);

glEnd();

}

 

void UpdateStep() // Вычисляем шаг смещения (для промежуточных точек)

{

Point2D pt = gPoints[giNext] - gPoints[giLast];

CVert::dv = Point2D (pt.x / gSteps, pt.y / gSteps);

}

 

void Animate()

{

//==== Изображение составлено из 4-х текстурных треугольников

//==== 4 угловых точки и одна точка, движущаяся по траектории

 

//==== Сначала растянем нижний треугольник

glBegin(GL_TRIANGLES); // |------------|

glTexCoord2f(gVerts[0].g.x, gVerts[0].g.y); // | |

glVertex2f(gVerts[0].v.x, gVerts[0].v.y); // | |

glTexCoord2f(gVerts[1].g.x, gVerts[1].g.y); // | 4 |

glVertex2f(gVerts[1].v.x, gVerts[1].v.y); // | / \ |

glTexCoord2f(gVerts[4].g.x, gVerts[4].g.y); // | / \ |

glVertex2f(gVerts[4].v.x, gVerts[4].v.y); // 0___________\1

glEnd();

//==== Затем – правый треугольник

glBegin(GL_TRIANGLES); // |------------2

glTexCoord2f(gVerts[1].g.x, gVerts[1].g.y); // | / |

glVertex2f(gVerts[1].v.x, gVerts[1].v.y); // | / |

glTexCoord2f(gVerts[2].g.x, gVerts[2].g.y); // | 4 |

glVertex2f(gVerts[2].v.x, gVerts[2].v.y); // | \ |

glTexCoord2f(gVerts[4].g.x, gVerts[4].g.y); // | \ |

glVertex2f(gVerts[4].v.x, gVerts[4].v.y); // |____________1

glEnd();

//==== После этого – верхний треугольник

glBegin(GL_TRIANGLES); // 3------------2

glTexCoord2f(gVerts[2].g.x, gVerts[2].g.y); // | \ / |

glVertex2f(gVerts[2].v.x, gVerts[2].v.y); // | \ / |

glTexCoord2f(gVerts[3].g.x, gVerts[3].g.y); // | 4 |

glVertex2f(gVerts[3].v.x, gVerts[3].v.y); // | |

glTexCoord2f(gVerts[4].g.x, gVerts[4].g.y); // | |

glVertex2f(gVerts[4].v.x, gVerts[4].v.y); // |____________|

glEnd();

//==== Наконец, левый треугольник

glBegin(GL_TRIANGLES); // 3------------|

glTexCoord2f(gVerts[3].g.x, gVerts[3].g.y); // | \ |

glVertex2f(gVerts[3].v.x, gVerts[3].v.y); // | \ |

glTexCoord2f(gVerts[0].g.x, gVerts[0].g.y); // | 4 |

glVertex2f(gVerts[0].v.x, gVerts[0].v.y); // | / |

glTexCoord2f(gVerts[4].g.x, gVerts[4].g.y); // | / |

glVertex2f(gVerts[4].v.x, gVerts[4].v.y); // 0____________|

glEnd();

 

//=== Смещаем пятую точку на шаг, но не трогаем ее текстурных координат!!!

if (++giCur <= gSteps)

gVerts[4].Shift();

else // Переходим к следующей точке траектории

{

giLast = giNext;

if (++giNext == gPoints.size()) // Если последняя – зацикливаем

giNext = 0;

 

UpdateStep();

giCur = 0;

}

}

 

void InitVList()// Инициализация массива точек (конверта)

{

giLast = 0;

giNext = 1;

UpdateStep();

 

gVerts[0] = CVert (); // Bottom Left corner

gVerts[1] = CVert (Point2D(gCX,0.), Point2D(1.,0.)); // Bottom Right corner

gVerts[2] = CVert (Point2D(gCX, gCY), Point2D(1.,1.)); // Top Right corner

gVerts[3] = CVert (Point2D(0.,gCY), Point2D(0.,1.)); // Top Left corner

 

//==== Текстурные координаты первой точки траектории

Point2D tex(gPoints[0].x / gCX, gPoints[0].y / gCY);

gVerts[4] = CVert (gPoints[0], tex); // Пятая точка – это первая точка траектории

}

 

void OnPaint()

{

switch (gMode)

{

case eANIMATE: Animate(); break;

case ePOINTS: DrawPoint(); break;

case eSTILL: DrawImage(); break;

}

glutSwapBuffers();

}

 

void OnKey (unsigned char ch, int x, int y)

{

switch (ch)

{

case 27: exit(0); break;

case ' ':

if (gPoints.size() > 1)

{

InitVList();

giCur = 0;

glEnable(GL_TEXTURE_2D);

gMode = eANIMATE;

glutIdleFunc(OnPaint);

}

break;

}

glutPostRedisplay();

}

 

void OnMouse(int button, int state, int x, int y)

{

if (state == GLUT_DOWN)

{

if (gMode == eANIMATE)

{

glDisable(GL_TEXTURE_2D);

gPoints.clear();

gMode = eSTILL;

glutIdleFunc(0);

}

else

{

gPoints.push_back(Point2D(x, gCY - y));

gMode = ePOINTS;

}

}

}

 

void Init()

{

glViewport(0, 0, gCX, gCY);

gluOrtho2D(0, gCX, 0, gCY);

 

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

glPixelStorei(GL_PACK_ALIGNMENT, 1);

 

BYTE *buf = (BYTE*) malloc (3 * gCX * gCY);

gluScaleImage (GL_RGB, pImg->sizeX, pImg->sizeY, GL_UNSIGNED_BYTE,

pImg->data, gCX, gCY, GL_UNSIGNED_BYTE, buf);

 

free (pImg->data);

pImg->data = buf;

pImg->sizeX = gCX; pImg->sizeY = gCY;

 

glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);

glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

 

glTexImage2D (GL_TEXTURE_2D, 0, 3, pImg->sizeX, pImg->sizeY, 0,

GL_RGB, GL_UNSIGNED_BYTE, (BYTE*)pImg->data);

 

giLast = giNext = 0;

gMode = eSTILL;

}







Дата добавления: 2015-10-19; просмотров: 590. Нарушение авторских прав; Мы поможем в написании вашей работы!



Вычисление основной дактилоскопической формулы Вычислением основной дактоформулы обычно занимается следователь. Для этого все десять пальцев разбиваются на пять пар...

Расчетные и графические задания Равновесный объем - это объем, определяемый равенством спроса и предложения...

Кардиналистский и ординалистский подходы Кардиналистский (количественный подход) к анализу полезности основан на представлении о возможности измерения различных благ в условных единицах полезности...

Обзор компонентов Multisim Компоненты – это основа любой схемы, это все элементы, из которых она состоит. Multisim оперирует с двумя категориями...

Огоньки» в основной период В основной период смены могут проводиться три вида «огоньков»: «огонек-анализ», тематический «огонек» и «конфликтный» огонек...

Упражнение Джеффа. Это список вопросов или утверждений, отвечая на которые участник может раскрыть свой внутренний мир перед другими участниками и узнать о других участниках больше...

Влияние первой русской революции 1905-1907 гг. на Казахстан. Революция в России (1905-1907 гг.), дала первый толчок политическому пробуждению трудящихся Казахстана, развитию национально-освободительного рабочего движения против гнета. В Казахстане, находившемся далеко от политических центров Российской империи...

Приготовление дезинфицирующего рабочего раствора хлорамина Задача: рассчитать необходимое количество порошка хлорамина для приготовления 5-ти литров 3% раствора...

Дезинфекция предметов ухода, инструментов однократного и многократного использования   Дезинфекция изделий медицинского назначения проводится с целью уничтожения патогенных и условно-патогенных микроорганизмов - вирусов (в т...

Машины и механизмы для нарезки овощей В зависимости от назначения овощерезательные машины подразделяются на две группы: машины для нарезки сырых и вареных овощей...

Studopedia.info - Студопедия - 2014-2024 год . (0.01 сек.) русская версия | украинская версия