Приветствую вас, господа форумчане. Ищу самый быстрый способ реализации следующей цепочки: рисуем в буфере OpenGL –> сэйвим картинку в промежуточное хранилище для добавления в неё текста из GDI –> выводим конечный результат в главное окно. По моему мнению, есть как минимум 3 способа реализации: 1. Поскольку в OpenGL Red Book написано следующее: , то должна работать следующая схема: OpenGL –> DDB –> BitBlt в главное окно; 2. OpenGL –> glReadPixels –> DIB –> BitBlt в главное окно; 3. OpenGL –> скрытое окно-посредник –> BitBlt в главное окно. Из них троих я смог успешно закодить только второе. Код варианта 1 (процедура подготовки, выполняющаяся однократно при старте, и циклическая процедура завершения вывода): Код (Text): PrepareObjectsForOutputThruDDB proc invoke GetDC,MAIN_WINDOW.handle mov MAIN_WINDOW_DC_HANDLE,eax invoke CreateCompatibleDC,MAIN_WINDOW_DC_HANDLE mov FIRST_COMPATIBLE_DC_HANDLE,eax mov PIXEL_FORMAT_PARAMETERS.nSize,sizeof PIXEL_FORMAT_PARAMETERS mov PIXEL_FORMAT_PARAMETERS.nVersion,1 mov PIXEL_FORMAT_PARAMETERS.dwFlags,PFD_DRAW_TO_BITMAP+PFD_SUPPORT_OPENGL+PFD_DOUBLEBUFFER mov PIXEL_FORMAT_PARAMETERS.iPixelType,PFD_TYPE_RGBA mov PIXEL_FORMAT_PARAMETERS.cColorBits,24 mov PIXEL_FORMAT_PARAMETERS.cDepthBits,32 mov PIXEL_FORMAT_PARAMETERS.iLayerType,PFD_MAIN_PLANE invoke ChoosePixelFormat,FIRST_COMPATIBLE_DC_HANDLE,addr PIXEL_FORMAT_PARAMETERS invoke SetPixelFormat,FIRST_COMPATIBLE_DC_HANDLE,eax,addr PIXEL_FORMAT_PARAMETERS call GetLastError mov DIB_INFO.bmiHeader.biSize,sizeof BITMAPINFOHEADER MMTEAX DIB_INFO.bmiHeader.biWidth,SCREEN_RESOLUTION_X mov eax,SCREEN_RESOLUTION_Y neg eax mov DIB_INFO.bmiHeader.biHeight,eax mov DIB_INFO.bmiHeader.biPlanes,1 mov DIB_INFO.bmiHeader.biBitCount,32 mov DIB_INFO.bmiHeader.biCompression,BI_RGB mov DIB_INFO.bmiHeader.biSizeImage,0 mov DIB_INFO.bmiHeader.biXPelsPerMeter,0 mov DIB_INFO.bmiHeader.biYPelsPerMeter,0 mov DIB_INFO.bmiHeader.biClrUsed,0 mov DIB_INFO.bmiHeader.biClrImportant,0 invoke CreateDIBSection,FIRST_COMPATIBLE_DC_HANDLE,addr DIB_INFO,DIB_RGB_COLORS,addr FIRST_DIB_PIXELS_DATA_MEMORY_OFFSET,0,0 mov FIRST_DIB_HANDLE,eax invoke CreateDIBitmap,FIRST_COMPATIBLE_DC_HANDLE,offset DIB_INFO.bmiHeader,0,0,offset DIB_INFO,DIB_RGB_COLORS mov FIRST_DDB_HANDLE,eax invoke SelectObject,FIRST_COMPATIBLE_DC_HANDLE,FIRST_DDB_HANDLE invoke wglCreateContext,FIRST_COMPATIBLE_DC_HANDLE mov OPEN_GL_DC_HANDLE,eax invoke wglMakeCurrent,FIRST_COMPATIBLE_DC_HANDLE,OPEN_GL_DC_HANDLE call GetLastError ret PrepareObjectsForOutputThruDDB endp FinishOutputThruDDB proc invoke SwapBuffers,FIRST_COMPATIBLE_DC_HANDLE .if FULL_SCREEN_FLAG==1 mov eax,SCREEN_RESOLUTION_X mov ebx,SCREEN_RESOLUTION_Y .else mov eax,MAIN_WINDOW.client_area_size.x mov ebx,MAIN_WINDOW.client_area_size.y .endif invoke BitBlt,MAIN_WINDOW_DC_HANDLE,0,0,eax,ebx,FIRST_COMPATIBLE_DC_HANDLE,0,0,SRCCOPY ret FinishOutputThruDDB endp Здесь wglMakeCurrent возвращает 0, однако самое интересное в том, что вызванная сразу же после неё GetLastError также возвращает 0, свидетельствующий о том, что при выполнении wglMakeCurrent никаких ошибок не возникало. Также хочу добавить, что при снятии флага PFD_DOUBLEBUFFER, SetPixelFormat возвращает 0, хотя и логично, что в данном случае его надо бы снять. Код варианта 3: Код (Text): PrepareObjectsForOutputThruHiddenWindow proc invoke CreateWindowExA,0,addr MAIN_WINDOWDOW_CLASS_NAME,0,WS_POPUP,0,0,SCREEN_RESOLUTION_X,SCREEN_RESOLUTION_Y,0,0,MODULE_HANDLE,0 mov WINDOW_INTERMEDIARY_BETWEEN_MAIN_WINDOW_AND_OPEN_GL_FRAME_BUFFER.handle,eax invoke ShowWindow,WINDOW_INTERMEDIARY_BETWEEN_MAIN_WINDOW_AND_OPEN_GL_FRAME_BUFFER.handle,SW_SHOWNORMAL invoke GetDC,MAIN_WINDOW.handle mov MAIN_WINDOW_DC_HANDLE,eax invoke GetDC,WINDOW_INTERMEDIARY_BETWEEN_MAIN_WINDOW_AND_OPEN_GL_FRAME_BUFFER.handle mov WINDOW_INTERMEDIARY_BETWEEN_MAIN_WINDOW_AND_OPEN_GL_FRAME_BUFFER_DC_HANDLE,eax mov PIXEL_FORMAT_PARAMETERS.nSize,sizeof PIXEL_FORMAT_PARAMETERS mov PIXEL_FORMAT_PARAMETERS.nVersion,1 mov PIXEL_FORMAT_PARAMETERS.dwFlags,PFD_DRAW_TO_WINDOW+PFD_SUPPORT_OPENGL+PFD_DOUBLEBUFFER mov PIXEL_FORMAT_PARAMETERS.iPixelType,PFD_TYPE_RGBA mov PIXEL_FORMAT_PARAMETERS.cColorBits,24 mov PIXEL_FORMAT_PARAMETERS.cDepthBits,32 mov PIXEL_FORMAT_PARAMETERS.iLayerType,PFD_MAIN_PLANE invoke ChoosePixelFormat,MAIN_WINDOW_DC_HANDLE,addr PIXEL_FORMAT_PARAMETERS invoke SetPixelFormat,MAIN_WINDOW_DC_HANDLE,eax,addr PIXEL_FORMAT_PARAMETERS invoke ChoosePixelFormat,WINDOW_INTERMEDIARY_BETWEEN_MAIN_WINDOW_AND_OPEN_GL_FRAME_BUFFER_DC_HANDLE,addr PIXEL_FORMAT_PARAMETERS invoke SetPixelFormat,WINDOW_INTERMEDIARY_BETWEEN_MAIN_WINDOW_AND_OPEN_GL_FRAME_BUFFER_DC_HANDLE,eax,addr PIXEL_FORMAT_PARAMETERS invoke wglCreateContext,WINDOW_INTERMEDIARY_BETWEEN_MAIN_WINDOW_AND_OPEN_GL_FRAME_BUFFER_DC_HANDLE mov OPEN_GL_DC_HANDLE,eax invoke wglMakeCurrent,WINDOW_INTERMEDIARY_BETWEEN_MAIN_WINDOW_AND_OPEN_GL_FRAME_BUFFER_DC_HANDLE,OPEN_GL_DC_HANDLE ret PrepareObjectsForOutputThruHiddenWindow endp FinishOutputThruHiddenWindow proc invoke SwapBuffers,WINDOW_INTERMEDIARY_BETWEEN_MAIN_WINDOW_AND_OPEN_GL_FRAME_BUFFER_DC_HANDLE .if FULL_SCREEN_FLAG==1 mov eax,SCREEN_RESOLUTION_X mov ebx,SCREEN_RESOLUTION_Y .else mov eax,MAIN_WINDOW.client_area_size.x mov ebx,MAIN_WINDOW.client_area_size.y .endif push eax push ebx invoke wglMakeCurrent,0,0 pop ebx pop eax invoke BitBlt,MAIN_WINDOW_DC_HANDLE,0,0,eax,ebx,WINDOW_INTERMEDIARY_BETWEEN_MAIN_WINDOW_AND_OPEN_GL_FRAME_BUFFER_DC_HANDLE,0,0,SRCCOPY call GetLastError invoke wglMakeCurrent,WINDOW_INTERMEDIARY_BETWEEN_MAIN_WINDOW_AND_OPEN_GL_FRAME_BUFFER_DC_HANDLE,OPEN_GL_DC_HANDLE ret FinishOutputThruHiddenWindow endp В этом случае в окно-посредник всё выводится без проблем, однако BitBlt не работает, хотя и возвращает 1. Хотелось бы ещё уточнить: возможно ли в принципе считать изображение с окна? Вобщем, просьба просветить: что именно не так с кодом. Для тех из вас, кто знает английский, комментарии к коду, я думаю, не понадобятся (я специально создаю для всех элементов кода длинные и подробные идентификаторы, чтобы не писать комментарии), но если что-то, всё же, непонятно – не стесняйтесь спрашивать.
А что мешает при создании window-class главного окна использовать пикселформат с PFD_SUPPORT_OPENGL (причем PFD_DOUBLEBUFFER даже необязательно, просто без него можно увидеть промежуточные построения), далее создать GL-контекст прямо из главного окна, и прямо в нем и применять GL-функции?
Dmitry_Milk: Эээ… причём тут класс окна? Формат пикселя задаётся для device context'а (DC) окна, а не для его класса. После того, как 3D-картинка нарисована, мне нужно добавить поверх неё текст средствами Windows GDI. Если вывести результат работы OpenGL в главное окно и только потом добавить текст (рисуя его непосредственно в это же окно) – текст будет мерцать. Поэтому и требуется такое промежуточное хранилище, использование которого будет наиболее оптимальным с точки зрения быстродействия. В нём GDI сможет добавить к картинке текст, и только потом конечное изображение будет выведено в главное окно. Я знаю, что OpenGL имеет собственные средства для вывода текста (wglUseFontBitmaps, wglUseFontOutlines), однако пользоваться ими я пока ещё не научился. Кроме того, мне хотелось бы правильно закодить и использовать наиболее быстрый способ считывания картинки из буфера OpenGL для других целей, которые, возможно, появятся по мере развития моего проекта. Немного исправил код 3-го варианта (отредактировал #1), хотя рабочим он от этого всё равно не стал.
Crollspase А вы посмотрите как реализован вывод текста (счётчик FPS) в проектах taksi и .kkapture (это аналоги FRAPS).
Пример организации шрифтов и вывода текста в OpenGL есть в редбуке http://fly.cc.fer.hr/~unreal/theredbook/chapter08.html, параграф "Defining and Using a Complete Font", прямо стандартными средствами gl, даже не glu и не glut. А если все же хочется средства GDI, то вижу еще такой вариант - главное окно и вспомогательное окно оба сделать с поддержкой GL, без двойной буферизации, для обоих создавать как виндовый контекст, так и GL-контекст. Сначала рисовать и GL-объекты, и ГДИ-шные вещи в вспомогательном окне (никто ведь не запрещает использовать оба контекста, причем из-за отсутствия вторичного буфера оба контекста будут рисовать в вспомогательном окне в основном буфере). После полной отрисовки копировать содержимое через glReadPixels() из вспомогательного в программный буфер, и glDrawPixels() из программного буфера в основное окно.