Диалог по открытию файла
Рассмотрим функцию FileDlg, которую следует вставить в файл проекта. В ее теле мы создаем файловый диалог, в контексте которого пользователь выбирает файл с изображением, и возвращаем строку с именем файла. Эта функция будет вызвана внутри функции Read, которая непосредственно читает файл и обрабтывает ислючения. Здесь мы демонстрируем, как работать с файловым диалогом, созданным с помощью функции API, и обрабатывать ошибки. Стандартный диалог в этом случае более управляем, чем при работе с MFC-классом CFileDialog, и ему можно придать множество сравнительно новых стилей. Так, стиль OFN_EXPLORER работает только в W2K. Из соображений общности сделано так, что функция FileDlg способна открыть диалог как для чтения, так и для записи файла. В примере использован только первый режим. Он задан параметром bRead=true. Чтобы код заработал надо вставить директиву подключения файла заголовков <commdlg.h>. double gx, gy, gz = 4; // Глобальные типы данных и переменные bool gbColor = false; float gFilter = GL_NEAREST;
char* FileDlg (bool bRead) // bRead (true - Open, false - Save) { TCHAR *fn = new TCHAR [MAX_PATH]; // File Name to Return fn[0] = 0;
TCHAR *szFilter = // File Extension Filters TEXT("BMP Files (*.bmp)\0*.bmp\0") TEXT("DIB Files (*.dib)\0*.dib\0");
TCHAR szCurDir[MAX_PATH]; ::GetCurrentDirectory (MAX_PATH-1, szCurDir);
TCHAR *szTitle = "Find a bitmap file";
OPENFILENAME ofn = { sizeof(OPENFILENAME), 0,// Dialog Owner 0, //App Instance szFilter, 0, 0, 1, // Filter, Custom Filter and Filter Index fn, MAX_PATH, 0, 0, // Recieve File Name, File Name Buffer szCurDir, szTitle, // InitialDir, Dialog Title OFN_EXPLORER | OFN_OVERWRITEPROMPT, // Flags 0, 0, "bmp", 0, 0, 0,// Offsets, Default extension, CustData, Hook, TemplateName 0, 0, 0 // Reserved, Reserved, FlagsEx };
//===== Create and Open the dialog (returns 0, if failed) BOOL b = bRead? GetOpenFileName(&ofn): GetSaveFileName(&ofn);
return b? fn: 0; } Сдедующая функция (вставьте ее вслед за первой) вызывает FileDlg, читает файл, строит последовательность mipmap -изображений и демонстрирует как пользоваться функцией gluErrorString, которая, опираясь на код ошибки, возвращает ее текстовое описание. Код ошибки возвращает другая функция: glGetError. void Read() //==== Чтение изображения из файла { BMPClass* img = new BMPClass(); img->BMPLoad (FileDlg (true)); if (!img) throw "Error reading texture.\n";
glGenTextures (1, &texture); glBindTexture (GL_TEXTURE_2D, texture);
glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
GLenum error; if ((error = gluBuild2DMipmaps (GL_TEXTURE_2D, 3, img->sizeX, img->sizeY, GL_RGB, GL_UNSIGNED_BYTE, (void*)img->data))) throw gluErrorString (error);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);// GL_NEAREST_MIPMAP_LINEAR glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);//GL_LINEAR glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } При изображении сцены учтем возможность включать и выключать текстуру. void DrawScene() { glNewList(1,GL_COMPILE); glBegin(GL_QUADS); glNormal3d (0., 0., 1.); if (gbColor) { glColor3d (rand()%256/255.,rand()%256/255., rand()%256/255.); glVertex3d (-1., -1., 0.); glColor3d (rand()%256/255.,rand()%256/255., rand()%256/255.); glVertex3d (1., -1., 0.); glColor3d (rand()%256/255.,rand()%256/255., rand()%256/255.); glVertex3d (1., 1., 0.); glColor3d (rand()%256/255.,rand()%256/255., rand()%256/255.); glVertex3d (-1., 1., 0.); } else { glTexCoord2d (0., 0.); glVertex3d (-1., -1., 0.); glTexCoord2d (1., 0.); glVertex3d (1., -1., 0.); glTexCoord2d (1., 1.); glVertex3d (1., 1., 0.); glTexCoord2d (0., 1.); glVertex3d (-1., 1., 0.); } glEnd(); glEndList(); } В функцию инициализации введем вызов функции, читающей растровое изображение из файла, а также установки, необходимые для двухмерной текстуры, совмещаемой с цветом объекта. void Init() { if (!Read()) glutQuit(); glClearColor (1., 1., 1., 0.);
glCullFace(GL_BACK); glEnable(GL_CULL_FACE); glEnable(GL_TEXTURE_2D); glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_COLOR_MATERIAL); DrawScene(); } Функция перерисовки стандартна, за исключением двух команд настройки параметров текстуры. void OnPaint() { glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gFilter); glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gFilter); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix (); gluLookAt (gx, gy, gz, 0., 0., 0., 0., 1., 0.);
glCallList(1); glPopMatrix (); glutSwapBuffers(); } На клавиши F и T возложим регулировку параметрами текстуры. void OnKey (unsigned char ch, int x, int y) {
static float f[] = { GL_NEAREST, GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_LINEAR }; static char* sf[] = { "GL_NEAREST", "GL_LINEAR", "GL_NEAREST_MIPMAP_NEAREST", "GL_LINEAR_MIPMAP_NEAREST", "GL_NEAREST_MIPMAP_LINEAR", "GL_LINEAR_MIPMAP_LINEAR" };
static int id;
switch (ch) { case 27: exit(0); break; case 't': gbColor =!gbColor; if (gbColor) glDisable(GL_TEXTURE_2D); else glEnable(GL_TEXTURE_2D); DrawScene(); break; case 'f': ++id %= 6;
gFilter = f[id]; cout <<"\nFilter: "<<sf[id]; InvalidateRect(glutGetHWND(),0,FALSE); break; } glutPostRedisplay(); } Недостающие функции каркаса вы можете взять из предыдущих примеров. После запуска проанализируйте работу фильтров текстуры. Различия в параметрах особенно хорошо заметны на контрастных изображениях типа того узора «Пики», который мы создали самостоятельно.
|