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

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

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






демонстрируется в следующем примере. Его идея взята из примера 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; просмотров: 594. Нарушение авторских прав; Мы поможем в написании вашей работы!



Важнейшие способы обработки и анализа рядов динамики Не во всех случаях эмпирические данные рядов динамики позволяют определить тенденцию изменения явления во времени...

ТЕОРЕТИЧЕСКАЯ МЕХАНИКА Статика является частью теоретической механики, изучающей условия, при ко­торых тело находится под действием заданной системы сил...

Теория усилителей. Схема Основная масса современных аналоговых и аналого-цифровых электронных устройств выполняется на специализированных микросхемах...

Логические цифровые микросхемы Более сложные элементы цифровой схемотехники (триггеры, мультиплексоры, декодеры и т.д.) не имеют...

Философские школы эпохи эллинизма (неоплатонизм, эпикуреизм, стоицизм, скептицизм). Эпоха эллинизма со времени походов Александра Македонского, в результате которых была образована гигантская империя от Индии на востоке до Греции и Македонии на западе...

Демографияда "Демографиялық жарылыс" дегеніміз не? Демография (грекше демос — халық) — халықтың құрылымын...

Субъективные признаки контрабанды огнестрельного оружия или его основных частей   Переходя к рассмотрению субъективной стороны контрабанды, остановимся на теоретическом понятии субъективной стороны состава преступления...

Роль органов чувств в ориентировке слепых Процесс ориентации протекает на основе совместной, интегративной деятельности сохранных анализаторов, каждый из которых при определенных объективных условиях может выступать как ведущий...

Лечебно-охранительный режим, его элементы и значение.   Терапевтическое воздействие на пациента подразумевает не только использование всех видов лечения, но и применение лечебно-охранительного режима – соблюдение условий поведения, способствующих выздоровлению...

Тема: Кинематика поступательного и вращательного движения. 1. Твердое тело начинает вращаться вокруг оси Z с угловой скоростью, проекция которой изменяется со временем 1. Твердое тело начинает вращаться вокруг оси Z с угловой скоростью...

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