Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.17.6.75] |
|
Сообщ.
#1
,
|
|
|
Всем доброго времени суток, у меня есть очередной вопрос. У меня не получается разобраться, как работает glut. Он был выбран, потому что приложение на glut32.dll корректно работает на всех моих машинах. Я хотел повторить то же самое, но без glut32.dll. Был написан код:
#include <windows.h> #include <gl/GL.h> #pragma comment(lib, "opengl32.lib") #define CLASSNOTREGISTERED 1 #define WINDOWNOTCREATED 2 #define MESSAGENOTGOT 3 #define OGLCONTEXNOTCREATED 4 #define OGLCONTEXNOTMADECURRENT 5 HWND hWnd; HDC hDc; LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_DESTROY: PostQuitMessage(0); break; case WM_PAINT: glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBegin(GL_TRIANGLES); glColor3f(1.0, 0.0, 0.0); glVertex3f(0.25, 0.25, 0.0); glColor3f(0.0, 1.0, 0.0); glVertex3f(0.75, 0.25, 0.0); glColor3f(0.0, 0.0, 1.0); glVertex3f(0.75, 0.75, 0.0); glEnd(); glFlush(); SwapBuffers(hDc); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } ATOM RegMyWindowClass(HINSTANCE hInst, LPCTSTR lpzClassName) { WNDCLASS wcWindowClass = { 0 }; wcWindowClass.lpfnWndProc = (WNDPROC)WndProc; // адрес ф-ции обработки сообщений wcWindowClass.style = CS_HREDRAW | CS_VREDRAW; // стиль окна wcWindowClass.hInstance = hInst; // дискриптор экземпляра приложения wcWindowClass.lpszClassName = lpzClassName; // название класса wcWindowClass.hCursor = LoadCursor(NULL, IDC_ARROW); // загрузка курсора wcWindowClass.hbrBackground = (HBRUSH)COLOR_APPWORKSPACE;// загрузка цвета окон return RegisterClass(&wcWindowClass); // регистрация класса }; int WinInit(HINSTANCE hInstance) { LPCTSTR lpzClass = TEXT("My Window Class!"); if (!RegMyWindowClass(hInstance, lpzClass)) { return CLASSNOTREGISTERED; }; hWnd = CreateWindow(lpzClass, TEXT("Dialog Window"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 800, 600, NULL, NULL, hInstance, NULL); if (!hWnd) { return WINDOWNOTCREATED; }; return 0; } int WinLoop() { MSG msg = { 0 }; int iGetOk = 0; while ((iGetOk = GetMessage(&msg, NULL, 0, 0)) != 0) { if (iGetOk == -1) return MESSAGENOTGOT; TranslateMessage(&msg); DispatchMessage(&msg); }; return msg.wParam; }; int WinOGLInit() { PIXELFORMATDESCRIPTOR pfd; ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR)); //Версия с сайта 1: /*pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_TYPE_RGBA; pfd.iPixelType = 24; pfd.cDepthBits = 32; pfd.iLayerType = PFD_MAIN_PLANE;*/ //Версия с сатйта 2 pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 24; hDc = GetDC(hWnd); int nPixelFormat = ChoosePixelFormat(hDc, &pfd); SetPixelFormat(hDc, nPixelFormat, &pfd); HGLRC hglrc = wglCreateContext(hDc); if (!hglrc) { return GetLastError(); }; if (!wglMakeCurrent(hDc, hglrc)) { return OGLCONTEXNOTMADECURRENT; }; return 0; }; int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { int initresult = WinInit(hInstance); if (initresult != 0) { return initresult; }; initresult = WinOGLInit(); if (initresult != 0) { return initresult; }; return WinLoop(); } Результат оставляет желать лучшего (обе версии). Во время перерисовок на одной машине (NVidia) окно мограет белым и скорость перерисовок очень низкая, на другой машине (Intel HD) вообще не рисует. Я решил узнать секрет glut. Попробовал прикрутить к проекту glut - но он намертво завязан на glut.dll. Исходный код всех функций вроде как есть, но всё равно требует glut32.lib и glut32.dll. Попробовал пособирать кусочки кода в один файл, чтоб точно скомпилировалось, но через один вечер работы запарился и понял, что что-то я не то делаю. Из ситуации вижу три выхода: 1) Как-то настроить проект так, чтобы он подключал glut/freeglut и компилировал их, при этом не требовал .lib/.dll. И отлаживать программу. 2) Найти или сделать самому файл, который работает так, как описано в пункте 1. Это у меня не получилось, хотя может нужно больше времени. 3) Отладчиком (таким, который показывает ассемблерные коды, не знаю, как это называется) смотреть, какие функции opengl32.dll и winapi вызываются из glut32.dll. Если честно, не хочется это делать. Просто забросить и использовать glut32.dll не очень хочется. Заранее спасибо. |
Сообщ.
#2
,
|
|
|
Я так понимаю, freeglut - хорошая альтернатива glut. В чем тогда проблема? Качаешь исходник freeglut, собираешь либы и подключаешь к своему проекту. В поставке freeglut вроде есть инструкции для всего этого, не?
|
Сообщ.
#3
,
|
|
|
k.sovailo, а вот это - что такое ?
case WM_PAINT: glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBegin(GL_TRIANGLES); glColor3f(1.0, 0.0, 0.0); glVertex3f(0.25, 0.25, 0.0); glColor3f(0.0, 1.0, 0.0); glVertex3f(0.75, 0.25, 0.0); glColor3f(0.0, 0.0, 1.0); glVertex3f(0.75, 0.75, 0.0); glEnd(); glFlush(); SwapBuffers(hDc); break; |
Сообщ.
#4
,
|
|
|
Цитата ЫукпШ @ Это рисование самого простого треугольника в ответ на сообщение о необходимости перерисовки окна. Очистка буфера, рисование и замена буфера. Наверное, я не понял вопрос. Добавлено JoeUser, хотел уже сказать, что проделывал эти шаги, но проверил ещё раз. Всё точно так же, как и в glut, только freeglut собирается только на х64. В результате я подключаю в проект .lib и .h и получаю "бла-бла-бла нет freeglutd.dll". Если её положить возле экзешника - никаких проблем, но это не то, чего я хочу. На всякий случай: #include <glut.h> void renderScene(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBegin(GL_TRIANGLES); glVertex3f(-0.5, -0.5, 0.0); glVertex3f(0.0, 0.5, 0.0); glVertex3f(0.5, -0.5, 0.0); glEnd(); glutSwapBuffers(); } int main(int argc, char **argv) { // инициализация glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); glutInitWindowPosition(100, 100); glutInitWindowSize(400, 400); glutCreateWindow("Урок 1"); // регистрация обратных вызовов glutDisplayFunc(renderScene); // Основной цикл GLUT glutMainLoop(); return 0; } В то же время в README.Win32 написано: ...If you are using the DLL version of "freeglut"... То есть можно как-то использовать не-ДЛЛ-версию? Не могу понять, как. Добавлено ЫукпШ, может Вы про то, что каждый раз вызывается glClearColor? Есть косяк. Убрал - всё точно так же. |
Сообщ.
#5
,
|
|
|
Цитата k.sovailo @ В то же время в README.Win32 написано: ...If you are using the DLL version of "freeglut"... То есть можно как-то использовать не-ДЛЛ-версию? Не могу понять, как. Там есть упоминание о "freeglut_static.lib" - следовательно статик-версия собираться должна... 1) Читай внимательно README.cmake 2) В одном из проектов есть сборочный файл под все версии, просто посмотри что и как там делают: # This file is part of MXE. See LICENSE.md for licensing information. PKG := freeglut $(PKG)_WEBSITE := https://freeglut.sourceforge.io/ $(PKG)_IGNORE := $(PKG)_VERSION := 3.0.0 $(PKG)_CHECKSUM := 2a43be8515b01ea82bcfa17d29ae0d40bd128342f0930cd1f375f1ff999f76a2 $(PKG)_SUBDIR := freeglut-$($(PKG)_VERSION) $(PKG)_FILE := freeglut-$($(PKG)_VERSION).tar.gz $(PKG)_URL := https://$(SOURCEFORGE_MIRROR)/project/freeglut/freeglut/$($(PKG)_VERSION)/$($(PKG)_FILE) $(PKG)_DEPS := cc define $(PKG)_UPDATE $(WGET) -q -O- 'https://sourceforge.net/projects/freeglut/files/freeglut/' | \ $(SED) -n 's,.*freeglut-\([0-9][^>]*\)\.tar.*,\1,p' | \ head -1 endef define $(PKG)_BUILD cd '$(BUILD_DIR)' && '$(TARGET)-cmake' '$(SOURCE_DIR)' \ -DFREEGLUT_GLES=OFF \ -DFREEGLUT_BUILD_DEMOS=OFF \ -DFREEGLUT_REPLACE_GLUT=ON \ -DFREEGLUT_BUILD_STATIC_LIBS=$(CMAKE_STATIC_BOOL) \ -DFREEGLUT_BUILD_SHARED_LIBS=$(CMAKE_SHARED_BOOL) $(MAKE) -C '$(BUILD_DIR)' -j '$(JOBS)' VERBOSE=1 $(MAKE) -C '$(BUILD_DIR)' -j 1 install VERBOSE=1 '$(TARGET)-gcc' \ -W -Wall -Werror -ansi -pedantic \ '$(TEST_FILE)' -o '$(PREFIX)/$(TARGET)/bin/test-freeglut.exe' \ `'$(TARGET)-pkg-config' glut --cflags --libs` endef |
Сообщ.
#6
,
|
|
|
Цитата k.sovailo @ Цитата ЫукпШ @ Это рисование самого простого треугольника в ответ на сообщение о необходимости перерисовки окна. Очистка буфера, рисование и замена буфера. Вот на это я и хотел обратить внимание. Чтобы с максимальной вероятностью прекратить любые видео-эффекты, надо отделить операцию рисования от операции вывода. А у тебя эти операции объединены вместе. Надо, чтобы из WM_PAINT готовое изображение копировалось в окно. Тогда такая операция будет производиться максимально быстро. ----- Ещё рекомендуется обрабатывать сообщение "WM_ERASEBKGND". |
Сообщ.
#7
,
|
|
|
Цитата JoeUser @ Действительно, есть упоминание. Всего-то и надо было: #define FREEGLUT_STATIC 1 #include <glut.h> Теперь буду надеяться, что разберусь, в чём "магия". Тему пока не закрываю. |
Сообщ.
#8
,
|
|
|
ЫукпШ, я ковырялся-ковырялся, но так и не смог сделать ещё один буфер. wglCreateContext напрочь отказывается создавать контекст, если ей передают hDc чего-то, кроме формы. Пробовал с HBITMAP, пробовал с Gdiplus::Bitmap и Gdiplus::Graphics, не работает. Не могу применить ваш совет.
Уточнил флаги, которые использует freeglut, лучше не стало. Хотя у меня такое чувство, что это какой-то обманный манёвр. Потому что freeglut сначала создаёт контекст и сразу же высвобождает, а потом создаёт его только где-то в дебрях (отслеживал отладчиком), кода которых у меня нет. Так что придётся либо писать 64-битную программу с freeglut, либо 32-битную с glut и таскать библиотеки, либо ковыряться дальше. В каждом варианте свои минусы. #include <windows.h> #include <gl/GL.h> #define _USE_MATH_DEFINES #include <cmath> #pragma comment(lib, "opengl32.lib") #define CLASSNOTREGISTERED 1 #define WINDOWNOTCREATED 2 #define MESSAGENOTGOT 3 #define OGLCONTEXNOTCREATED 4 #define OGLCONTEXNOTMADECURRENT 5 #define PIXELFORMATNOTSET 6 class Application { public: HINSTANCE hInstance; HWND hWnd; HDC windowDC; HGLRC hglrc; LPCTSTR classname; WNDCLASS wndclass; }; Application app; float angle = 1.0; void DrawScreen() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBegin(GL_TRIANGLES); glColor3f(1.0, 0.0, 0.0); glVertex3f(0.5*sin(angle), 0.5*cos(angle), 0.0); glColor3f(0.0, 1.0, 0.0); glVertex3f(0.5*sin(angle + 2 * M_PI / 3), 0.5*cos(angle + 2 * M_PI / 3), 0.0); glColor3f(0.0, 0.0, 1.0); glVertex3f(0.5*sin(angle + 4 * M_PI / 3), 0.5*cos(angle + 4 * M_PI / 3), 0.0); glEnd(); glFlush(); SwapBuffers(app.windowDC); }; LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_DESTROY: PostQuitMessage(0); break; case WM_PAINT: DrawScreen(); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } int WinLoop() { MSG msg = { 0 }; int iGetOk = 0; while ((iGetOk = GetMessage(&msg, NULL, 0, 0)) != 0) { if (iGetOk == -1) return MESSAGENOTGOT; TranslateMessage(&msg); DispatchMessage(&msg); }; return msg.wParam; }; ATOM RegMyWindowClass() { ZeroMemory(&(app.wndclass), sizeof(WNDCLASS)); app.wndclass.lpfnWndProc = (WNDPROC)WndProc; // адрес ф-ции обработки сообщений app.wndclass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;// стиль окна app.wndclass.hInstance = app.hInstance; // дискриптор экземпляра приложения app.wndclass.lpszClassName = app.classname; // название класса app.wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); // загрузка курсора app.wndclass.hbrBackground = (HBRUSH)COLOR_APPWORKSPACE;// загрузка цвета окон return RegisterClass(&app.wndclass); // регистрация класса }; bool SetWindowFormat() { PIXELFORMATDESCRIPTOR pfd; ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR)); int flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; /* Specify which pixel format do we opt for... */ pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); pfd.nVersion = 1; pfd.dwFlags = flags; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cRedBits = 8; pfd.cGreenBits = 8; pfd.cBlueBits = 8; pfd.cAlphaBits = 0;//(fgState.DisplayMode & GLUT_ALPHA) ? 8 : 0 pfd.cColorBits = 24; pfd.cRedShift = 0; pfd.cGreenShift = 0; pfd.cBlueShift = 0; pfd.cAlphaShift = 0; pfd.cAccumBits = 0;//(fgState.DisplayMode & GLUT_ACCUM) ? 1 : 0 pfd.cAccumRedBits = 0; pfd.cAccumGreenBits = 0; pfd.cAccumBlueBits = 0; pfd.cAccumAlphaBits = 0; /* Hmmm, or 32/0 instead of 24/8? */ pfd.cDepthBits = 24; pfd.cStencilBits = 8; pfd.cAuxBuffers = 0;//(BYTE)fghNumberOfAuxBuffersRequested() pfd.iLayerType = 0;//layer_type pfd.bReserved = 0; pfd.dwLayerMask = 0; pfd.dwVisibleMask = 0; pfd.dwDamageMask = 0; pfd.cColorBits = (BYTE)GetDeviceCaps(app.windowDC, BITSPIXEL); int nPixelFormat = ChoosePixelFormat(app.windowDC, &pfd); if (nPixelFormat == 0) return false; SetPixelFormat(app.windowDC, nPixelFormat, &pfd); return true; }; int WinInit() { app.classname = TEXT("My Window Class!"); if (!RegMyWindowClass()) return CLASSNOTREGISTERED; if ((app.hWnd = CreateWindow(app.classname, TEXT("Dialog Window"), WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 800, 600, NULL, NULL, app.hInstance, NULL)) == 0) return WINDOWNOTCREATED; app.windowDC = GetDC(app.hWnd); if (!SetWindowFormat()) return PIXELFORMATNOTSET; return 0; } int WinOGLInit() { app.hglrc = wglCreateContext(app.windowDC); if (app.hglrc == 0) return GetLastError(); if (!wglMakeCurrent(app.windowDC, app.hglrc)) return OGLCONTEXNOTMADECURRENT; return 0; }; int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { app.hInstance = hInstance; int initresult; initresult = WinInit(); if (initresult != 0) return initresult; initresult = WinOGLInit(); if (initresult != 0) return initresult; return WinLoop(); } |
Сообщ.
#9
,
|
|
|
Цитата k.sovailo @ ЫукпШ, я ковырялся-ковырялся, но так и не смог сделать ещё один буфер. wglCreateContext напрочь отказывается создавать контекст, если ей передают hDc чего-то, кроме формы. Вот, я посмотрел. Ты используешь : class Application { public: HINSTANCE hInstance; HWND hWnd; HDC windowDC; HGLRC hglrc; LPCTSTR classname; WNDCLASS wndclass; }; Если в структуру подставить HDC какого-нибудь memdc ? Созданного на WINAPI. Всё должно работать. А потом в WM_PAINT просто выполним "BitBlt" в соответствии с размерами прямоугольника, передаваемого в Paint - структуре. |
Сообщ.
#10
,
|
|
|
ЫукпШ
app.windowDC = GetDC(app.hWnd); SetOGLPixelFormat(app.windowDC));//pfd и всё остальное - в этой функции app.bufferDC = CreateCompatibleDC(app.windowDC); app.hBuffer = CreateCompatibleBitmap(app.bufferDC, 800, 600); SetOGLPixelFormat(app.bufferDC); SelectObject(app.bufferDC, app.hBuffer);//советовали на одном форуме wglMakeCurrent(app.bufferDC, NULL);//советовали на другом форуме app.hglrc = wglCreateContext(app.bufferDC);//возвращает 0 Не работает. Если создавать битмап в контексте окна, тоже не работает. Я правильно понял? |
Сообщ.
#11
,
|
|
|
Я тут провёл ещё несколько попыток и понял, что лучше доверить эту работу freeglut. Закончилось на том, что я подкорректировал код, добавил getHWND() и написал функцию динамического подключения freeglut.dll. Спасибо за внимание.
|
Сообщ.
#12
,
|
|
|
Цитата k.sovailo @ Не работает. Если создавать битмап в контексте окна, тоже не работает. Я правильно понял? Трудно мне без отладки по тексту сказать точно, где ошибка. я делал так: //.. HDC d_c = ::CreateDC(_T("DISPLAY"),NULL,NULL,NULL); HDC memdc = ::CreateCompatibleDC (d_c); RECT rc; ::GetWindowRect (::GetDesktopWindow(), &rc); // размер скрина: int sizex = (rc.right - rc.left) ; int sizey = (rc.bottom - rc.top) ; HBITMAP hbit = ::CreateCompatibleBitmap (d_c, sizex, sizey); ::SelectObject (memdc, hbit); HBRUSH brush = ::CreateSolidBrush (someColor); ::SelectObject (memdc, brush); ::PatBlt(memdc,0,0,sizex,sizey,PATCOPY); // закрасить memdc кистью brush цвета someColor ::DeleteDC(d_c); //... // в результате получили memdc размером с экран. // зачищенный цветом "someColor". // функциями GDI там можно рисовать что угодно. Можно читать/писать посредством "BitBlt" любыми кусками. Понятно, что лучше все эти объекты обернуть классами, поскольку попытка следить за ними "вручную" скорее всего закончится утечкой ресурсов. Исходник в таком виде я представил для примера. ----- Хочу заметить, что всё это имеет конкретное практическое применение. Например, что делать, если рисование картинки занимает 1 секунду (или больше)? Если сделать это из оконной процедуры, тогда на это время всё управление приложением будет парализовано, в том числе перерисовка экрана. При этом сам вывод картинки на экран (даже самый большой) может составить 1 [мс] или меньше. Рисовать имиджи можно и в другом потоке. Поэтому разделение этих 2-х операций весьма перспективное мероприятие. |