OpenGL –> WinGDI –> Win32.

Тема в разделе "WASM.OpenGL", создана пользователем Crollspase, 14 сен 2011.

  1. Crollspase

    Crollspase New Member

    Публикаций:
    0
    Регистрация:
    22 июн 2009
    Сообщения:
    75
    Приветствую вас, господа форумчане. Ищу самый быстрый способ реализации следующей цепочки: рисуем в буфере OpenGL –> сэйвим картинку в промежуточное хранилище для добавления в неё текста из GDI –> выводим конечный результат в главное окно. По моему мнению, есть как минимум 3 способа реализации:

    1. Поскольку в OpenGL Red Book написано следующее:
    , то должна работать следующая схема: OpenGL –> DDB –> BitBlt в главное окно;
    2. OpenGL –> glReadPixels –> DIB –> BitBlt в главное окно;
    3. OpenGL –> скрытое окно-посредник –> BitBlt в главное окно.

    Из них троих я смог успешно закодить только второе.

    Код варианта 1 (процедура подготовки, выполняющаяся однократно при старте, и циклическая процедура завершения вывода):
    Код (Text):
    1. PrepareObjectsForOutputThruDDB proc
    2. invoke GetDC,MAIN_WINDOW.handle
    3. mov MAIN_WINDOW_DC_HANDLE,eax
    4.  
    5. invoke CreateCompatibleDC,MAIN_WINDOW_DC_HANDLE
    6. mov FIRST_COMPATIBLE_DC_HANDLE,eax
    7.  
    8. mov PIXEL_FORMAT_PARAMETERS.nSize,sizeof PIXEL_FORMAT_PARAMETERS
    9. mov PIXEL_FORMAT_PARAMETERS.nVersion,1
    10. mov PIXEL_FORMAT_PARAMETERS.dwFlags,PFD_DRAW_TO_BITMAP+PFD_SUPPORT_OPENGL+PFD_DOUBLEBUFFER
    11. mov PIXEL_FORMAT_PARAMETERS.iPixelType,PFD_TYPE_RGBA
    12. mov PIXEL_FORMAT_PARAMETERS.cColorBits,24
    13. mov PIXEL_FORMAT_PARAMETERS.cDepthBits,32
    14. mov PIXEL_FORMAT_PARAMETERS.iLayerType,PFD_MAIN_PLANE
    15.  
    16. invoke ChoosePixelFormat,FIRST_COMPATIBLE_DC_HANDLE,addr PIXEL_FORMAT_PARAMETERS
    17. invoke SetPixelFormat,FIRST_COMPATIBLE_DC_HANDLE,eax,addr PIXEL_FORMAT_PARAMETERS
    18.  
    19. call GetLastError
    20.  
    21. mov DIB_INFO.bmiHeader.biSize,sizeof BITMAPINFOHEADER
    22. MMTEAX DIB_INFO.bmiHeader.biWidth,SCREEN_RESOLUTION_X
    23. mov eax,SCREEN_RESOLUTION_Y
    24. neg eax
    25. mov DIB_INFO.bmiHeader.biHeight,eax
    26. mov DIB_INFO.bmiHeader.biPlanes,1
    27. mov DIB_INFO.bmiHeader.biBitCount,32
    28. mov DIB_INFO.bmiHeader.biCompression,BI_RGB
    29. mov DIB_INFO.bmiHeader.biSizeImage,0
    30. mov DIB_INFO.bmiHeader.biXPelsPerMeter,0
    31. mov DIB_INFO.bmiHeader.biYPelsPerMeter,0
    32. mov DIB_INFO.bmiHeader.biClrUsed,0
    33. mov DIB_INFO.bmiHeader.biClrImportant,0
    34. invoke CreateDIBSection,FIRST_COMPATIBLE_DC_HANDLE,addr DIB_INFO,DIB_RGB_COLORS,addr FIRST_DIB_PIXELS_DATA_MEMORY_OFFSET,0,0
    35. mov FIRST_DIB_HANDLE,eax
    36.  
    37. invoke CreateDIBitmap,FIRST_COMPATIBLE_DC_HANDLE,offset DIB_INFO.bmiHeader,0,0,offset DIB_INFO,DIB_RGB_COLORS
    38. mov FIRST_DDB_HANDLE,eax
    39.  
    40. invoke SelectObject,FIRST_COMPATIBLE_DC_HANDLE,FIRST_DDB_HANDLE
    41.  
    42. invoke wglCreateContext,FIRST_COMPATIBLE_DC_HANDLE
    43. mov OPEN_GL_DC_HANDLE,eax
    44. invoke wglMakeCurrent,FIRST_COMPATIBLE_DC_HANDLE,OPEN_GL_DC_HANDLE
    45.  
    46. call GetLastError
    47.  
    48. ret
    49. PrepareObjectsForOutputThruDDB endp
    50.  
    51.  
    52.  
    53. FinishOutputThruDDB proc
    54. invoke SwapBuffers,FIRST_COMPATIBLE_DC_HANDLE
    55.  
    56.     .if FULL_SCREEN_FLAG==1
    57.     mov eax,SCREEN_RESOLUTION_X
    58.     mov ebx,SCREEN_RESOLUTION_Y
    59.     .else
    60.     mov eax,MAIN_WINDOW.client_area_size.x
    61.     mov ebx,MAIN_WINDOW.client_area_size.y
    62.     .endif
    63.    
    64. invoke BitBlt,MAIN_WINDOW_DC_HANDLE,0,0,eax,ebx,FIRST_COMPATIBLE_DC_HANDLE,0,0,SRCCOPY
    65.  
    66. ret
    67. FinishOutputThruDDB endp
    Здесь wglMakeCurrent возвращает 0, однако самое интересное в том, что вызванная сразу же после неё GetLastError также возвращает 0, свидетельствующий о том, что при выполнении wglMakeCurrent никаких ошибок не возникало. Также хочу добавить, что при снятии флага PFD_DOUBLEBUFFER, SetPixelFormat возвращает 0, хотя и логично, что в данном случае его надо бы снять.

    Код варианта 3:
    Код (Text):
    1. PrepareObjectsForOutputThruHiddenWindow proc
    2. invoke CreateWindowExA,0,addr MAIN_WINDOWDOW_CLASS_NAME,0,WS_POPUP,0,0,SCREEN_RESOLUTION_X,SCREEN_RESOLUTION_Y,0,0,MODULE_HANDLE,0
    3. mov WINDOW_INTERMEDIARY_BETWEEN_MAIN_WINDOW_AND_OPEN_GL_FRAME_BUFFER.handle,eax
    4.  
    5. invoke ShowWindow,WINDOW_INTERMEDIARY_BETWEEN_MAIN_WINDOW_AND_OPEN_GL_FRAME_BUFFER.handle,SW_SHOWNORMAL
    6.  
    7. invoke GetDC,MAIN_WINDOW.handle
    8. mov MAIN_WINDOW_DC_HANDLE,eax
    9. invoke GetDC,WINDOW_INTERMEDIARY_BETWEEN_MAIN_WINDOW_AND_OPEN_GL_FRAME_BUFFER.handle
    10. mov WINDOW_INTERMEDIARY_BETWEEN_MAIN_WINDOW_AND_OPEN_GL_FRAME_BUFFER_DC_HANDLE,eax
    11.  
    12. mov PIXEL_FORMAT_PARAMETERS.nSize,sizeof PIXEL_FORMAT_PARAMETERS
    13. mov PIXEL_FORMAT_PARAMETERS.nVersion,1
    14. mov PIXEL_FORMAT_PARAMETERS.dwFlags,PFD_DRAW_TO_WINDOW+PFD_SUPPORT_OPENGL+PFD_DOUBLEBUFFER
    15. mov PIXEL_FORMAT_PARAMETERS.iPixelType,PFD_TYPE_RGBA
    16. mov PIXEL_FORMAT_PARAMETERS.cColorBits,24
    17. mov PIXEL_FORMAT_PARAMETERS.cDepthBits,32
    18. mov PIXEL_FORMAT_PARAMETERS.iLayerType,PFD_MAIN_PLANE
    19.  
    20. invoke ChoosePixelFormat,MAIN_WINDOW_DC_HANDLE,addr PIXEL_FORMAT_PARAMETERS
    21. invoke SetPixelFormat,MAIN_WINDOW_DC_HANDLE,eax,addr PIXEL_FORMAT_PARAMETERS
    22. invoke ChoosePixelFormat,WINDOW_INTERMEDIARY_BETWEEN_MAIN_WINDOW_AND_OPEN_GL_FRAME_BUFFER_DC_HANDLE,addr PIXEL_FORMAT_PARAMETERS
    23. invoke SetPixelFormat,WINDOW_INTERMEDIARY_BETWEEN_MAIN_WINDOW_AND_OPEN_GL_FRAME_BUFFER_DC_HANDLE,eax,addr PIXEL_FORMAT_PARAMETERS
    24.  
    25. invoke wglCreateContext,WINDOW_INTERMEDIARY_BETWEEN_MAIN_WINDOW_AND_OPEN_GL_FRAME_BUFFER_DC_HANDLE
    26. mov OPEN_GL_DC_HANDLE,eax
    27. invoke wglMakeCurrent,WINDOW_INTERMEDIARY_BETWEEN_MAIN_WINDOW_AND_OPEN_GL_FRAME_BUFFER_DC_HANDLE,OPEN_GL_DC_HANDLE
    28.  
    29. ret
    30. PrepareObjectsForOutputThruHiddenWindow endp
    31.  
    32.  
    33.  
    34. FinishOutputThruHiddenWindow proc
    35. invoke SwapBuffers,WINDOW_INTERMEDIARY_BETWEEN_MAIN_WINDOW_AND_OPEN_GL_FRAME_BUFFER_DC_HANDLE
    36.  
    37.     .if FULL_SCREEN_FLAG==1
    38.     mov eax,SCREEN_RESOLUTION_X
    39.     mov ebx,SCREEN_RESOLUTION_Y
    40.     .else
    41.     mov eax,MAIN_WINDOW.client_area_size.x
    42.     mov ebx,MAIN_WINDOW.client_area_size.y
    43.     .endif
    44.  
    45. push eax
    46. push ebx
    47.  
    48. invoke wglMakeCurrent,0,0
    49.  
    50. pop ebx
    51. pop eax
    52. 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
    53.  
    54. call GetLastError
    55.  
    56. invoke wglMakeCurrent,WINDOW_INTERMEDIARY_BETWEEN_MAIN_WINDOW_AND_OPEN_GL_FRAME_BUFFER_DC_HANDLE,OPEN_GL_DC_HANDLE
    57.  
    58. ret
    59. FinishOutputThruHiddenWindow endp
    В этом случае в окно-посредник всё выводится без проблем, однако BitBlt не работает, хотя и возвращает 1. Хотелось бы ещё уточнить: возможно ли в принципе считать изображение с окна?

    Вобщем, просьба просветить: что именно не так с кодом.

    Для тех из вас, кто знает английский, комментарии к коду, я думаю, не понадобятся (я специально создаю для всех элементов кода длинные и подробные идентификаторы, чтобы не писать комментарии), но если что-то, всё же, непонятно – не стесняйтесь спрашивать.
     
  2. Dmitry_Milk

    Dmitry_Milk Member

    Публикаций:
    0
    Регистрация:
    20 ноя 2007
    Сообщения:
    540
    А что мешает при создании window-class главного окна использовать пикселформат с PFD_SUPPORT_OPENGL (причем PFD_DOUBLEBUFFER даже необязательно, просто без него можно увидеть промежуточные построения), далее создать GL-контекст прямо из главного окна, и прямо в нем и применять GL-функции?
     
  3. Crollspase

    Crollspase New Member

    Публикаций:
    0
    Регистрация:
    22 июн 2009
    Сообщения:
    75
    Dmitry_Milk:
    Эээ… причём тут класс окна? Формат пикселя задаётся для device context'а (DC) окна, а не для его класса.
    После того, как 3D-картинка нарисована, мне нужно добавить поверх неё текст средствами Windows GDI. Если вывести результат работы OpenGL в главное окно и только потом добавить текст (рисуя его непосредственно в это же окно) – текст будет мерцать. Поэтому и требуется такое промежуточное хранилище, использование которого будет наиболее оптимальным с точки зрения быстродействия. В нём GDI сможет добавить к картинке текст, и только потом конечное изображение будет выведено в главное окно. Я знаю, что OpenGL имеет собственные средства для вывода текста (wglUseFontBitmaps, wglUseFontOutlines), однако пользоваться ими я пока ещё не научился. Кроме того, мне хотелось бы правильно закодить и использовать наиболее быстрый способ считывания картинки из буфера OpenGL для других целей, которые, возможно, появятся по мере развития моего проекта.

    Немного исправил код 3-го варианта (отредактировал #1), хотя рабочим он от этого всё равно не стал.
     
  4. T800

    T800 Member

    Публикаций:
    0
    Регистрация:
    7 дек 2006
    Сообщения:
    293
    Адрес:
    Moscow
    Crollspase
    А вы посмотрите как реализован вывод текста (счётчик FPS) в проектах taksi и .kkapture (это аналоги FRAPS).
     
  5. Crollspase

    Crollspase New Member

    Публикаций:
    0
    Регистрация:
    22 июн 2009
    Сообщения:
    75
    T800: ссылка?
     
  6. Crollspase

    Crollspase New Member

    Публикаций:
    0
    Регистрация:
    22 июн 2009
    Сообщения:
    75
    T800, я имею в виду, что мне нужна ссылка на исходники этих проектов.
     
  7. Dmitry_Milk

    Dmitry_Milk Member

    Публикаций:
    0
    Регистрация:
    20 ноя 2007
    Сообщения:
    540
    Пример организации шрифтов и вывода текста в 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() из программного буфера в основное окно.