…
Профиль
Группа: Завсегдатай
Сообщений: 1037
Регистрация: 21.11.2004
Репутация: нет Всего: 4
|
Обучаюсь работе с OpenGL по урокам NeHe. Использую C++Builder 2010. По ходу обучения возникли несостыковки. Функция от библиотеки glaux.h не захотела работать. На всякий случай для начала полный код моей программы: Код | // OpenGL - урок номер 4, лепим текстуру на 3д // ---------------------------------------------------------------------------
#include <vcl.h> #include <windows.h> #pragma hdrstop
#include <tchar.h>
#include <gl\gl.h> #include <gl\glu.h> #include <gl\glaux.h> // ---------------------------------------------------------------------------
HGLRC hRC; // постоянный контекст рендеринга HDC hDC; // постоянный контекст устройства GDI HWND hWnd; // дескриптор главного окна HINSTANCE appInstance; // дескриптор приложения
bool keys[256]; // массив, используемый для операций с клавиатурой bool active = true; // флаг активности приложения, чтобы приостановить пр. при его минимизации bool fullscreen = true;
GLuint texture[1]; // всего 1, но начинается с 0
LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); // прототип функции GLvoid ReSizeGLScene( GLsizei width, GLsizei height ); int InitGL( GLvoid ); int DrawGLScene( GLvoid ); GLvoid KillGLWindow( GLvoid ); bool CreateGLWindow( LPCWSTR title, int width, int height, int bits, bool fullscreenflag ); GLvoid LoadGLTextures();
#pragma argsused
WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow ) { //appInstance = hInstance; // считываем по другому при создании окна MSG msg; // структура для хранения сообщения windows bool done = false; // логическая переменная для выхода из цикла
// Спрашивает пользователя, какой режим экрана он предпочитает if ( MessageBox( NULL, "Запустить приложение вполноэкранном режиме?", "Выбор режима запуска", MB_YESNO|MB_ICONQUESTION ) == IDNO ) { fullscreen = false; // оконный режим }
// Создать наше OpenGL окно if ( !CreateGLWindow( String("OpenGL lolo").c_str(), 1024, 768, 32, fullscreen ) ) { return 0; // выйти, если окно не может быть создано }
while ( !done ) { if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) { // Есть ли в очереди какое-нибудь сообщение? if ( msg.message == WM_QUIT ) { done = true; } else { TranslateMessage( &msg ); // Переводим сообщение DispatchMessage( &msg ); // Отсылаем сообщение } } else { // если нет сообщений // Прорисовываем сцену. if ( active ) { if ( keys[ VK_ESCAPE ] ) { done = true; } else { DrawGLScene(); SwapBuffers( hDC ); // меняем буфер (двойная буфферизация) } }
if ( keys[ VK_F1 ] ) { keys[ VK_F1 ] = false; KillGLWindow(); fullscreen = !fullscreen;
// Пересоздаём наше OpenGL окно if ( !CreateGLWindow( String("OpenGL lolo").c_str(), 1024, 768, 32, fullscreen ) ) { return 0; } } } }
// shutdown KillGLWindow(); // крушим окно return msg.wParam; // выходим из программы } // ---------------------------------------------------------------------------
GLvoid ReSizeGLScene( GLsizei width, GLsizei height ) { // изменить размер и инициализировать окно GL if ( height == 0 ) { // предотвращаем <del>конец света</del> деление на ноль height = 1; } glViewport( 0, 0, width, height ); // сброс текущей области вывода
glMatrixMode( GL_PROJECTION ); // выбор матрицы проекций glLoadIdentity(); // сброс матрицы проекции
// Вычисление соотношения геометрических размеров для окна GLUlib gluPerspective( 45.0f, (GLfloat)width/(GLfloat)height, 0.1f, 100.0f );
glMatrixMode( GL_MODELVIEW ); // выбор матрицы вида модели glLoadIdentity(); // сброс матрицы вида модели }
int InitGL( GLvoid ) { // все установки касаемо GL происходят тут LoadGLTextures(); // загрузка текстур glEnable( GL_TEXTURE_2D ); // разрешение наложения текстур
glShadeModel( GL_SMOOTH ); // разрешить плавное цветовое сглаживание glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); // очистка экрана в чёрный цвет glClearDepth( 1.0f ); // разрешить очистку буфера глубины glEnable( GL_DEPTH_TEST ); // разрешить тест глубины glDepthFunc( GL_LEQUAL ); // тип теста глубины
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ); // улучшение в вычислении перспективы return true; // инициализация прошла успешно }
int DrawGLScene( GLvoid ) { // тут происходит вся прорисовка glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); // очистить экран и буфер глубины
glLoadIdentity(); // сбросить текущую матрицу
static GLfloat rQuad;
// Куб glTranslatef( 0.0f, 0.0f, -5.0f ); glRotatef( rQuad, 0.5f, 1.0f, 0.5f ); //glRotatef( rQuad, 0.0f, 1.0f, 0.0f ); //glColor3f( 1.0f, 0.0f, 1.0f ); glBindTexture( GL_TEXTURE_2D, texture[0] ); glBegin( GL_QUADS ); // лицо glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -1.0f, 1.0f, 1.0f ); glTexCoord2f( 1.0f, 0.0f ); glVertex3f( 1.0f, 1.0f, 1.0f ); glTexCoord2f( 1.0f, 1.0f ); glVertex3f( 1.0f, -1.0f, 1.0f ); glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -1.0f, -1.0f, 1.0f );
// правый бок glTexCoord2f( 0.0f, 0.0f ); glVertex3f( 1.0f, 1.0f, -1.0f ); glTexCoord2f( 1.0f, 0.0f ); glVertex3f( 1.0f, 1.0f, 1.0f ); glTexCoord2f( 0.0f, 1.0f ); glVertex3f( 1.0f, -1.0f, 1.0f ); glTexCoord2f( 1.0f, 1.0f ); glVertex3f( 1.0f, -1.0f, -1.0f );
// жопа glTexCoord2f( 1.0f, 1.0f ); glVertex3f( 1.0f, 1.0f, -1.0f ); glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -1.0f, 1.0f, -1.0f ); glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -1.0f, -1.0f, -1.0f ); glTexCoord2f( 1.0f, 0.0f ); glVertex3f( 1.0f, -1.0f, -1.0f );
// левый бок glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -1.0f, 1.0f, -1.0f ); glTexCoord2f( 1.0f, 1.0f ); glVertex3f( -1.0f, 1.0f, 1.0f ); glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -1.0f, -1.0f, 1.0f ); glTexCoord2f( 1.0f, 0.0f ); glVertex3f( -1.0f, -1.0f, -1.0f );
// голова glTexCoord2f( 1.0f, 0.0f ); glVertex3f( -1.0f, 1.0f, 1.0f ); glTexCoord2f( 1.0f, 1.0f ); glVertex3f( -1.0f, 1.0f, -1.0f ); glTexCoord2f( 0.0f, 1.0f ); glVertex3f( 1.0f, 1.0f, -1.0f ); glTexCoord2f( 0.0f, 0.0f ); glVertex3f( 1.0f, 1.0f, 1.0f );
// нижняя glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -1.0f, -1.0f, 1.0f ); glTexCoord2f( 1.0f, 0.0f ); glVertex3f( -1.0f, -1.0f, -1.0f ); glTexCoord2f( 1.0f, 1.0f ); glVertex3f( 1.0f, -1.0f, -1.0f ); glTexCoord2f( 0.0f, 1.0f ); glVertex3f( 1.0f, -1.0f, 1.0f ); glEnd();
rQuad -= 0.05f;
return true; // прорисовка прошла успешно }
GLvoid KillGLWindow( GLvoid ) { // корректное разрушение форточки if ( fullscreen ) { ChangeDisplaySettings( NULL, 0 ); // переключаемся в оконный режим (востанавливаютяс настройки экрана по умолчанию) ShowCursor( true ); // показываем курсор }
if ( hRC ) { if ( !wglMakeCurrent( NULL, NULL ) ) { // возможно ли освободить RC от DC MessageBox( NULL, "Невозможно освободить RC от DC.", "Ошибка завершения", MB_OK|MB_ICONINFORMATION ); } if ( !wglDeleteContext( hRC ) ) { // возможно ли удалить RC MessageBox( NULL, "Невозможно удалить RC.", "Ошибка завершения", MB_OK|MB_ICONINFORMATION ); } hRC = NULL; // устанавливаем RC в нул (я так понял убиваем линк и тем самым освобождаем память) }
if ( hDC && !ReleaseDC( hWnd, hDC ) ) { // возможно ли уничтожить DC MessageBox( NULL, "Невозможно освободить DC.", "Ошибка завершения", MB_OK|MB_ICONINFORMATION ); hDC = NULL; }
if ( hWnd && !DestroyWindow(hWnd) ) { // возможно ли уничтожить окно MessageBox( NULL, "Невозможно освободить окно.", "Ошибка завершения", MB_OK|MB_ICONINFORMATION ); hWnd = NULL; }
if ( !UnregisterClass( "OpenGL", appInstance ) ) { // возможно ли разрегистрировать класс MessageBox( NULL, "Невозможно разрегистрировать класс окна.", "Ошибка завершения", MB_OK|MB_ICONINFORMATION ); appInstance = NULL; } }
bool CreateGLWindow( LPCWSTR title, int width, int height, int bits, bool fullscreenflag ) { GLuint PixelFormat; // хранит результат после поиска WNDCLASS wc; DWORD dwExStyle; // расширенный стиль окна DWORD dwStyle; // обычный стиль окна
RECT WindowRect; // сюда соберём углы краёв, чтобы по ним запонлять окно (типа) WindowRect.left = (long)0; WindowRect.right = (long)width; WindowRect.top = (long)0; WindowRect.bottom = (long)height;
fullscreen = fullscreenflag;
appInstance = GetModuleHandle( NULL ); // считываем дескриптом приложения wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // перерисуем при перемещении и создаём скрытый DC wc.lpfnWndProc = (WNDPROC)WndProc; // процедура обработки сообщений wc.cbClsExtra = 0; // нет доп. инф. для окна wc.cbWndExtra = 0; // нет доп. инф. для окна wc.hInstance = appInstance; wc.hIcon = LoadIcon( NULL, IDI_WINLOGO ); // иконка по умолчанию wc.hCursor = LoadCursor( NULL, IDC_ARROW ); // загружаем указатель мышки wc.hbrBackground = NULL; // фон не требуется для GL wc.lpszMenuName = NULL; // меню в окне не будет wc.lpszClassName = "OpenGL";
if ( !RegisterClass( &wc ) ) { // пытаемся зарегить класс окна MessageBox( NULL, "Ошибка регистрации класса окна.", "Ошибка", MB_OK|MB_ICONEXCLAMATION ); return false; // выход и возврат false }
if ( fullscreen ) { DEVMODE dmScreenSettings; // режим устройства memset( &dmScreenSettings, 0, sizeof( dmScreenSettings ) ); // очистка для хранения установок dmScreenSettings.dmSize = sizeof( dmScreenSettings ); // размер структуры DEVMODE dmScreenSettings.dmPelsWidth = width; dmScreenSettings.dmPelsHeight = height; dmScreenSettings.dmBitsPerPel = bits; dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; // режим пикселя
// Пытаемся установить выбранный режим и получить результат. Примечание: CDS_FULLSCREEN убирает панель управления. if ( ChangeDisplaySettings( &dmScreenSettings, CDS_FULLSCREEN ) != DISP_CHANGE_SUCCESSFUL ) { // Если переключение в полноэкранный режим невозможно, будет предложено два варианта: оконный режим или выход. if ( MessageBox( NULL, "Невозможно воспользоваться полноэкранным режимом.\nИспользовать оконный режим?", "GL", MB_YESNO|MB_ICONEXCLAMATION ) == IDYES ) { fullscreen = false; // выбор оконного режима } else { // Выскакивающее окно, сообщающее пользователю о закрытие окна. MessageBox( NULL, "Дальнейшее выполнение программы невозможно.\nНажмите OK, чтобы завершить работу с приложением.", "Ошибка", MB_OK|MB_ICONSTOP ); return false; } } }
if ( fullscreen ) { // остались ли в полноэкранном режиме dwExStyle = WS_EX_APPWINDOW; dwStyle = WS_POPUP; ShowCursor( false ); } else { dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; dwStyle = WS_OVERLAPPEDWINDOW; }
AdjustWindowRectEx( &WindowRect, dwStyle, false, dwExStyle ); // подбирает окну подходящие размеры
if ( !( hWnd = CreateWindowEx( dwExStyle, "OpenGL", String(title).t_str(), WS_CLIPSIBLINGS|WS_CLIPCHILDREN|dwStyle, 0, 0, WindowRect.right-WindowRect.left, WindowRect.bottom-WindowRect.top, NULL, NULL, appInstance, NULL ) ) ) { KillGLWindow(); // восстановить экран MessageBox( NULL, "Ошибка создания окна.", "Ошибка", MB_OK|MB_ICONEXCLAMATION ); return false; }
static PIXELFORMATDESCRIPTOR pfd = { // pfd сообщает Windows каким будет вывод на экран каждого пикселя sizeof( PIXELFORMATDESCRIPTOR ), // Размер дескриптора данного формата пикселей 1, // номер версии PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, PFD_TYPE_RGBA, // требуется ргба формат bits, // вибирается бит глубины цвета 0, 0, 0, 0, 0, 0, // игнорирование цветовых битов 0, // нет буфера прозрачности 0, // сдвиговый бит игнорируется 0, // нет буфера-накопителя 0, 0, 0, 0, // биты накопления игнорируются 32, // 32-битный З-буфер (буфер глубины) 0, // нет буфера трафарета 0, // нет вспомогательных буферов PFD_MAIN_PLANE, // главный слой рисования 0, // зарезервировано 0, 0, 0 // маски слоя игнорируются };
if ( !( hDC = GetDC( hWnd ) ) ) { // можем ли получить контекст устройства KillGLWindow(); // восстанавливаем экран MessageBox( NULL, "Невозможно получить DC.", "Ошибка", MB_OK|MB_ICONEXCLAMATION ); return false; }
if ( !( PixelFormat = ChoosePixelFormat( hDC, &pfd ) ) ) { // найден ли подходящий формат пикселя KillGLWindow(); // восстанавливаем экран MessageBox( NULL, "Не найден подходящий формат пикселя.", "Ошибка", MB_OK|MB_ICONEXCLAMATION ); return false; }
if ( !SetPixelFormat( hDC, PixelFormat, &pfd ) ) { // возможно ли установить формат пикселя KillGLWindow(); // восстанавливаем экран MessageBox( NULL, "Невозможно установить формат пикселя.", "Ошибка", MB_OK|MB_ICONEXCLAMATION ); return false; }
if ( !( hRC = wglCreateContext( hDC ) ) ) { // возможно ли установить контекст рендеринга KillGLWindow(); // восстанавливаем экран MessageBox( NULL, "Невозможно установить контекст рендеринга.", "Ошибка", MB_OK|MB_ICONEXCLAMATION ); return false; }
if ( !wglMakeCurrent( hDC, hRC ) ) { // попытка активировать контекст рендеринга KillGLWindow(); // восстанавливаем экран MessageBox( NULL, "Невозможно активировать контекст рендеринга.", "Ошибка", MB_OK|MB_ICONEXCLAMATION ); return false; }
ShowWindow( hWnd, SW_SHOW ); SetForegroundWindow( hWnd ); // слегка повышаем приоритет проги SetFocus( hWnd ); ReSizeGLScene( width, height ); // Настроим перспективу для нашего OpenGL экрана.
if ( !InitGL() ) { KillGLWindow(); // восстанавливаем экран MessageBox( NULL, "Произошла ошибка инициализации.", "Ошибка", MB_OK|MB_ICONEXCLAMATION ); return false; } }
LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch ( uMsg ) { case WM_ACTIVATE: // проверка сообщения активности окна if ( !HIWORD( wParam ) ) { // проверяем состояние минимизации active = true; } else { active = false; } return 0; case WM_SYSCOMMAND: // перехватываем системную команду if ( wParam == SC_SCREENSAVE || wParam == SC_MONITORPOWER ) { return 0; } break;
case WM_CLOSE: PostQuitMessage(0); // отправляем сообщение о выходе return 0; // вернуться назад
case WM_KEYDOWN: keys[ wParam ] = true; return 0;
case WM_KEYUP: keys[ wParam ] = false; return 0;
case WM_SIZE: ReSizeGLScene( LOWORD(lParam), HIWORD(lParam) ); // Младшее слово=Width, старшее слово=Height return 0; } return DefWindowProc( hWnd, uMsg, wParam, lParam ); // пересылаем все необработанные сообщения }
// Загрузка картинки и конвертирование в текстуру (используется AUXlib) GLvoid LoadGLTextures() { // загрузка картинки Graphics::TBitmap *texture1 = new Graphics::TBitmap; texture1->LoadFromResourceName( (int)appInstance, "TX5" ); //texture1->PixelFormat = pf32bit;
// создание текстуры glGenTextures( 1, &texture[0] ); glBindTexture( GL_TEXTURE_2D, texture[0] );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexImage2D( GL_TEXTURE_2D, 0, 3, texture1->Width, texture1->Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture1->ScanLine[ texture1->Width-1 ] ); }
|
Вот тут загружаются текстуры: Код | // Загрузка картинки и конвертирование в текстуру (используется AUXlib) GLvoid LoadGLTextures() { // загрузка картинки Graphics::TBitmap *texture1 = new Graphics::TBitmap; texture1->LoadFromResourceName( (int)appInstance, "TX5" ); //texture1->PixelFormat = pf32bit;
// создание текстуры glGenTextures( 1, &texture[0] ); glBindTexture( GL_TEXTURE_2D, texture[0] );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexImage2D( GL_TEXTURE_2D, 0, 3, texture1->Width, texture1->Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture1->ScanLine[ texture1->Width-1 ] ); }
|
Загружаю я, как видно, через библиотеку Graphics, иным способом, нежели в статье обучения, вместо GL_RGB использую GL_RGBA, иначе не понятно что вообще с текстурой творится. В оригинале (статье) эта функция описана так: Код | GLvoid LoadGLTextures() { // Загрузка картинки AUX_RGBImageRec *texture1; texture1 = auxDIBImageLoad("Data/NeHe.bmp");
// Создание текстуры glGenTextures(1, &texture[0]); glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, 3, texture1->sizeX, texture1->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, texture1->data); }
|
Функция auxDIBImageLoad() вызывает ошибку, в общем-то не факт, что в ней одной дело. Своим методом я выдёгиваю тот же BITMAP из ресурсов. Картинка загружается, всё хорошо, да вот беда! С цветами что-то не так, как будто один из каналов пропадает или местами меняются, даже не знаю. В общем любая картинка становится синеватого оттенка. Сколько ни бился, чего не перепробовал, а получилось только так. Кто-нибудь может подсказать в чём проблема с этими цветами? И как заставить GL отображать текстуру с правильными цветами, истинными?
|