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

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

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





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




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


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


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


Композиция из абстрактных геометрических фигур Данная композиция состоит из линий, штриховки, абстрактных геометрических форм...

Стресс-лимитирующие факторы Поскольку в каждом реализующем факторе общего адаптацион­ного синдрома при бесконтрольном его развитии заложена потенци­альная опасность появления патогенных преобразований...

ТЕОРИЯ ЗАЩИТНЫХ МЕХАНИЗМОВ ЛИЧНОСТИ В современной психологической литературе встречаются различные термины, касающиеся феноменов защиты...

Этические проблемы проведения экспериментов на человеке и животных В настоящее время четко определены новые подходы и требования к биомедицинским исследованиям...

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

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

Деятельность сестер милосердия общин Красного Креста ярко проявилась в период Тритоны – интервалы, в которых содержится три тона. К тритонам относятся увеличенная кварта (ув.4) и уменьшенная квинта (ум.5). Их можно построить на ступенях натурального и гармонического мажора и минора.  ...

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